Commit ecb0badb0d3b7ba6b4175c174d63d78e118597e0

Authored by ming
1 parent 92989af0

保存jpg图片

.vscode/launch.json
... ... @@ -6,7 +6,7 @@
6 6 "type": "cppdbg",
7 7 "request": "launch",
8 8 "program": "${workspaceFolder}/bin/lib/test",
9   - "args": ["rtsp","3", "30012"],
  9 + "args": ["rtsp://192.168.10.4:8554/street","3", "30012"],
10 10 "stopAtEntry": false,
11 11 "cwd": "${workspaceFolder}/bin/lib",
12 12 "environment": [],
... ... @@ -55,6 +55,42 @@
55 55 "ignoreFailures": true
56 56 }
57 57 ]
  58 + },{
  59 + "name": "save_tool",
  60 + "type": "cppdbg",
  61 + "request": "launch",
  62 + "program": "${workspaceFolder}/bin/lib/save_tool",
  63 + "args": ["rtsp://admin:ad123456@192.168.60.165:554/cam/realmonitor?channel=1&subtype=0"],
  64 + "stopAtEntry": false,
  65 + "cwd": "${workspaceFolder}/bin/lib",
  66 + "environment": [],
  67 + "externalConsole": false,
  68 + "MIMode": "gdb",
  69 + "setupCommands": [
  70 + {
  71 + "description": "Enable pretty-printing for gdb",
  72 + "text": "-enable-pretty-printing",
  73 + "ignoreFailures": true
  74 + }
  75 + ]
  76 + },{
  77 + "name": "gb28181",
  78 + "type": "cppdbg",
  79 + "request": "launch",
  80 + "program": "${workspaceFolder}/bin/lib/test",
  81 + "args": ["rtsp://192.168.10.4:8554/street","3", "30026","sipId"],
  82 + "stopAtEntry": false,
  83 + "cwd": "${workspaceFolder}/bin/lib",
  84 + "environment": [],
  85 + "externalConsole": false,
  86 + "MIMode": "gdb",
  87 + "setupCommands": [
  88 + {
  89 + "description": "Enable pretty-printing for gdb",
  90 + "text": "-enable-pretty-printing",
  91 + "ignoreFailures": true
  92 + }
  93 + ]
58 94 }
59 95 ]
60 96 }
61 97 \ No newline at end of file
... ...
src/Makefile renamed to build/Makefile
... ... @@ -16,6 +16,7 @@ TARGET= $(DEPEND_DIR)/lib/test
16 16  
17 17 SPDLOG_ROOT = $(THIRDPARTY_ROOT)/spdlog-1.9.2/release
18 18 JRTP_ROOT = $(THIRDPARTY_ROOT)/jrtp_export
  19 +CURL_ROOT = $(THIRDPARTY_ROOT)/curl/bin
19 20  
20 21  
21 22 INCLUDE= -I $(DEPEND_DIR)/include \
... ... @@ -26,13 +27,15 @@ INCLUDE= -I $(DEPEND_DIR)/include \
26 27 -I $(SPDLOG_ROOT)/include \
27 28 -I $(SRC_ROOT)/gb28181 \
28 29 -I $(JRTP_ROOT)/jrtplib/include/jrtplib3 \
29   - -I $(JRTP_ROOT)/jthread/include/jthread
  30 + -I $(JRTP_ROOT)/jthread/include/jthread \
  31 + -I $(CURL_ROOT)/include \
30 32  
31 33 LIBSPATH= -L $(DEPEND_DIR)/lib -lavformat -lavcodec -lswscale -lavutil -lavfilter -lswresample -lavdevice \
32 34 -L $(CUDA_ROOT)/lib64 -lcuda -lcudart -lnvcuvid -lcurand -lcublas -lnvjpeg \
33 35 -L $(SPDLOG_ROOT) -l:libspdlog.a \
34 36 -L $(JRTP_ROOT)/jthread/lib -l:libjthread.a \
35   - -L $(JRTP_ROOT)/jrtplib/lib -l:libjrtp.a
  37 + -L $(JRTP_ROOT)/jrtplib/lib -l:libjrtp.a \
  38 + -L $(CURL_ROOT)/lib -l:libcurl.a \
36 39  
37 40 CFLAGS= -g -fPIC -O0 $(INCLUDE) -pthread -lrt -lz -std=c++11 -fvisibility=hidden -Wl,-Bsymbolic -ldl
38 41 # -DUNICODE -D_UNICODE
... ...
nv-codec-headers/Makefile
1   -PREFIX = /usr/local
  1 +PREFIX = /mnt/data/cmhu/nv_headers
2 2 LIBDIR = lib
3 3 INSTALL = install
4 4 SED = sed
... ...
save_tool/Makefile 0 → 100644
  1 +
  2 +XX = g++
  3 +NVCC = nvcc
  4 +
  5 +PROJECT_ROOT= /mnt/data/cmhu/FFNvDecoder
  6 +
  7 +DEPEND_DIR = $(PROJECT_ROOT)/bin
  8 +SRC_ROOT = $(PROJECT_ROOT)/save_tool
  9 +CUDA_ROOT = /usr/local/cuda
  10 +
  11 +TARGET= $(DEPEND_DIR)/lib/save_tool
  12 +
  13 +
  14 +INCLUDE= -I $(DEPEND_DIR)/include \
  15 + -I $(CUDA_ROOT)/include \
  16 + -I $(SRC_ROOT)\
  17 +
  18 +LIBSPATH= -L $(DEPEND_DIR)/lib -lavformat -lavcodec -lswscale -lavutil -lavfilter -lswresample -lavdevice \
  19 + -L $(CUDA_ROOT)/lib64 -lcudart -lcurand -lcublas -lnvjpeg \
  20 + -L /usr/lib/wsl/lib -lcuda -lnvcuvid\
  21 +
  22 +CFLAGS= -g -fPIC -O0 $(INCLUDE) -pthread -lrt -lz -std=c++11 -fvisibility=hidden -Wl,-Bsymbolic -ldl
  23 + # -DUNICODE -D_UNICODE
  24 +
  25 +NFLAGS_LIB=-g -c -shared -Xcompiler -fPIC -Xcompiler -fvisibility=hidden
  26 +NFLAGS = $(NFLAGS_LIB) $(INCLUDE) -std=c++11
  27 +
  28 +SRCS:=$(wildcard $(SRC_ROOT)/*.cpp)
  29 +OBJS = $(patsubst %.cpp, %.o, $(notdir $(SRCS)))
  30 +
  31 +CU_SOURCES = $(wildcard ${SRC_ROOT}/*.cu)
  32 +CU_OBJS = $(patsubst %.cu, %.o, $(notdir $(CU_SOURCES)))
  33 +
  34 +
  35 +$(TARGET):$(OBJS) $(CU_OBJS)
  36 + rm -f $(TARGET)
  37 + $(XX) -o $@ $^ $(CFLAGS) $(LIBSPATH) $(LIBS) -Wwrite-strings
  38 + rm -f *.o
  39 +
  40 +%.o:$(SRC_ROOT)/%.cpp
  41 + $(XX) $(CFLAGS) -c $<
  42 +
  43 +%.o:$(SRC_ROOT)/%.cu
  44 + @echo "#######################CU_OBJS:$@###############"
  45 + $(NVCC) $(NFLAGS) -o $@ $<
  46 +
  47 +clean:
  48 + rm -f *.o $(TARGET)
  49 +
  50 +
... ...
save_tool/check_tool.cpp1 0 → 100644
  1 +#include"check_tool.h"
  2 +
  3 +extern "C"
  4 +{
  5 + #include <libavcodec/avcodec.h>
  6 + #include <libavdevice/avdevice.h>
  7 + #include <libavformat/avformat.h>
  8 + #include <libavfilter/avfilter.h>
  9 + #include <libavutil/avutil.h>
  10 + #include <libavutil/pixdesc.h>
  11 + #include <libswscale/swscale.h>
  12 + #include <libavutil/imgutils.h>
  13 +}
  14 +
  15 +#include <chrono>
  16 +
  17 +
  18 +static long long get_cur_time(){
  19 + // 获取操作系统当前时间点(精确到微秒)
  20 + chrono::time_point<chrono::system_clock, chrono::milliseconds> tpMicro
  21 + = chrono::time_point_cast<chrono::milliseconds>(chrono::system_clock::now());
  22 + // (微秒精度的)时间点 => (微秒精度的)时间戳
  23 + time_t currentTime = tpMicro.time_since_epoch().count();
  24 +
  25 + return (long long )currentTime;
  26 +}
  27 +
  28 +void save_pkt(const string& uri){
  29 + AVFormatContext* ifmt_ctx = nullptr;
  30 + AVCodecContext* codec_ctx = nullptr;
  31 + AVCodec *decoder = nullptr;
  32 + AVCodec* codec = nullptr;
  33 + AVPacket* pkt = nullptr;
  34 + int video_index = -1;
  35 + AVStream* i_video_stream = nullptr;
  36 + SwsContext *img_convert_ctx = nullptr;
  37 + uint8_t *buffer = nullptr;
  38 + int numBytes = 0;
  39 +
  40 + long start_time = 0;
  41 + long end_time = 0;
  42 + long s_time = 0;
  43 + long e_time = 0;
  44 + long long sum = 0;
  45 + double avg_time = 0.0;
  46 +
  47 + int sep = 0;
  48 +
  49 + AVFormatContext *o_fmt_ctx;
  50 + AVStream *o_video_stream;
  51 +
  52 + const char *filename = "test.mp4";
  53 +
  54 +
  55 + avformat_network_init();
  56 +
  57 + // 打开输入视频文件
  58 + AVDictionary *options = nullptr;
  59 + av_dict_set( &options, "bufsize", "655360", 0 );
  60 + av_dict_set( &options, "rtsp_transport", "tcp", 0 );
  61 + // av_dict_set( &options, "listen_timeout", "30", 0 ); // 单位为s
  62 + av_dict_set( &options, "stimeout", "30000000", 0 ); // 单位为 百万分之一秒
  63 +
  64 + ///打开输入的流
  65 + ifmt_ctx = avformat_alloc_context();
  66 + int ret = avformat_open_input(&ifmt_ctx, uri.c_str(), nullptr, &options);
  67 + if (ret != 0){
  68 + av_log(nullptr, AV_LOG_ERROR, "Couldn't open input stream ! \n");
  69 + goto end_flag ;
  70 + }
  71 +
  72 + //查找流信息
  73 + if (avformat_find_stream_info(ifmt_ctx, nullptr) < 0){
  74 + av_log(nullptr, AV_LOG_ERROR, "Couldn't find stream information ! \n");
  75 + goto end_flag ;
  76 + }
  77 +
  78 + // 查找视频流信息
  79 + video_index = av_find_best_stream(ifmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &decoder, 0);
  80 + if (video_index < 0) {
  81 + av_log(nullptr, AV_LOG_ERROR, "Cannot find a video stream in the input file ! \n");
  82 + goto end_flag ;
  83 + }
  84 +
  85 + //申请AVCodecContext
  86 + codec_ctx = avcodec_alloc_context3(decoder);
  87 + if (!codec_ctx){
  88 + goto end_flag ;
  89 + }
  90 +
  91 + i_video_stream = ifmt_ctx->streams[video_index];
  92 + if(avcodec_parameters_to_context(codec_ctx, i_video_stream->codecpar) < 0){
  93 + goto end_flag ;
  94 + }
  95 +
  96 + {
  97 + av_log(nullptr, AV_LOG_INFO, "path: %s \n", ifmt_ctx->url);
  98 + av_log(nullptr, AV_LOG_INFO, "format: %s \n", ifmt_ctx->iformat->name);
  99 + const char* profile = avcodec_profile_name(codec_ctx->codec_id, codec_ctx->profile);
  100 + av_log(nullptr, AV_LOG_INFO, "codec: %s(%s) \n", decoder->name, profile);
  101 + const char* pix_fmt_name = av_get_pix_fmt_name(codec_ctx->pix_fmt);
  102 + av_log(nullptr, AV_LOG_INFO, "pix_fmt_name: %s \n", pix_fmt_name);
  103 + av_log(nullptr, AV_LOG_INFO, "width x height: %dX%d \n", i_video_stream->codecpar->width, i_video_stream->codecpar->height);
  104 +
  105 + av_log(NULL, AV_LOG_INFO, "frame_rate: %1.0f ", av_q2d(i_video_stream->r_frame_rate));
  106 + av_log(NULL, AV_LOG_INFO, " --> reference PPS: %f ms\n", 1/av_q2d(i_video_stream->r_frame_rate) * 1000);
  107 + }
  108 +
  109 +
  110 + avformat_alloc_output_context2(&o_fmt_ctx, NULL, NULL, filename);
  111 +
  112 + /*
  113 + * since all input files are supposed to be identical (framerate, dimension, color format, ...)
  114 + * we can safely set output codec values from first input file
  115 + */
  116 + o_video_stream = avformat_new_stream(o_fmt_ctx, NULL);
  117 + {
  118 + AVCodecContext *c;
  119 + c = o_video_stream->codec;
  120 + c->bit_rate = 400000;
  121 + c->codec_id = i_video_stream->codec->codec_id;
  122 + c->codec_type = i_video_stream->codec->codec_type;
  123 + c->time_base.num = i_video_stream->time_base.num;
  124 + c->time_base.den = i_video_stream->time_base.den;
  125 + fprintf(stderr, " = time_base.num = %d time_base.den = %d\n", c->time_base.num, c->time_base.den);
  126 + c->width = i_video_stream->codec->width;
  127 + c->height = i_video_stream->codec->height;
  128 + c->pix_fmt = i_video_stream->codec->pix_fmt;
  129 + printf(" = width: %d height: %d pix_fmt: %d\n", c->width, c->height, c->pix_fmt);
  130 + c->flags = i_video_stream->codec->flags;
  131 + c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
  132 + c->me_range = i_video_stream->codec->me_range;
  133 + c->max_qdiff = i_video_stream->codec->max_qdiff;
  134 +
  135 + c->qmin = i_video_stream->codec->qmin;
  136 + c->qmax = i_video_stream->codec->qmax;
  137 +
  138 + c->qcompress = i_video_stream->codec->qcompress;
  139 + }
  140 +
  141 + avio_open(&o_fmt_ctx->pb, filename, AVIO_FLAG_WRITE);
  142 +
  143 + avformat_write_header(o_fmt_ctx, NULL);
  144 +
  145 +
  146 + s_time = get_cur_time();
  147 + start_time = get_cur_time();
  148 + pkt = av_packet_alloc();
  149 + while (av_read_frame(ifmt_ctx, pkt) >= 0){
  150 + end_time = get_cur_time();
  151 + sum ++ ;
  152 + sep ++ ;
  153 + if(end_time - start_time > 1000){
  154 + avg_time = double(end_time - start_time) / sep;
  155 + start_time = get_cur_time();
  156 + sep = 0;
  157 + av_log(nullptr, AV_LOG_INFO, "PPS: %f ms\n", avg_time);
  158 + }
  159 + av_packet_unref(pkt);
  160 + }
  161 +
  162 + e_time = get_cur_time();
  163 + avg_time = double(e_time - s_time) / sum;
  164 + av_log(nullptr, AV_LOG_INFO, "TOOTAL PPS: %f ms\n", avg_time);
  165 +
  166 +end_flag:
  167 + if (codec_ctx != nullptr){
  168 + avcodec_close(codec_ctx);
  169 + avcodec_free_context(&codec_ctx);
  170 + }
  171 +
  172 + if (ifmt_ctx != nullptr){
  173 + avformat_close_input(&ifmt_ctx);
  174 + }
  175 +
  176 + if (pkt != nullptr){
  177 + av_packet_free(&pkt);
  178 + }
  179 +}
0 180 \ No newline at end of file
... ...
save_tool/check_tool.h1 0 → 100644
  1 +#include<string>
  2 +
  3 +using namespace std;
  4 +
  5 +void save_pkt(const string& uri);
0 6 \ No newline at end of file
... ...
save_tool/main.cpp 0 → 100644
  1 +#include"save_tool.h"
  2 +
  3 +
  4 +#include<iostream>
  5 +
  6 +using namespace std;
  7 +
  8 +
  9 +
  10 +int main(int argc, char *argv[]) {
  11 + printf("start \n");
  12 + if (argc != 2) {
  13 + fprintf(stderr, "./xxx uri\n");
  14 + return -1;
  15 + }
  16 +
  17 + char* uri = "rtsp://admin:ad123456@192.168.60.165:554/cam/realmonitor?channel=1&subtype=0";
  18 +
  19 + cout << uri << endl;
  20 +
  21 + save_tool(uri);
  22 +
  23 + return 0;
  24 +}
0 25 \ No newline at end of file
... ...
save_tool/save_tool.cpp 0 → 100644
  1 +extern "C"
  2 +{
  3 + #include <libavcodec/avcodec.h>
  4 + #include <libavdevice/avdevice.h>
  5 + #include <libavformat/avformat.h>
  6 + #include <libavfilter/avfilter.h>
  7 + #include <libavutil/avutil.h>
  8 + #include <libavutil/pixdesc.h>
  9 + #include <libswscale/swscale.h>
  10 + #include <libavutil/imgutils.h>
  11 +}
  12 +
  13 +#include <chrono>
  14 +#include<string>
  15 +
  16 +using namespace std;
  17 +
  18 +bool bFirstFrame = false;
  19 +long last_src_pts = 0;
  20 +long last_pts = 0;
  21 +
  22 +void update_pts(AVPacket* pkt) {
  23 + if (pkt->pts > 0) {
  24 + if (bFirstFrame) {
  25 + bFirstFrame = false;
  26 + last_src_pts = pkt->pts;
  27 + }
  28 + int64_t pkt_pts = pkt->pts;
  29 + pkt->pts = last_pts + (pkt_pts - last_src_pts);
  30 + last_src_pts = pkt_pts;
  31 + last_pts = pkt->pts;
  32 + pkt->dts = pkt->pts;
  33 + }
  34 + else {
  35 + if (bFirstFrame) {
  36 + bFirstFrame = false;
  37 + last_pts = 0;
  38 + }
  39 + pkt->pts = last_pts + 512;
  40 + last_pts = pkt->pts;
  41 + }
  42 +
  43 +}
  44 +
  45 +void *save_tool(const string uri)
  46 +{
  47 + AVFormatContext *i_fmt_ctx;
  48 + AVCodecContext* codec_ctx = nullptr;
  49 + AVCodec *decoder = nullptr;
  50 + AVStream *i_video_stream;
  51 + int video_index;
  52 +
  53 + AVFormatContext *o_fmt_ctx;
  54 + AVStream *o_video_stream;
  55 +
  56 + bool bStop = false;
  57 + int frame_nums = 0;
  58 +
  59 + avcodec_register_all();
  60 + av_register_all();
  61 + avformat_network_init();
  62 +
  63 + /* should set to NULL so that avformat_open_input() allocate a new one */
  64 + i_fmt_ctx = NULL;
  65 +
  66 + const char *filename = "2.mp4";
  67 +
  68 + if (avformat_open_input(&i_fmt_ctx, uri.c_str(), NULL, NULL)!=0)
  69 + {
  70 + fprintf(stderr, " = could not open input file\n");
  71 + return nullptr;
  72 + }
  73 +
  74 + if (avformat_find_stream_info(i_fmt_ctx, NULL)<0)
  75 + {
  76 + fprintf(stderr, " = could not find stream info\n");
  77 + return nullptr;
  78 + }
  79 +
  80 + video_index = av_find_best_stream(i_fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &decoder, 0);
  81 + if (video_index < 0) {
  82 + av_log(nullptr, AV_LOG_ERROR, "Cannot find a video stream in the input file ! \n");
  83 + return nullptr;
  84 + }
  85 +
  86 + codec_ctx = avcodec_alloc_context3(decoder);
  87 + if (!codec_ctx){
  88 + return nullptr;
  89 + }
  90 +
  91 + i_video_stream = i_fmt_ctx->streams[video_index];
  92 + if(avcodec_parameters_to_context(codec_ctx, i_video_stream->codecpar) < 0){
  93 + return nullptr;
  94 + }
  95 +
  96 + avformat_alloc_output_context2(&o_fmt_ctx, NULL, NULL, filename);
  97 +
  98 + o_video_stream = avformat_new_stream(o_fmt_ctx, NULL);
  99 + {
  100 + AVCodecContext *c;
  101 + c = o_video_stream->codec;
  102 + c->bit_rate = 400000;
  103 + c->codec_id = i_video_stream->codec->codec_id;
  104 + c->codec_type = i_video_stream->codec->codec_type;
  105 + c->time_base.num = i_video_stream->time_base.num;
  106 + c->time_base.den = i_video_stream->time_base.den;
  107 + fprintf(stderr, " = time_base.num = %d time_base.den = %d\n", c->time_base.num, c->time_base.den);
  108 + c->width = i_video_stream->codec->width;
  109 + c->height = i_video_stream->codec->height;
  110 + c->pix_fmt = i_video_stream->codec->pix_fmt;
  111 + printf(" = width: %d height: %d pix_fmt: %d\n", c->width, c->height, c->pix_fmt);
  112 + c->flags = i_video_stream->codec->flags;
  113 + c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
  114 + c->me_range = i_video_stream->codec->me_range;
  115 + c->max_qdiff = i_video_stream->codec->max_qdiff;
  116 +
  117 + c->qmin = i_video_stream->codec->qmin;
  118 + c->qmax = i_video_stream->codec->qmax;
  119 +
  120 + c->qcompress = i_video_stream->codec->qcompress;
  121 + }
  122 +
  123 + avio_open(&o_fmt_ctx->pb, filename, AVIO_FLAG_WRITE);
  124 +
  125 + avformat_write_header(o_fmt_ctx, NULL);
  126 +
  127 + AVPacket* i_pkt = av_packet_alloc();
  128 + av_init_packet(i_pkt);
  129 +
  130 + while (av_read_frame(i_fmt_ctx, i_pkt) >= 0){
  131 +
  132 + update_pts(i_pkt);
  133 +
  134 + static int num = 1;
  135 + printf(" = frame %d\n", num++);
  136 + av_interleaved_write_frame(o_fmt_ctx, i_pkt);
  137 +
  138 + av_packet_unref(i_pkt);
  139 +
  140 + if(frame_nums > 750){
  141 + break;
  142 + }
  143 + frame_nums++;
  144 + }
  145 +
  146 + av_packet_free(&i_pkt);
  147 +
  148 + avformat_close_input(&i_fmt_ctx);
  149 +
  150 + av_write_trailer(o_fmt_ctx);
  151 +
  152 + avcodec_close(o_fmt_ctx->streams[0]->codec);
  153 + av_freep(&o_fmt_ctx->streams[0]->codec);
  154 + av_freep(&o_fmt_ctx->streams[0]);
  155 +
  156 + avio_close(o_fmt_ctx->pb);
  157 + av_free(o_fmt_ctx);
  158 +
  159 + printf("end. \n");
  160 +}
0 161 \ No newline at end of file
... ...
save_tool/save_tool.h 0 → 100644
  1 +#include<string>
  2 +
  3 +using namespace std;
  4 +
  5 +void *save_tool(const string uri);
0 6 \ No newline at end of file
... ...
src/FFNvDecoderManager.cpp
... ... @@ -40,6 +40,7 @@ AbstractDecoder* FFNvDecoderManager::createDecoder(MgrDecConfig config){
40 40 if (bRet)
41 41 {
42 42 dec->setName(config.name) ;
  43 + dec->setSnapTimeInterval(config.snap_time_interval);
43 44 decoderMap[config.name] = dec;
44 45  
45 46 LOG_INFO("[{}][{}]- 解码器初始化成功",config.name, config.cfg.uri);
... ...
src/FFNvDecoderManager.h
... ... @@ -12,6 +12,7 @@ struct MgrDecConfig
12 12 DECODER_TYPE dec_type; // 解码器类型
13 13 FFDecConfig cfg; // 解码器配置
14 14 string name{""}; // 解码器名称
  15 + long snap_time_interval; // 定时抓拍时间间隔
15 16 };
16 17  
17 18 /**
... ...
src/FFSaveImg.cpp 0 → 100644
  1 +#include "FFSaveImg.h"
  2 +
  3 +extern "C"
  4 +{
  5 + #include <libavcodec/avcodec.h>
  6 + #include <libavdevice/avdevice.h>
  7 + #include <libavformat/avformat.h>
  8 + #include <libavfilter/avfilter.h>
  9 + #include <libavutil/avutil.h>
  10 + #include <libavutil/pixdesc.h>
  11 + #include <libswscale/swscale.h>
  12 + #include <libavutil/imgutils.h>
  13 +}
  14 +
  15 +int saveJpg(AVFrame *pFrame, const char *out_file) {
  16 +
  17 + int width = pFrame->width;
  18 + int height = pFrame->height;
  19 + AVCodecContext *pCodecCtx = NULL;
  20 +
  21 + AVFormatContext *pFormatCtx = avformat_alloc_context();
  22 + // 设置输出文件格式
  23 + pFormatCtx->oformat = av_guess_format("mjpeg", NULL, NULL);
  24 +
  25 + // 创建并初始化输出AVIOContext
  26 + if (avio_open(&pFormatCtx->pb, out_file, AVIO_FLAG_READ_WRITE) < 0) {
  27 + printf("Couldn't open output file.");
  28 + return -1;
  29 + }
  30 +
  31 + // 构建一个新stream
  32 + AVStream *video_st = avformat_new_stream(pFormatCtx, 0);
  33 + if (video_st == NULL) {
  34 + return -1;
  35 + }
  36 +
  37 + pCodecCtx = video_st->codec;
  38 + pCodecCtx->codec_id = pFormatCtx->oformat->video_codec;
  39 + pCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO;
  40 + pCodecCtx->pix_fmt = AV_PIX_FMT_YUVJ420P;
  41 + pCodecCtx->width = width;
  42 + pCodecCtx->height = height;
  43 +
  44 + pCodecCtx->time_base = (AVRational) {1, 25};
  45 +
  46 + AVCodec *pCodec = avcodec_find_encoder(pCodecCtx->codec_id);
  47 +
  48 + if (!pCodec) {
  49 + printf("Could not find encoder\n");
  50 + return -1;
  51 + }
  52 +
  53 + if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {
  54 + printf("Could not open codec.");
  55 + return -1;
  56 + }
  57 +
  58 + int ret = avformat_write_header(pFormatCtx, NULL);
  59 + if (ret < 0) {
  60 + printf("write_header fail\n");
  61 + return -1;
  62 + }
  63 +
  64 + AVPacket* pkt = av_packet_alloc();
  65 + av_init_packet(pkt);
  66 +
  67 + // 编码数据
  68 + ret = avcodec_send_frame(pCodecCtx, pFrame);
  69 + if (ret < 0) {
  70 + printf("Could not avcodec_send_frame.");
  71 + return -1;
  72 + }
  73 +
  74 + // 得到编码后数据
  75 + ret = avcodec_receive_packet(pCodecCtx, pkt);
  76 + if (ret < 0) {
  77 + printf("Could not avcodec_receive_packet");
  78 + return -1;
  79 + }
  80 +
  81 + ret = av_write_frame(pFormatCtx, pkt);
  82 +
  83 + if (ret < 0) {
  84 + printf("Could not av_write_frame");
  85 + return -1;
  86 + }
  87 +
  88 + av_frame_free(&pFrame);
  89 + av_packet_free(&pkt);
  90 +
  91 + //Write Trailer
  92 + av_write_trailer(pFormatCtx);
  93 +
  94 +
  95 + avcodec_close(pCodecCtx);
  96 + avio_close(pFormatCtx->pb);
  97 + avformat_free_context(pFormatCtx);
  98 +
  99 + return 0;
  100 +}
  101 +
  102 +AVFrame* convert2yuv(int width, int height, unsigned char * rgbbuf, AVPixelFormat src_pix_fmt){
  103 +
  104 + AVPixelFormat dst_pix_fmt = AV_PIX_FMT_YUV420P;
  105 +
  106 + AVFrame *pFrameYUV = av_frame_alloc();
  107 + uint8_t *out_buffer = new uint8_t[avpicture_get_size(dst_pix_fmt, width, height)];
  108 +
  109 + avpicture_fill((AVPicture *)pFrameYUV, out_buffer, dst_pix_fmt, width, height);
  110 +
  111 + AVFrame *rgbFrame = av_frame_alloc();
  112 +
  113 + avpicture_fill((AVPicture *)rgbFrame, rgbbuf, src_pix_fmt, width, height);
  114 +
  115 + SwsContext *sws_ctx = sws_getContext(
  116 + width, height, src_pix_fmt,
  117 + width, height, dst_pix_fmt,
  118 + SWS_BILINEAR, NULL, NULL, NULL);
  119 +
  120 + sws_scale(sws_ctx, rgbFrame->data, rgbFrame->linesize, 0, height, pFrameYUV->data, pFrameYUV->linesize);
  121 + sws_freeContext(sws_ctx);
  122 + av_frame_free(&rgbFrame);
  123 +
  124 + pFrameYUV->width = width;
  125 + pFrameYUV->height = height;
  126 + pFrameYUV->format = dst_pix_fmt;
  127 +
  128 + return pFrameYUV;
  129 +}
  130 +
  131 +void saveJpg(int width, int height, unsigned char * pData, string file_name){
  132 + AVFrame *pFrame = convert2yuv(width, height, pData, AV_PIX_FMT_BGR24);
  133 + saveJpg(pFrame, file_name.c_str());
  134 +}
0 135 \ No newline at end of file
... ...
src/FFSaveImg.h 0 → 100644
  1 +
  2 +#include <string>
  3 +
  4 +using namespace std;
  5 +
  6 +void saveJpg(int width, int height, unsigned char * pData, string file_name);
0 7 \ No newline at end of file
... ...
src/gb28181/FFGB28181Decoder.cpp
... ... @@ -173,11 +173,11 @@ void FFGB28181Decoder::stream_callback(int videoType, char* data, int len, int i
173 173 return;
174 174 }
175 175  
176   - AVPacket framePacket = {};
177   - av_init_packet(&framePacket);
  176 + AVPacket* pkt = av_packet_alloc();
  177 + av_init_packet(pkt);
178 178  
179   - framePacket.size = len;
180   - framePacket.data = (uint8_t*)data;
  179 + pkt->size = len;
  180 + pkt->data = (uint8_t*)data;
181 181  
182 182 if (m_pAVCodecCtx == nullptr) {
183 183 LOG_INFO("frame data is zero --{}", m_dec_name);
... ... @@ -232,11 +232,12 @@ void FFGB28181Decoder::stream_callback(int videoType, char* data, int len, int i
232 232 }
233 233  
234 234 //开始解码
235   - int ret = avcodec_send_packet(m_pAVCodecCtx, &framePacket);
  235 + int ret = avcodec_send_packet(m_pAVCodecCtx, pkt);
236 236 if (ret < 0) {
237 237 //send_exception(RunMessageType::E2002, e_msg);
238 238 LOG_ERROR("Real stream视频解码失败,请检查视频设备{}: avcodec_send_packet failed. ret={}", m_dec_name, ret);
239   - av_packet_unref(&framePacket);
  239 + av_packet_free(&pkt);
  240 + pkt = nullptr;
240 241 return;
241 242 }
242 243  
... ... @@ -245,7 +246,8 @@ void FFGB28181Decoder::stream_callback(int videoType, char* data, int len, int i
245 246 frameH = m_pAVCodecCtx->height;
246 247 if (frameW <= 0 || frameH <= 0) {
247 248 LOG_ERROR("[{}] frame W or H is error! ({},{})", m_dec_name, frameW, frameH);
248   - av_packet_unref(&framePacket);
  249 + av_packet_free(&pkt);
  250 + pkt = nullptr;
249 251 return;
250 252 }
251 253 }
... ... @@ -257,16 +259,20 @@ void FFGB28181Decoder::stream_callback(int videoType, char* data, int len, int i
257 259 ret = avcodec_receive_frame(m_pAVCodecCtx, gpuFrame);
258 260 if ((ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) || ret < 0){
259 261 LOG_ERROR("{} - Failed to receive frame: {}", m_dec_name, ret);
260   - av_packet_unref(&framePacket);
  262 + av_packet_free(&pkt);
  263 + pkt = nullptr;
261 264 av_frame_free(&gpuFrame);
  265 + gpuFrame = nullptr;
262 266 return;
263 267 }
264 268  
265   - av_packet_unref(&framePacket);
  269 + av_packet_free(&pkt);
  270 + pkt = nullptr;
266 271  
267 272 if (gpuFrame->width != frameW || gpuFrame->height != frameH){
268 273 LOG_INFO("AVFrame is inconsistent: width is {}, height is {}; original frameW is {}, frameH is {}--{}", gpuFrame->width, gpuFrame->height, frameW, frameH , m_dec_name);
269 274 av_frame_free(&gpuFrame);
  275 + gpuFrame = nullptr;
270 276 return;
271 277 }
272 278  
... ... @@ -275,6 +281,7 @@ void FFGB28181Decoder::stream_callback(int videoType, char* data, int len, int i
275 281 mFrameQueue.push(gpuFrame);
276 282 }else{
277 283 av_frame_free(&gpuFrame);
  284 + gpuFrame = nullptr;
278 285 }
279 286 m_queue_mutex.unlock();
280 287 }
... ... @@ -297,6 +304,7 @@ void FFGB28181Decoder::post_decode_thread(){
297 304 }
298 305  
299 306 av_frame_free(&gpuFrame);
  307 + gpuFrame = nullptr;
300 308  
301 309 index++;
302 310 if(index >= 100000){
... ...
src/main.cpp
... ... @@ -12,6 +12,7 @@
12 12  
13 13 #include <unistd.h>
14 14  
  15 +#include "FFSaveImg.h"
15 16  
16 17 #ifdef _WIN32
17 18 #include "Winsock2.h"
... ... @@ -24,6 +25,9 @@
24 25  
25 26 #include "utiltools.hpp"
26 27  
  28 +#include "curl/curl.h"
  29 +
  30 +
27 31 #define MIN_RTP_PORT 10000
28 32 #define MAX_RTP_PORT 60000
29 33  
... ... @@ -155,10 +159,34 @@ int CheckCUDAProperty( int devId )
155 159 return 0;
156 160 }
157 161  
  162 +static long get_cur_time_ms() {
  163 + chrono::time_point<chrono::system_clock, chrono::milliseconds> tpMicro
  164 + = chrono::time_point_cast<chrono::milliseconds>(chrono::system_clock::now());
  165 + return tpMicro.time_since_epoch().count();
  166 +}
  167 +
158 168 /**
159 169 * 注意: gpuFrame 在解码器设置的显卡上,后续操作要十分注意这一点,尤其是多线程情况
160 170 * */
161 171 void postDecoded(const void * userPtr, AVFrame * gpuFrame){
  172 +
  173 + // long first_time = get_cur_time_ms();
  174 + // long second_time = 0;
  175 + // int a = 1;
  176 + // while(true){
  177 + // a = a * 99;
  178 + // if(a > 1000000){
  179 + // a = 1;
  180 + // }
  181 + // second_time = get_cur_time_ms();
  182 + // if(second_time - first_time > 100){
  183 + // break;
  184 + // }
  185 + // }
  186 + // return ;
  187 +
  188 + // std::this_thread::sleep_for(std::chrono::milliseconds(100));
  189 +
162 190 AbstractDecoder* decoder = (AbstractDecoder*)userPtr;
163 191 if (decoder!= nullptr)
164 192 {
... ... @@ -235,7 +263,8 @@ static int sum = 0;
235 263 unsigned char *pHwData = nullptr;
236 264  
237 265 void postDecoded0(const void * userPtr, AVFrame * gpuFrame){
238   - // std::this_thread::sleep_for(std::chrono::milliseconds(30000));
  266 +
  267 + std::this_thread::sleep_for(std::chrono::milliseconds(100));
239 268  
240 269 AbstractDecoder* decoder = (AbstractDecoder*)userPtr;
241 270 if (decoder!= nullptr)
... ... @@ -287,12 +316,196 @@ void postDecoded0(const void * userPtr, AVFrame * gpuFrame){
287 316 }
288 317 }
289 318  
  319 +//get请求和post请求数据响应函数
  320 +size_t req_reply(void *ptr, size_t size, size_t nmemb, void *stream)
  321 +{
  322 + //在注释的里面可以打印请求流,cookie的信息
  323 + //cout << "----->reply" << endl;
  324 + string *str = (string*)stream;
  325 + //cout << *str << endl;
  326 + (*str).append((char*)ptr, size*nmemb);
  327 + return size * nmemb;
  328 +}
  329 +
  330 +//http POST请求
  331 +CURLcode curl_post_body_getVideoRealStream(const string &url, const string &postParams, string &response, string devid, string ip, string port)
  332 +{
  333 + // curl初始化
  334 + CURL *curl = curl_easy_init();
  335 + // curl返回值
  336 + CURLcode res;
  337 + if (curl)
  338 + {
  339 + // set params
  340 + //设置curl的请求头
  341 + struct curl_slist* header_list = NULL;
  342 + header_list = curl_slist_append(header_list, "User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko");
  343 + // header_list = curl_slist_append(header_list, "Content-Type:application/x-www-form-urlencoded; charset=UTF-8");
  344 +
  345 + header_list = curl_slist_append(header_list, "Accept: application/json");
  346 + header_list = curl_slist_append(header_list, "Content-Type: application/json");//text/html
  347 + header_list = curl_slist_append(header_list, "charsets: utf-8");
  348 +
  349 + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list);
  350 +
  351 + //不接收响应头数据0代表不接收 1代表接收
  352 + curl_easy_setopt(curl, CURLOPT_HEADER, 0);
  353 +
  354 + //设置请求为post请求
  355 + // curl_easy_setopt(curl, CURLOPT_POST, 1);
  356 + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
  357 +
  358 + //设置请求的URL地址
  359 + curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
  360 + //设置post请求的参数
  361 + // curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postParams.c_str());
  362 +
  363 + //设置ssl验证
  364 + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
  365 + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);
  366 +
  367 + //CURLOPT_VERBOSE的值为1时,会显示详细的调试信息
  368 + curl_easy_setopt(curl, CURLOPT_VERBOSE, 0);
  369 +
  370 + string strResult = "{ \
  371 + \"authinfo\": \"hisense|hisense123|201807311630\", \
  372 + \"method\": \"getVideoRealStream\", \
  373 + \"deviceId\": \""+devid+"\", \
  374 + \"streamFormat\": \"0\", \
  375 + \"recvIp\": \""+ip+"\", \
  376 + \"recvPort\": \""+port+"\", \
  377 + \"remark\": \"\", \
  378 + \"protocol\": \"1\" \
  379 + }";
  380 +
  381 + curl_easy_setopt(curl,CURLOPT_POSTFIELDS,strResult.c_str());
  382 +
  383 + curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
  384 +
  385 + //设置数据接收和写入函数
  386 + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply);
  387 + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&response);
  388 +
  389 + curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
  390 +
  391 + //设置超时时间
  392 + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 6);
  393 + curl_easy_setopt(curl, CURLOPT_TIMEOUT, 6);
  394 +
  395 + // 开启post请求
  396 + res = curl_easy_perform(curl);
  397 + }
  398 + //释放curl
  399 + curl_easy_cleanup(curl);
  400 + return res;
  401 +}
  402 +
  403 +//http POST请求
  404 +CURLcode curl_post_body_stopVideoRealStream(const string &url, const string &postParams, string &response, string handleId)
  405 +{
  406 +
  407 + // curl初始化
  408 + CURL *curl = curl_easy_init();
  409 + // curl返回值
  410 + CURLcode res;
  411 + if (curl)
  412 + {
  413 + // set params
  414 + //设置curl的请求头
  415 + struct curl_slist* header_list = NULL;
  416 + header_list = curl_slist_append(header_list, "User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko");
  417 + // header_list = curl_slist_append(header_list, "Content-Type:application/x-www-form-urlencoded; charset=UTF-8");
  418 +
  419 + header_list = curl_slist_append(header_list, "Accept: application/json");
  420 + header_list = curl_slist_append(header_list, "Content-Type: application/json");//text/html
  421 + header_list = curl_slist_append(header_list, "charsets: utf-8");
  422 +
  423 + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list);
  424 +
  425 + //不接收响应头数据0代表不接收 1代表接收
  426 + curl_easy_setopt(curl, CURLOPT_HEADER, 0);
  427 +
  428 + //设置请求为post请求
  429 + // curl_easy_setopt(curl, CURLOPT_POST, 1);
  430 + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
  431 +
  432 + //设置请求的URL地址
  433 + curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
  434 + //设置post请求的参数
  435 + // curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postParams.c_str());
  436 +
  437 + //设置ssl验证
  438 + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
  439 + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);
  440 +
  441 + //CURLOPT_VERBOSE的值为1时,会显示详细的调试信息
  442 + curl_easy_setopt(curl, CURLOPT_VERBOSE, 0);
  443 +
  444 + string strResult = "{ \
  445 + \"authinfo\": \"hisense|hisense123|201807311630\", \
  446 + \"method\": \"stopVideoRealStream\", \
  447 + \"handleId\": \""+ handleId + "\" \
  448 + }";
  449 +
  450 + curl_easy_setopt(curl,CURLOPT_POSTFIELDS,strResult.c_str());
  451 +
  452 + curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
  453 +
  454 + //设置数据接收和写入函数
  455 + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply);
  456 + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&response);
  457 +
  458 + curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
  459 +
  460 + //设置超时时间
  461 + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 6);
  462 + curl_easy_setopt(curl, CURLOPT_TIMEOUT, 6);
  463 +
  464 + // 开启post请求
  465 + res = curl_easy_perform(curl);
  466 + }
  467 + //释放curl
  468 + curl_easy_cleanup(curl);
  469 + return res;
  470 +}
  471 +
290 472 void decode_finished_cbk(const void* userPtr){
291 473 cout << "当前时间戳: " << UtilTools::get_cur_time_ms() << endl;
292 474 }
293 475  
  476 +string recv_port = "13012";
  477 +
294 478 bool decode_request_stream_cbk(const char* deviceId){
295   - cout << "需在此请求流" << endl;
  479 + // cout << "需在此请求流" << endl;
  480 +
  481 + string url_post = "http://172.16.6.129:7000/httpRequest";
  482 + string paramsLogin = "key1=value1&key2=value2";
  483 + string resPost;
  484 +
  485 + static string last_handleid = "";
  486 + if(!last_handleid.empty()){
  487 + auto res3 = curl_post_body_stopVideoRealStream(url_post, paramsLogin, resPost, last_handleid);
  488 + if (res3 == CURLE_OK)
  489 + {
  490 + cout << resPost << endl;
  491 + }
  492 + }
  493 +
  494 + auto res = curl_post_body_getVideoRealStream(url_post, paramsLogin, resPost, deviceId, "172.16.6.129", recv_port);
  495 + if (res == CURLE_OK)
  496 + {
  497 + cout << resPost << endl;
  498 +
  499 + size_t start = resPost.find_last_of(":") + 3;
  500 + size_t end = resPost.find_last_of("\"");
  501 + if (start == end){
  502 + return false;
  503 + }
  504 + last_handleid = resPost.substr(start,end - start);
  505 +
  506 + cout << last_handleid << endl;
  507 + }
  508 +
296 509 return true;
297 510 }
298 511  
... ... @@ -301,7 +514,7 @@ bool decode_request_stream_cbk(const char* deviceId){
301 514 // string test_uri = "/home/cmhu/data/output_1920x1080.mp4";
302 515 // string test_uri = "rtsp://176.10.0.2:8554/stream";
303 516 // string test_uri = "/mnt/f/fiss/test_data/h265.mp4";
304   -string test_uri = "rtsp://176.10.0.4:8554/stream";
  517 +string test_uri = "rtsp://192.168.10.4:8554/street";
305 518  
306 519 void createDecode(int index, const char* gpu_id){
307 520 FFNvDecoderManager* pDecManager = FFNvDecoderManager::getInstance();
... ... @@ -312,6 +525,7 @@ void createDecode(int index, const char* gpu_id){
312 525 config.cfg.decode_finished_cbk = decode_finished_cbk;
313 526 config.cfg.force_tcp = true;
314 527 config.dec_type = DECODER_TYPE_FFMPEG;
  528 + config.snap_time_interval = 100;
315 529  
316 530 config.cfg.gpuid = gpu_id;
317 531 // if (index % 2 == 0)
... ... @@ -333,10 +547,10 @@ void createDecode(int index, const char* gpu_id){
333 547 pDecManager->startDecodeByName(config.name);
334 548 }
335 549  
336   -void createGB28181Decode(int index, char* gpu_id, int port){
  550 +void createGB28181Decode(char* devid, char* gpu_id, int port){
337 551 FFNvDecoderManager* pDecManager = FFNvDecoderManager::getInstance();
338 552 MgrDecConfig config;
339   - config.name = "dec" + to_string(index);
  553 + config.name = devid;
340 554 config.cfg.uri = config.name;
341 555 config.cfg.post_decoded_cbk = postDecoded;
342 556 config.cfg.decode_finished_cbk = decode_finished_cbk;
... ... @@ -345,8 +559,11 @@ void createGB28181Decode(int index, char* gpu_id, int port){
345 559  
346 560 config.dec_type = DECODER_TYPE_GB28181;
347 561 config.cfg.port = port;//allocRtpPort();
348   -
  562 +
349 563 config.cfg.gpuid = gpu_id;
  564 + config.snap_time_interval = 100;
  565 +
  566 + recv_port = to_string(port);
350 567  
351 568 AbstractDecoder* decoder = pDecManager->createDecoder(config);
352 569 if (!decoder)
... ... @@ -366,10 +583,11 @@ void logFF(void *, int level, const char *fmt, va_list ap)
366 583  
367 584 int main(int argc, char* argv[]){
368 585  
369   - test_uri = "rtsp://admin:admin@123456@192.168.60.176:554/cam/realmonitor?channel=1&subtype=0";//argv[1];
  586 + test_uri = argv[1];
370 587 char* gpuid = argv[2];
371 588 int port = atoi(argv[3]);
372   - cout << test_uri << " gpu_id:" << gpuid << " port:" << port << endl;
  589 + char* devId = argv[4];
  590 + cout << test_uri << " gpu_id:" << gpuid << " port:" << port << " devId:" << devId << endl;
373 591  
374 592 // av_log_set_callback(&logFF);
375 593  
... ... @@ -382,10 +600,20 @@ int main(int argc, char* argv[]){
382 600 // cudaSetDevice(atoi(gpuid));
383 601 while (true)
384 602 {
385   - std::this_thread::sleep_for(std::chrono::minutes(1));
  603 + std::this_thread::sleep_for(std::chrono::seconds(10));
386 604 FFNvDecoderManager* pDecManager = FFNvDecoderManager::getInstance();
387 605 int count = pDecManager->count();
388 606 cout << "当前时间:" << UtilTools::get_cur_time_ms() << " 当前运行路数: " << pDecManager->count() << endl;
  607 + vector<FFImgInfo*> vec_img = pDecManager->timing_snapshot_all();
  608 + for (auto imgInfo : vec_img){
  609 + auto task_id = imgInfo->dec_name;
  610 +
  611 + std::string fpath_ori = "./time_snapshot/" + task_id + "_" + std::to_string(imgInfo->timestamp) + ".jpg";
  612 +
  613 + saveJpg(imgInfo->width, imgInfo->height, imgInfo->pData, fpath_ori.c_str());
  614 +
  615 + pDecManager->releaseFFImgInfo(imgInfo);
  616 + }
389 617 }
390 618  
391 619 return (void*)0;
... ... @@ -413,7 +641,7 @@ int main(int argc, char* argv[]){
413 641 break;
414 642 case 'g':
415 643 case 'G':
416   - createGB28181Decode(i, gpuid, port);
  644 + createGB28181Decode(devId, gpuid, port);
417 645 i++;
418 646 break;
419 647 case 'r':
... ...