Commit 34cc7f89b1d64f58347defb7fe99928917a8a2f5

Authored by Hu Chunming
2 parents bc52e542 6fc86385

Merge branch 'dev-wsl' into 'dev-cmhu'

Dev wsl

See merge request !3
.vscode/launch.json
... ... @@ -6,7 +6,7 @@
6 6 "type": "cppdbg",
7 7 "request": "launch",
8 8 "program": "${workspaceFolder}/bin/lib/test",
9   - "args": [],
  9 + "args": ["rtsp://176.10.0.4:8554/stream","0"],
10 10 "stopAtEntry": false,
11 11 "cwd": "${workspaceFolder}/bin/lib",
12 12 "environment": [],
... ...
.vscode/settings.json
... ... @@ -10,6 +10,57 @@
10 10 "iostream": "cpp",
11 11 "thread": "cpp",
12 12 "nvdec.h": "c",
13   - "chrono": "cpp"
  13 + "chrono": "cpp",
  14 + "atomic": "cpp",
  15 + "bit": "cpp",
  16 + "*.tcc": "cpp",
  17 + "bitset": "cpp",
  18 + "cctype": "cpp",
  19 + "clocale": "cpp",
  20 + "cmath": "cpp",
  21 + "codecvt": "cpp",
  22 + "condition_variable": "cpp",
  23 + "cstdarg": "cpp",
  24 + "cstddef": "cpp",
  25 + "cstdint": "cpp",
  26 + "cstdio": "cpp",
  27 + "cstdlib": "cpp",
  28 + "cstring": "cpp",
  29 + "ctime": "cpp",
  30 + "cwchar": "cpp",
  31 + "cwctype": "cpp",
  32 + "deque": "cpp",
  33 + "map": "cpp",
  34 + "set": "cpp",
  35 + "unordered_map": "cpp",
  36 + "vector": "cpp",
  37 + "exception": "cpp",
  38 + "algorithm": "cpp",
  39 + "functional": "cpp",
  40 + "iterator": "cpp",
  41 + "memory": "cpp",
  42 + "memory_resource": "cpp",
  43 + "numeric": "cpp",
  44 + "optional": "cpp",
  45 + "random": "cpp",
  46 + "ratio": "cpp",
  47 + "system_error": "cpp",
  48 + "tuple": "cpp",
  49 + "type_traits": "cpp",
  50 + "utility": "cpp",
  51 + "fstream": "cpp",
  52 + "initializer_list": "cpp",
  53 + "iomanip": "cpp",
  54 + "istream": "cpp",
  55 + "limits": "cpp",
  56 + "mutex": "cpp",
  57 + "new": "cpp",
  58 + "ostream": "cpp",
  59 + "sstream": "cpp",
  60 + "stdexcept": "cpp",
  61 + "streambuf": "cpp",
  62 + "cfenv": "cpp",
  63 + "cinttypes": "cpp",
  64 + "__nullptr": "cpp"
14 65 }
15 66 }
16 67 \ No newline at end of file
... ...
check_tool/FFCuContextManager.cpp 0 → 100644
  1 +#include "FFCuContextManager.h"
  2 +#include <iostream>
  3 +
  4 +using namespace std;
  5 +
  6 +FFCuContextManager::~FFCuContextManager()
  7 +{
  8 + for(auto iter = ctxMap.begin(); iter != ctxMap.end(); iter++){
  9 + av_buffer_unref(&iter->second);
  10 + }
  11 + ctxMap.clear();
  12 +}
  13 +
  14 +AVBufferRef *FFCuContextManager::getCuCtx(string gpuid)
  15 +{
  16 + AVBufferRef *hw_device_ctx = ctxMap[gpuid];
  17 + if (nullptr == hw_device_ctx)
  18 + {
  19 + // 初始化硬件解码器
  20 + if (av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_CUDA, gpuid.c_str(), nullptr, 0) < 0)
  21 + {
  22 + av_log(nullptr, AV_LOG_ERROR, "Failed to create specified HW device ! \n");
  23 + return nullptr;
  24 + }
  25 + ctxMap[gpuid] = hw_device_ctx;
  26 + }
  27 + return hw_device_ctx;
  28 +}
0 29 \ No newline at end of file
... ...
check_tool/FFCuContextManager.h 0 → 100644
  1 +
  2 +#include<map>
  3 +#include<string>
  4 +
  5 +extern "C"
  6 +{
  7 + #include <libavcodec/avcodec.h>
  8 + #include <libavdevice/avdevice.h>
  9 + #include <libavformat/avformat.h>
  10 + #include <libavfilter/avfilter.h>
  11 + #include <libavutil/avutil.h>
  12 + #include <libavutil/pixdesc.h>
  13 + #include <libswscale/swscale.h>
  14 +}
  15 +
  16 +using namespace std;
  17 +
  18 +class FFCuContextManager{
  19 +public:
  20 + static FFCuContextManager* getInstance(){
  21 + static FFCuContextManager* singleton = nullptr;
  22 + if (singleton == nullptr){
  23 + singleton = new FFCuContextManager();
  24 + }
  25 + return singleton;
  26 + }
  27 +
  28 + AVBufferRef *getCuCtx(string gpuid);
  29 +
  30 +private:
  31 + FFCuContextManager(){}
  32 + ~FFCuContextManager();
  33 +
  34 +private:
  35 + map<string,AVBufferRef *> ctxMap;
  36 +
  37 +};
0 38 \ No newline at end of file
... ...
check_tool/Makefile 0 → 100644
  1 +
  2 +XX = g++
  3 +NVCC = nvcc
  4 +
  5 +PROJECT_ROOT= /mnt/e/fiss/FFNvDecoder
  6 +
  7 +DEPEND_DIR = $(PROJECT_ROOT)/bin
  8 +SRC_ROOT = $(PROJECT_ROOT)/check_tool
  9 +CUDA_ROOT = /usr/local/cuda
  10 +
  11 +TARGET= $(DEPEND_DIR)/lib/check_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 +
... ...
check_tool/check_tool.cpp 0 → 100644
  1 +#include"check_tool.h"
  2 +
  3 +#include "FFCuContextManager.h"
  4 +
  5 +extern "C"
  6 +{
  7 + #include <libavcodec/avcodec.h>
  8 + #include <libavdevice/avdevice.h>
  9 + #include <libavformat/avformat.h>
  10 + #include <libavfilter/avfilter.h>
  11 + #include <libavutil/avutil.h>
  12 + #include <libavutil/pixdesc.h>
  13 + #include <libswscale/swscale.h>
  14 + #include <libavutil/imgutils.h>
  15 +}
  16 +
  17 +#include <chrono>
  18 +
  19 +static AVPixelFormat get_hw_format(AVCodecContext *avctx, const AVPixelFormat *pix_fmts){
  20 +
  21 + const AVPixelFormat *p;
  22 +
  23 + for (p = pix_fmts; *p != -1; p++) {
  24 + if (*p == AV_PIX_FMT_CUDA)
  25 + return *p;
  26 + }
  27 +
  28 + av_log(nullptr, AV_LOG_ERROR, "Failed to get HW surface format. \n");
  29 + return AV_PIX_FMT_NONE;
  30 +}
  31 +
  32 +static long long get_cur_time(){
  33 + // 获取操作系统当前时间点(精确到微秒)
  34 + chrono::time_point<chrono::system_clock, chrono::milliseconds> tpMicro
  35 + = chrono::time_point_cast<chrono::milliseconds>(chrono::system_clock::now());
  36 + // (微秒精度的)时间点 => (微秒精度的)时间戳
  37 + time_t currentTime = tpMicro.time_since_epoch().count();
  38 +
  39 + return (long long )currentTime;
  40 +}
  41 +
  42 +void evalQuality(const string& uri, const char* gpuid){
  43 + AVFormatContext* ifmt_ctx = nullptr;
  44 + AVCodecContext* codec_ctx = nullptr;
  45 + AVCodec *decoder = nullptr;
  46 + AVCodec* codec = nullptr;
  47 + AVPacket* pkt = nullptr;
  48 + int video_index = -1;
  49 + AVStream* st = nullptr;
  50 + SwsContext *img_convert_ctx = nullptr;
  51 + uint8_t *buffer = nullptr;
  52 + int numBytes = 0;
  53 +
  54 + long start_time = 0;
  55 + long end_time = 0;
  56 + long s_time = 0;
  57 + long e_time = 0;
  58 + long long sum = 0;
  59 + double avg_time = 0.0;
  60 +
  61 + int sep = 0;
  62 +
  63 + string cuvid_dec_name = "" ;
  64 + FFCuContextManager* pCtxMgr = FFCuContextManager::getInstance();
  65 + AVDictionary *op = nullptr;
  66 + AVBufferRef *hw_device_ctx = nullptr;
  67 +
  68 +
  69 + avformat_network_init();
  70 +
  71 + // 打开输入视频文件
  72 + AVDictionary *options = nullptr;
  73 + av_dict_set( &options, "bufsize", "655360", 0 );
  74 + av_dict_set( &options, "rtsp_transport", "tcp", 0 );
  75 + // av_dict_set( &options, "listen_timeout", "30", 0 ); // 单位为s
  76 + av_dict_set( &options, "stimeout", "30000000", 0 ); // 单位为 百万分之一秒
  77 +
  78 + ///打开输入的流
  79 + ifmt_ctx = avformat_alloc_context();
  80 + int ret = avformat_open_input(&ifmt_ctx, uri.c_str(), nullptr, &options);
  81 + if (ret != 0){
  82 + av_log(nullptr, AV_LOG_ERROR, "Couldn't open input stream ! \n");
  83 + goto end_flag ;
  84 + }
  85 +
  86 + //查找流信息
  87 + if (avformat_find_stream_info(ifmt_ctx, nullptr) < 0){
  88 + av_log(nullptr, AV_LOG_ERROR, "Couldn't find stream information ! \n");
  89 + goto end_flag ;
  90 + }
  91 +
  92 + // 查找视频流信息
  93 + video_index = av_find_best_stream(ifmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &decoder, 0);
  94 + if (video_index < 0) {
  95 + av_log(nullptr, AV_LOG_ERROR, "Cannot find a video stream in the input file ! \n");
  96 + goto end_flag ;
  97 + }
  98 +
  99 + cuvid_dec_name = string(decoder->name) + "_cuvid";
  100 + codec = avcodec_find_decoder_by_name(cuvid_dec_name.c_str());
  101 + if (!codec){
  102 + av_log(nullptr, AV_LOG_ERROR, "Codec not found ! \n");
  103 + goto end_flag ;
  104 + }
  105 +
  106 + //申请AVCodecContext
  107 + codec_ctx = avcodec_alloc_context3(codec);
  108 + if (!codec_ctx){
  109 + goto end_flag ;
  110 + }
  111 +
  112 + st = ifmt_ctx->streams[video_index];
  113 + if(avcodec_parameters_to_context(codec_ctx, st->codecpar) < 0){
  114 + goto end_flag ;
  115 + }
  116 +
  117 + {
  118 + av_log(nullptr, AV_LOG_INFO, "path: %s \n", ifmt_ctx->url);
  119 + av_log(nullptr, AV_LOG_INFO, "format: %s \n", ifmt_ctx->iformat->name);
  120 + const char* profile = avcodec_profile_name(codec_ctx->codec_id, codec_ctx->profile);
  121 + av_log(nullptr, AV_LOG_INFO, "codec: %s(%s) \n", decoder->name, profile);
  122 + const char* pix_fmt_name = av_get_pix_fmt_name(codec_ctx->pix_fmt);
  123 + av_log(nullptr, AV_LOG_INFO, "pix_fmt_name: %s \n", pix_fmt_name);
  124 + av_log(nullptr, AV_LOG_INFO, "width x height: %dX%d \n", st->codecpar->width, st->codecpar->height);
  125 +
  126 + av_log(NULL, AV_LOG_INFO, "frame_rate: %1.0f ", av_q2d(st->r_frame_rate));
  127 + av_log(NULL, AV_LOG_INFO, " --> reference PPS: %f ms\n", 1/av_q2d(st->r_frame_rate) * 1000);
  128 +
  129 + }
  130 +
  131 + // 设置解码器管理器的像素格式回调函数
  132 + codec_ctx->get_format = get_hw_format;
  133 +
  134 + hw_device_ctx = pCtxMgr->getCuCtx(gpuid);
  135 + if(nullptr == hw_device_ctx){
  136 + av_log(nullptr, AV_LOG_ERROR, "create CUDA context failed ! \n");
  137 + goto end_flag ;
  138 + }
  139 + codec_ctx->hw_device_ctx = av_buffer_ref(hw_device_ctx);
  140 + if (nullptr == codec_ctx->hw_device_ctx){
  141 + goto end_flag ;
  142 + }
  143 +
  144 + // 打开解码器流
  145 + av_dict_set( &op, "gpu", gpuid, 0 );
  146 + if (avcodec_open2(codec_ctx, codec, &op) < 0) {
  147 + av_log(nullptr, AV_LOG_ERROR, "Failed to open codec for stream ! \n");
  148 + goto end_flag ;
  149 + }
  150 +
  151 + s_time = get_cur_time();
  152 + start_time = get_cur_time();
  153 + pkt = av_packet_alloc();
  154 + while (av_read_frame(ifmt_ctx, pkt) >= 0){
  155 + end_time = get_cur_time();
  156 + sum ++ ;
  157 + sep ++ ;
  158 + if(end_time - start_time > 1000){
  159 + avg_time = double(end_time - start_time) / sep;
  160 + start_time = get_cur_time();
  161 + sep = 0;
  162 + av_log(nullptr, AV_LOG_INFO, "PPS: %f ms\n", avg_time);
  163 + }
  164 + av_packet_unref(pkt);
  165 + }
  166 +
  167 + e_time = get_cur_time();
  168 + avg_time = double(e_time - s_time) / sum;
  169 + av_log(nullptr, AV_LOG_INFO, "TOOTAL PPS: %f ms\n", avg_time);
  170 +
  171 +end_flag:
  172 + if (codec_ctx != nullptr){
  173 + avcodec_close(codec_ctx);
  174 + avcodec_free_context(&codec_ctx);
  175 + }
  176 +
  177 + if (ifmt_ctx != nullptr){
  178 + avformat_close_input(&ifmt_ctx);
  179 + }
  180 +
  181 + if (pkt != nullptr){
  182 + av_packet_free(&pkt);
  183 + }
  184 +}
0 185 \ No newline at end of file
... ...
check_tool/check_tool.h 0 → 100644
  1 +#include<string>
  2 +
  3 +using namespace std;
  4 +
  5 +void evalQuality(const string& uri, const char* gpuid);
0 6 \ No newline at end of file
... ...
check_tool/main.cpp 0 → 100644
  1 +#include"check_tool.h"
  2 +
  3 +#include <cuda.h>
  4 +
  5 +#include<iostream>
  6 +
  7 +using namespace std;
  8 +
  9 +
  10 +#define checkCudaErrors(S) do {CUresult status; \
  11 + status = S; \
  12 + if (status != CUDA_SUCCESS ) {std::cout << __LINE__ <<" checkCudaErrors - status = " << status << std::endl; \
  13 + exit(EXIT_FAILURE);}\
  14 + } while (false)
  15 +
  16 +
  17 +
  18 +int CheckCUDAProperty( int devId )
  19 +{
  20 + cuInit(0);
  21 +
  22 + CUdevice dev = devId;
  23 + size_t memSize = 0;
  24 + char devName[256] = {0};
  25 + int major = 0, minor = 0;
  26 + CUresult rlt = CUDA_SUCCESS;
  27 +
  28 + checkCudaErrors(cuDeviceGetAttribute(&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, dev));
  29 + checkCudaErrors(cuDeviceGetAttribute(&minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, dev));
  30 +
  31 + checkCudaErrors( cuDeviceGetName(devName, sizeof( devName ), dev) );
  32 +
  33 + printf( "Using GPU Device %d: %s has SM %d.%d compute capability\n",
  34 + dev, devName, major, minor );
  35 +
  36 + rlt = cuDeviceTotalMem( &memSize, dev );
  37 + checkCudaErrors( rlt );
  38 +
  39 + printf( "Total amount of global memory: %4.4f MB\n",
  40 + (float)memSize / ( 1024 * 1024 ) );
  41 +
  42 + return 0;
  43 +}
  44 +
  45 +
  46 +int main(int argc, char *argv[]) {
  47 + printf("start \n");
  48 + if (argc != 3) {
  49 + fprintf(stderr, "./xxx uri gpu_id\n");
  50 + return -1;
  51 + }
  52 +
  53 + char* uri = argv[1];
  54 + char* gpuid = argv[2];
  55 +
  56 + CheckCUDAProperty(atoi(gpuid));
  57 +
  58 + evalQuality(uri,gpuid);
  59 +
  60 + return 0;
  61 +}
0 62 \ No newline at end of file
... ...
src/FFCuContextManager.cpp
... ... @@ -19,7 +19,7 @@ AVBufferRef *FFCuContextManager::getCuCtx(string gpuid)
19 19 // 初始化硬件解码器
20 20 if (av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_CUDA, gpuid.c_str(), nullptr, 0) < 0)
21 21 {
22   - cout << "Failed to create specified HW device.";
  22 + av_log(nullptr, AV_LOG_ERROR, "Failed to create specified HW device ! \n");
23 23 return nullptr;
24 24 }
25 25 ctxMap[gpuid] = hw_device_ctx;
... ...
src/FFNvDecoder.cpp
1 1 #include "FFNvDecoder.h"
2   -#include<iostream>
3 2  
4 3 #include <chrono>
5 4 #include <thread>
6 5 #include <fstream>
7 6  
8   -#include <chrono>
9   -
10 7 #include "FFCuContextManager.h"
11 8  
12 9 using namespace std;
... ... @@ -24,7 +21,7 @@ static AVPixelFormat get_hw_format(AVCodecContext *avctx, const AVPixelFormat *p
24 21 return *p;
25 22 }
26 23  
27   - //cout << "Failed to get HW surface format";
  24 + av_log(nullptr, AV_LOG_ERROR, "Failed to get HW surface format. \n");
28 25 return AV_PIX_FMT_NONE;
29 26 }
30 27  
... ... @@ -86,13 +83,13 @@ bool FFNvDecoder::init(const char* uri, const char* gpuid, bool force_tcp)
86 83 fmt_ctx = avformat_alloc_context();
87 84 const char* input_file = uri;
88 85 if (avformat_open_input(&fmt_ctx, input_file, nullptr, &options) != 0) {
89   - cout << "Cannot open input file: " << input_file;
  86 + av_log(nullptr, AV_LOG_ERROR, "Cannot open input file: %s \n", input_file);
90 87 return false;
91 88 }
92 89  
93 90 // 查找流信息
94 91 if (avformat_find_stream_info(fmt_ctx, nullptr) < 0) {
95   - cout << "Cannot find input stream information";
  92 + av_log(nullptr, AV_LOG_ERROR, "Cannot find input stream information ! \n");
96 93 return false;
97 94 }
98 95  
... ... @@ -100,7 +97,7 @@ bool FFNvDecoder::init(const char* uri, const char* gpuid, bool force_tcp)
100 97 AVCodec *decoder = nullptr;
101 98 stream_index = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &decoder, 0);
102 99 if (stream_index < 0) {
103   - cout << "Cannot find a video stream in the input file";
  100 + av_log(nullptr, AV_LOG_ERROR, "Cannot find a video stream in the input file ! \n");
104 101 return false;
105 102 }
106 103  
... ... @@ -121,7 +118,13 @@ bool FFNvDecoder::init(const char* uri, const char* gpuid, bool force_tcp)
121 118 hw_pix_fmt = AV_PIX_FMT_CUDA;
122 119  
123 120 FFCuContextManager* pCtxMgr = FFCuContextManager::getInstance();
124   - avctx->hw_device_ctx = av_buffer_ref(pCtxMgr->getCuCtx(gpuid));
  121 +
  122 + AVBufferRef *hw_device_ctx = pCtxMgr->getCuCtx(gpuid);
  123 + if(nullptr == hw_device_ctx){
  124 + av_log(nullptr, AV_LOG_ERROR, "create CUDA context failed ! \n");
  125 + return false;
  126 + }
  127 + avctx->hw_device_ctx = av_buffer_ref(hw_device_ctx);
125 128 if (nullptr == avctx->hw_device_ctx)
126 129 {
127 130 return false;
... ... @@ -130,9 +133,9 @@ bool FFNvDecoder::init(const char* uri, const char* gpuid, bool force_tcp)
130 133 // 打开解码器流
131 134 AVDictionary *op = nullptr;
132 135 av_dict_set( &op, "gpu", gpuid, 0 );
133   - av_dict_set( &op, "surfaces", "3", 0 );
  136 + // av_dict_set( &op, "surfaces", "10", 0 );
134 137 if (avcodec_open2(avctx, vcodec, &op) < 0) {
135   - cout << "Failed to open codec for stream" << stream_index;
  138 + av_log(nullptr, AV_LOG_ERROR, "Failed to open codec for stream ! \n");
136 139 return false;
137 140 }
138 141  
... ... @@ -162,14 +165,12 @@ void FFNvDecoder::start(){
162 165  
163 166 static long long get_cur_time(){
164 167 // 获取操作系统当前时间点(精确到微秒)
165   - chrono::time_point<chrono::system_clock, chrono::microseconds> tpMicro
166   - = chrono::time_point_cast<chrono::microseconds>(chrono::system_clock::now());
  168 + chrono::time_point<chrono::system_clock, chrono::milliseconds> tpMicro
  169 + = chrono::time_point_cast<chrono::milliseconds>(chrono::system_clock::now());
167 170 // (微秒精度的)时间点 => (微秒精度的)时间戳
168   - time_t totalMicroSeconds = tpMicro.time_since_epoch().count();
169   -
170   - long long currentTime = ((long long)totalMicroSeconds)/1000;
  171 + time_t currentTime = tpMicro.time_since_epoch().count();
171 172  
172   - return currentTime;
  173 + return (long long )currentTime;
173 174 }
174 175  
175 176 void FFNvDecoder::decode_thread()
... ... @@ -208,14 +209,9 @@ void FFNvDecoder::decode_thread()
208 209 }
209 210  
210 211 int result = av_read_frame(fmt_ctx, pkt);
211   - if (result == AVERROR_EOF)
  212 + if (result == AVERROR_EOF || result < 0)
212 213 {
213   - cout << "Failed to read frame!" << endl;
214   - break;
215   - }
216   - if (result < 0)
217   - {
218   - cout << "Failed to read frame!" << endl;
  214 + av_log(nullptr, AV_LOG_ERROR, "Failed to read frame! \n");
219 215 break;
220 216 }
221 217  
... ... @@ -234,19 +230,16 @@ void FFNvDecoder::decode_thread()
234 230 }
235 231 }
236 232  
237   - if (stream_index == pkt->stream_index)
238   - {
  233 + if (stream_index == pkt->stream_index){
239 234 result = avcodec_send_packet(avctx, pkt);
240   - if (result < 0)
241   - {
242   - cout << "Failed to send pkt:" << result << endl;
  235 + if (result < 0){
  236 + av_log(nullptr, AV_LOG_ERROR, "%s - Failed to send pkt: %d \n",name,result);
243 237 continue;
244 238 }
245 239  
246 240 result = avcodec_receive_frame(avctx, gpuFrame);
247   - if (result == AVERROR(EAGAIN) || result == AVERROR_EOF || result < 0)
248   - {
249   - cout << "Failed to receive frame"<< endl;
  241 + if ((result == AVERROR(EAGAIN) || result == AVERROR_EOF) || result < 0){
  242 + av_log(nullptr, AV_LOG_ERROR, "%s - Failed to receive frame: %d \n",name,result);
250 243 continue;
251 244 }
252 245  
... ... @@ -255,6 +248,14 @@ void FFNvDecoder::decode_thread()
255 248 av_packet_unref(pkt);
256 249 }
257 250  
  251 + // 队列中没有数据了再结束
  252 + while (mFrameQueue.length() > 0){
  253 + if(!m_bRunning){
  254 + break;
  255 + }
  256 + std::this_thread::sleep_for(std::chrono::milliseconds(10));
  257 + }
  258 +
258 259 m_bRunning = false;
259 260  
260 261 // long end_time = get_cur_time();
... ... @@ -266,9 +267,11 @@ void FFNvDecoder::decode_thread()
266 267 pthread_join(m_post_decode_thread,0);
267 268 }
268 269  
  270 + decode_finished_cbk(m_userPtr);
  271 +
269 272 decode_finished();
270 273  
271   - cout << "decode thread exited." << endl;
  274 + av_log(nullptr, AV_LOG_INFO, "%s - decode thread exited. \n",name);
272 275 }
273 276  
274 277 void FFNvDecoder::decode_finished()
... ... @@ -289,7 +292,7 @@ void FFNvDecoder::decode_finished()
289 292  
290 293 void FFNvDecoder::post_decode_thread()
291 294 {
292   - while (m_bRunning)
  295 + while (m_bRunning || mFrameQueue.length() > 0)
293 296 {
294 297 AVFrame * gpuFrame = mFrameQueue.getHead();
295 298 if (gpuFrame == nullptr)
... ... @@ -302,8 +305,8 @@ void FFNvDecoder::post_decode_thread()
302 305  
303 306 mFrameQueue.addHead();
304 307 }
305   -
306   - cout << "post decode thread exited." << endl;
  308 +
  309 + av_log(nullptr, AV_LOG_INFO, "post decode thread exited. \n");
307 310 }
308 311  
309 312 void FFNvDecoder::close()
... ... @@ -338,12 +341,16 @@ bool FFNvDecoder::isFinished()
338 341 return m_bFinished;
339 342 }
340 343  
  344 +bool FFNvDecoder::isPausing(){
  345 + return m_bPause;
  346 +}
  347 +
341 348 bool FFNvDecoder::getResolution( int &width, int &height )
342 349 {
343   - if (avctx != nullptr)
  350 + if (stream != nullptr && stream->codecpar != nullptr)
344 351 {
345   - width = avctx->width;
346   - height = avctx->height;
  352 + width = stream->codecpar->width;
  353 + height = stream->codecpar->height;
347 354 return true;
348 355 }
349 356  
... ... @@ -363,4 +370,145 @@ void FFNvDecoder::resume()
363 370 void FFNvDecoder::setDecKeyframe(bool bKeyframe)
364 371 {
365 372 m_dec_keyframe = bKeyframe;
366   -}
367 373 \ No newline at end of file
  374 +}
  375 +
  376 +int FFNvDecoder::getCachedQueueLength(){
  377 + return mFrameQueue.length();
  378 +}
  379 +
  380 +FFImgInfo* FFNvDecoder::snapshot(const string& uri){
  381 +
  382 + AVFormatContext* ifmt_ctx = nullptr;
  383 + AVCodecContext* codec_ctx = nullptr;
  384 + AVCodec* codec = nullptr;
  385 + AVPacket* pkt = nullptr;
  386 + AVFrame *frame = nullptr;
  387 + AVFrame *pFrameRGB = nullptr;
  388 + int video_index = -1;
  389 + AVStream* st = nullptr;
  390 + SwsContext *img_convert_ctx = nullptr;
  391 + uint8_t *buffer = nullptr;
  392 + int numBytes = 0;
  393 +
  394 + FFImgInfo* imgInfo = nullptr;
  395 +
  396 +
  397 + avformat_network_init();
  398 +
  399 + // 打开输入视频文件
  400 + AVDictionary *options = nullptr;
  401 + av_dict_set( &options, "bufsize", "655360", 0 );
  402 + av_dict_set( &options, "rtsp_transport", "tcp", 0 );
  403 + // av_dict_set( &options, "listen_timeout", "30", 0 ); // 单位为s
  404 + av_dict_set( &options, "stimeout", "30000000", 0 ); // 单位为 百万分之一秒
  405 +
  406 + ///打开输入的流
  407 + ifmt_ctx = avformat_alloc_context();
  408 + int ret = avformat_open_input(&ifmt_ctx, uri.c_str(), nullptr, &options);
  409 + if (ret != 0){
  410 + av_log(nullptr, AV_LOG_ERROR, "Couldn't open input stream ! \n");
  411 + goto end_flag ;
  412 + }
  413 +
  414 + //查找流信息
  415 + if (avformat_find_stream_info(ifmt_ctx, nullptr) < 0){
  416 + av_log(nullptr, AV_LOG_ERROR, "Couldn't find stream information ! \n");
  417 + goto end_flag ;
  418 + }
  419 +
  420 + //找到视频流索引
  421 + video_index = av_find_best_stream(ifmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, nullptr, 0);
  422 +
  423 + st = ifmt_ctx->streams[video_index];
  424 +
  425 + //找到解码器
  426 + codec = avcodec_find_decoder(st->codecpar->codec_id);
  427 + if (!codec){
  428 + av_log(nullptr, AV_LOG_ERROR, "Codec not found ! \n");
  429 + goto end_flag ;
  430 + }
  431 +
  432 + //申请AVCodecContext
  433 + codec_ctx = avcodec_alloc_context3(codec);
  434 + if (!codec_ctx){
  435 + goto end_flag ;
  436 + }
  437 +
  438 + avcodec_parameters_to_context(codec_ctx, ifmt_ctx->streams[video_index]->codecpar);
  439 +
  440 + //打开解码器
  441 + if ((ret = avcodec_open2(codec_ctx, codec, nullptr) < 0)){
  442 + goto end_flag ;
  443 + }
  444 +
  445 + // 计算解码后原始数据所需缓冲区大小,并分配内存空间 Determine required buffer size and allocate buffer
  446 + numBytes = av_image_get_buffer_size(AV_PIX_FMT_RGB24, codec_ctx->width, codec_ctx->height, 1);
  447 + buffer = (uint8_t *)av_malloc(numBytes * sizeof(uint8_t));
  448 +
  449 + pFrameRGB = av_frame_alloc();
  450 + av_image_fill_arrays(pFrameRGB->data, pFrameRGB->linesize, buffer, AV_PIX_FMT_BGR24, codec_ctx->width, codec_ctx->height, 1);
  451 +
  452 + img_convert_ctx = sws_getContext(codec_ctx->width, codec_ctx->height,codec_ctx->pix_fmt, codec_ctx->width, codec_ctx->height, AV_PIX_FMT_BGR24,
  453 + SWS_BICUBIC, nullptr, nullptr, nullptr);
  454 +
  455 + pkt = av_packet_alloc();
  456 + frame = av_frame_alloc();
  457 + while (av_read_frame(ifmt_ctx, pkt) >= 0){
  458 + if (pkt->stream_index == video_index){
  459 + int ret = avcodec_send_packet(codec_ctx, pkt);
  460 + if (ret >= 0){
  461 + ret = avcodec_receive_frame(codec_ctx, frame);
  462 + if ((ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) || ret < 0){
  463 + av_log(nullptr, AV_LOG_ERROR, "Failed to receive frame: %d \n", ret);
  464 + av_packet_unref(pkt);
  465 + continue;
  466 + }
  467 +
  468 + sws_scale(img_convert_ctx, (const unsigned char* const*)frame->data, frame->linesize, 0, codec_ctx->height, pFrameRGB->data, pFrameRGB->linesize);
  469 +
  470 + imgInfo = new FFImgInfo();
  471 + imgInfo->pData = buffer;
  472 + imgInfo->height = codec_ctx->height;
  473 + imgInfo->width = codec_ctx->width;
  474 + break;
  475 + }
  476 + }
  477 +
  478 + av_packet_unref(pkt);
  479 + }
  480 +
  481 +end_flag:
  482 + if (codec_ctx != nullptr){
  483 + avcodec_close(codec_ctx);
  484 + avcodec_free_context(&codec_ctx);
  485 + }
  486 +
  487 + if (ifmt_ctx != nullptr){
  488 + avformat_close_input(&ifmt_ctx);
  489 + }
  490 +
  491 + if (frame != nullptr){
  492 + av_frame_free(&frame);
  493 + }
  494 +
  495 + if (pFrameRGB != nullptr){
  496 + av_frame_free(&pFrameRGB);
  497 + }
  498 +
  499 + if (pkt != nullptr){
  500 + av_packet_free(&pkt);
  501 + }
  502 +
  503 + return imgInfo;
  504 +}
  505 +
  506 +void FFNvDecoder::releaseFFImgInfo(FFImgInfo* info){
  507 + if(nullptr != info){
  508 + if(info->pData != nullptr){
  509 + av_free(info->pData);
  510 + info->pData = nullptr;
  511 + }
  512 + delete info;
  513 + info = nullptr;
  514 + }
  515 +}
... ...
src/FFNvDecoder.h
... ... @@ -12,6 +12,7 @@ extern &quot;C&quot;
12 12 #include <libavutil/avutil.h>
13 13 #include <libavutil/pixdesc.h>
14 14 #include <libswscale/swscale.h>
  15 + #include <libavutil/imgutils.h>
15 16 }
16 17  
17 18 using namespace std;
... ... @@ -29,14 +30,22 @@ using namespace std;
29 30 **************************************************/
30 31 typedef void(*POST_DECODE_CALLBACK)(const void * userPtr, AVFrame * gpuFrame);
31 32  
32   -struct FFDecConfig
33   -{
  33 +typedef void(*DECODE_FINISHED_CALLBACK)(const void* userPtr);
  34 +
  35 +struct FFDecConfig{
34 36 string uri; // 视频地址
35 37 POST_DECODE_CALLBACK post_decoded_cbk; // 解码数据回调接口
  38 + DECODE_FINISHED_CALLBACK decode_finished_cbk; // 解码线程结束后的回调接口
36 39 string gpuid; // gpu id
37 40 bool force_tcp{true}; // 是否指定使用tcp连接
38 41 };
39 42  
  43 +struct FFImgInfo{
  44 + int width;
  45 + int height;
  46 + unsigned char * pData;
  47 +};
  48 +
40 49 class FFNvDecoder{
41 50 public:
42 51 FFNvDecoder();
... ... @@ -51,6 +60,7 @@ public:
51 60  
52 61 bool isRunning();
53 62 bool isFinished();
  63 + bool isPausing();
54 64 bool getResolution( int &width, int &height );
55 65  
56 66 void setName(string nm);
... ... @@ -58,6 +68,12 @@ public:
58 68  
59 69 bool isSurport(FFDecConfig& cfg);
60 70  
  71 + int getCachedQueueLength();
  72 +
  73 + static FFImgInfo* snapshot(const string& uri);
  74 +
  75 + static void releaseFFImgInfo(FFImgInfo*);
  76 +
61 77 public:
62 78 AVPixelFormat getHwPixFmt();
63 79  
... ... @@ -69,6 +85,7 @@ private:
69 85  
70 86 public:
71 87 POST_DECODE_CALLBACK post_decoded_cbk;
  88 + DECODE_FINISHED_CALLBACK decode_finished_cbk;
72 89 const void * m_userPtr;
73 90 FFDecConfig m_cfg;
74 91  
... ...
src/FFNvDecoderManager.cpp
1 1 #include "FFNvDecoderManager.h"
2   -#include<iostream>
3 2  
4 3 using namespace std;
5 4  
6 5  
7   -FFNvDecoder* FFNvDecoderManager::createDecoder(MgrDecConfig& config){
  6 +FFNvDecoder* FFNvDecoderManager::createDecoder(MgrDecConfig config){
8 7  
9 8 closeAllFinishedDecoder();
10 9  
11   - int num = decoderMap.count(config.name);
12   - if (num > 0)
13   - {
14   - cout << "已存在name所标记的解码器" << endl;
  10 + std::lock_guard<std::mutex> l(m_mutex);
  11 +
  12 + auto it = decoderMap.find(config.name);
  13 + if (it != decoderMap.end()){
  14 + av_log(NULL, AV_LOG_ERROR, "已存在name所标记的解码器 \n");
15 15 return nullptr;
16 16 }
17 17  
... ... @@ -26,6 +26,7 @@ FFNvDecoder* FFNvDecoderManager::createDecoder(MgrDecConfig&amp; config){
26 26 {
27 27 dec->setName(config.name) ;
28 28 dec->post_decoded_cbk = config.cfg.post_decoded_cbk;
  29 + dec->decode_finished_cbk = config.cfg.decode_finished_cbk;
29 30 decoderMap[config.name] = dec;
30 31 return dec;
31 32 }
... ... @@ -41,10 +42,12 @@ bool FFNvDecoderManager::setUserPtr(const string name, const void * userPtr)
41 42 {
42 43 if (name.empty())
43 44 {
44   - cout << "name 为空!"<< endl;
  45 + av_log(NULL, AV_LOG_ERROR, "name 为空! \n");
45 46 return false;
46 47 }
47 48  
  49 + std::lock_guard<std::mutex> l(m_mutex);
  50 +
48 51 auto dec = decoderMap.find(name);
49 52 if (dec != decoderMap.end())
50 53 {
... ... @@ -52,7 +55,7 @@ bool FFNvDecoderManager::setUserPtr(const string name, const void * userPtr)
52 55 return true;
53 56 }
54 57  
55   - cout << "没有找到name为" << name << "的解码器!" << endl;
  58 + av_log(NULL, AV_LOG_ERROR, "没有找到name为 %s 的解码器! \n", name.c_str());
56 59 return false;
57 60 }
58 61  
... ... @@ -60,17 +63,19 @@ FFNvDecoder* FFNvDecoderManager::getDecoderByName(const string name)
60 63 {
61 64 if (name.empty())
62 65 {
63   - cout << "name 为空!"<< endl;
  66 + av_log(NULL, AV_LOG_ERROR, "name 为空! \n");
64 67 return nullptr;
65 68 }
66 69  
  70 + std::lock_guard<std::mutex> l(m_mutex);
  71 +
67 72 auto dec = decoderMap.find(name);
68 73 if (dec != decoderMap.end())
69 74 {
70 75 return dec->second;
71 76 }
72 77  
73   - cout << "没有找到name为" << name << "的解码器!" << endl;
  78 + av_log(NULL, AV_LOG_ERROR, "没有找到name为 %s 的解码器! \n", name.c_str());
74 79 return nullptr;
75 80 }
76 81  
... ... @@ -84,10 +89,12 @@ void FFNvDecoderManager::startDecode(FFNvDecoder* dec){
84 89 bool FFNvDecoderManager::startDecodeByName(const string name){
85 90 if (name.empty())
86 91 {
87   - cout << "name 为空!"<< endl;
  92 + av_log(NULL, AV_LOG_ERROR, "name 为空! \n");
88 93 return false;
89 94 }
90 95  
  96 + std::lock_guard<std::mutex> l(m_mutex);
  97 +
91 98 auto dec = decoderMap.find(name);
92 99 if (dec != decoderMap.end())
93 100 {
... ... @@ -95,11 +102,14 @@ bool FFNvDecoderManager::startDecodeByName(const string name){
95 102 return true;
96 103 }
97 104  
98   - cout << "没有找到name为" << name << "的解码器!" << endl;
  105 + av_log(NULL, AV_LOG_ERROR, "没有找到name为 %s 的解码器! \n", name.c_str());
99 106 return false;
100 107 }
101 108  
102 109 void FFNvDecoderManager::startAllDecode(){
  110 +
  111 + std::lock_guard<std::mutex> l(m_mutex);
  112 +
103 113 for(auto iter = decoderMap.begin(); iter != decoderMap.end(); iter++){
104 114 if (!iter->second->isRunning())
105 115 {
... ... @@ -111,11 +121,12 @@ void FFNvDecoderManager::startAllDecode(){
111 121 bool FFNvDecoderManager::closeDecoderByName(const string name){
112 122 if (name.empty())
113 123 {
114   - cout << "name 为空!"<< endl;
  124 + av_log(NULL, AV_LOG_ERROR, "name 为空! \n");
115 125 return false;
116 126 }
117 127  
118   - m_mutex_erase.lock();
  128 + std::lock_guard<std::mutex> l(m_mutex);
  129 +
119 130 auto dec = decoderMap.find(name);
120 131 if (dec != decoderMap.end())
121 132 {
... ... @@ -124,30 +135,29 @@ bool FFNvDecoderManager::closeDecoderByName(const string name){
124 135 dec->second = nullptr;
125 136 decoderMap.erase(dec);
126 137  
127   - m_mutex_erase.unlock();
128 138 return true;
129 139 }
130 140  
131   - m_mutex_erase.unlock();
132   - cout << "没有找到name为" << name << "的解码器!" << endl;
  141 + av_log(NULL, AV_LOG_ERROR, "没有找到name为 %s 的解码器! \n", name.c_str());
133 142 return false;
134 143 }
135 144  
136 145 void FFNvDecoderManager::closeAllDecoder()
137 146 {
138   - m_mutex_erase.lock();
  147 + std::lock_guard<std::mutex> l(m_mutex);
  148 +
139 149 for(auto iter = decoderMap.begin(); iter != decoderMap.end(); iter++){
140 150 iter->second->close();
141 151 delete iter->second;
142 152 iter->second = nullptr;
143 153 }
144 154 decoderMap.clear();
145   - m_mutex_erase.unlock();
146 155 }
147 156  
148 157 void FFNvDecoderManager::closeAllFinishedDecoder()
149 158 {
150   - m_mutex_erase.lock();
  159 + std::lock_guard<std::mutex> l(m_mutex);
  160 +
151 161 for(auto iter = decoderMap.begin(); iter != decoderMap.end(); ){
152 162 if (iter->second->isFinished())
153 163 {
... ... @@ -160,13 +170,13 @@ void FFNvDecoderManager::closeAllFinishedDecoder()
160 170 iter++ ;
161 171 }
162 172 }
163   - m_mutex_erase.unlock();
164 173 }
165 174  
166 175 int FFNvDecoderManager::count()
167 176 {
168 177 closeAllFinishedDecoder();
169 178  
  179 + std::lock_guard<std::mutex> l(m_mutex);
170 180 return decoderMap.size();
171 181 }
172 182  
... ... @@ -174,10 +184,12 @@ bool FFNvDecoderManager::pauseDecoder(const string name)
174 184 {
175 185 if (name.empty())
176 186 {
177   - cout << "name 为空!"<< endl;
  187 + av_log(NULL, AV_LOG_ERROR, "name 为空! \n");
178 188 return false;
179 189 }
180 190  
  191 + std::lock_guard<std::mutex> l(m_mutex);
  192 +
181 193 auto dec = decoderMap.find(name);
182 194 if (dec != decoderMap.end())
183 195 {
... ... @@ -185,7 +197,7 @@ bool FFNvDecoderManager::pauseDecoder(const string name)
185 197 return true;
186 198 }
187 199  
188   - cout << "没有找到name为" << name << "的解码器!" << endl;
  200 + av_log(NULL, AV_LOG_ERROR, "没有找到name为 %s 的解码器! \n", name.c_str());
189 201 return false;
190 202 }
191 203  
... ... @@ -193,10 +205,12 @@ bool FFNvDecoderManager::resumeDecoder(const string name)
193 205 {
194 206 if (name.empty())
195 207 {
196   - cout << "name 为空!"<< endl;
  208 + av_log(NULL, AV_LOG_ERROR, "name 为空! \n");
197 209 return false;
198 210 }
199 211  
  212 + std::lock_guard<std::mutex> l(m_mutex);
  213 +
200 214 auto dec = decoderMap.find(name);
201 215 if (dec != decoderMap.end())
202 216 {
... ... @@ -204,7 +218,7 @@ bool FFNvDecoderManager::resumeDecoder(const string name)
204 218 return true;
205 219 }
206 220  
207   - cout << "没有找到name为" << name << "的解码器!" << endl;
  221 + av_log(NULL, AV_LOG_ERROR, "没有找到name为 %s 的解码器! \n", name.c_str());
208 222 return false;
209 223 }
210 224  
... ... @@ -217,17 +231,57 @@ bool FFNvDecoderManager::isSurport(FFDecConfig&amp; cfg)
217 231 bool FFNvDecoderManager::isRunning(const string name){
218 232 if (name.empty())
219 233 {
220   - cout << "name 为空!"<< endl;
  234 + av_log(NULL, AV_LOG_ERROR, "name 为空! \n");
221 235 return false;
222 236 }
223 237  
  238 + std::lock_guard<std::mutex> l(m_mutex);
  239 +
224 240 auto dec = decoderMap.find(name);
225 241 if (dec != decoderMap.end())
226 242 {
227 243 return dec->second->isRunning();
228 244 }
229 245  
230   - cout << "没有找到name为" << name << "的解码器!" << endl;
  246 + av_log(NULL, AV_LOG_ERROR, "没有找到name为 %s 的解码器! \n", name.c_str());
  247 + return false;
  248 +}
  249 +
  250 +bool FFNvDecoderManager::isFinished(const string name){
  251 + if (name.empty())
  252 + {
  253 + av_log(NULL, AV_LOG_ERROR, "name 为空! \n");
  254 + return false;
  255 + }
  256 +
  257 + std::lock_guard<std::mutex> l(m_mutex);
  258 +
  259 + auto dec = decoderMap.find(name);
  260 + if (dec != decoderMap.end())
  261 + {
  262 + return dec->second->isFinished();
  263 + }
  264 +
  265 + av_log(NULL, AV_LOG_ERROR, "没有找到name为 %s 的解码器! \n", name.c_str());
  266 + return false;
  267 +}
  268 +
  269 +bool FFNvDecoderManager::isPausing(const string name){
  270 + if (name.empty())
  271 + {
  272 + av_log(NULL, AV_LOG_ERROR, "name 为空! \n");
  273 + return false;
  274 + }
  275 +
  276 + std::lock_guard<std::mutex> l(m_mutex);
  277 +
  278 + auto dec = decoderMap.find(name);
  279 + if (dec != decoderMap.end())
  280 + {
  281 + return dec->second->isPausing();
  282 + }
  283 +
  284 + av_log(NULL, AV_LOG_ERROR, "没有找到name为 %s 的解码器! \n", name.c_str());
231 285 return false;
232 286 }
233 287  
... ... @@ -235,10 +289,12 @@ bool FFNvDecoderManager::setDecKeyframe(const string name, bool bKeyframe)
235 289 {
236 290 if (name.empty())
237 291 {
238   - cout << "name 为空!"<< endl;
  292 + av_log(NULL, AV_LOG_ERROR, "name 为空! \n");
239 293 return false;
240 294 }
241 295  
  296 + std::lock_guard<std::mutex> l(m_mutex);
  297 +
242 298 auto dec = decoderMap.find(name);
243 299 if (dec != decoderMap.end())
244 300 {
... ... @@ -246,6 +302,65 @@ bool FFNvDecoderManager::setDecKeyframe(const string name, bool bKeyframe)
246 302 return true;
247 303 }
248 304  
249   - cout << "没有找到name为" << name << "的解码器!" << endl;
  305 + av_log(NULL, AV_LOG_ERROR, "没有找到name为 %s 的解码器! \n", name.c_str());
  306 + return false;
  307 +}
  308 +
  309 +bool FFNvDecoderManager::getResolution(const string name, int &width, int &height)
  310 +{
  311 + if (name.empty())
  312 + {
  313 + av_log(NULL, AV_LOG_ERROR, "name 为空! \n");
  314 + return false;
  315 + }
  316 +
  317 + std::lock_guard<std::mutex> l(m_mutex);
  318 +
  319 + auto dec = decoderMap.find(name);
  320 + if (dec != decoderMap.end())
  321 + {
  322 + dec->second->getResolution(width, height);
  323 + return true;
  324 + }
  325 +
  326 + av_log(NULL, AV_LOG_ERROR, "没有找到name为 %s 的解码器! \n", name.c_str());
250 327 return false;
  328 +}
  329 +
  330 +vector<string> FFNvDecoderManager::getAllDecodeName(){
  331 +
  332 + closeAllFinishedDecoder();
  333 +
  334 + std::lock_guard<std::mutex> l(m_mutex);
  335 +
  336 + vector<string> decode_names;
  337 + for(auto it = decoderMap.begin(); it != decoderMap.end(); ++it){
  338 + decode_names.push_back(it->first);
  339 + }
  340 + return decode_names;
  341 +}
  342 +
  343 +int FFNvDecoderManager::getCachedQueueLength(const string name){
  344 + if (name.empty()){
  345 + av_log(NULL, AV_LOG_ERROR, "name 为空! \n");
  346 + return -1;
  347 + }
  348 +
  349 + std::lock_guard<std::mutex> l(m_mutex);
  350 +
  351 + auto dec = decoderMap.find(name);
  352 + if (dec != decoderMap.end()){
  353 + return dec->second->getCachedQueueLength();
  354 + }
  355 +
  356 + av_log(NULL, AV_LOG_ERROR, "没有找到name为 %s 的解码器! \n", name.c_str());
  357 + return -1;
  358 +}
  359 +
  360 +FFImgInfo* FFNvDecoderManager::snapshot(const string& uri){
  361 + return FFNvDecoder::snapshot(uri);
  362 +}
  363 +
  364 +void FFNvDecoderManager::releaseFFImgInfo(FFImgInfo* info){
  365 + FFNvDecoder::releaseFFImgInfo(info);
251 366 }
252 367 \ No newline at end of file
... ...
src/FFNvDecoderManager.h
... ... @@ -45,7 +45,7 @@ public:
45 45 * 返回:成功返回解码器, 失败返回 nullptr
46 46 * 备注:
47 47 **************************************************/
48   - FFNvDecoder* createDecoder(MgrDecConfig& config);
  48 + FFNvDecoder* createDecoder(MgrDecConfig config);
49 49  
50 50 /**************************************************
51 51 * 接口:setUserPtr
... ... @@ -111,6 +111,15 @@ public:
111 111 **************************************************/
112 112 void closeAllDecoder();
113 113  
  114 + /**************************************************
  115 + * 接口:closeAllDecoderByGpuid
  116 + * 功能:关闭某张显卡撒花姑娘的全部解码器
  117 + * 参数:const string gpuid gpu的id
  118 + * 返回:void
  119 + * 备注:
  120 + **************************************************/
  121 + void closeAllDecoderByGpuid(const string gpuid);
  122 +
114 123 /**************************************************
115 124 * 接口:pauseDecoder
116 125 * 功能:暂停指定名称的解码器
... ... @@ -147,6 +156,24 @@ public:
147 156 **************************************************/
148 157 bool isRunning(const string name);
149 158  
  159 + /**************************************************
  160 + * 接口:isFinished
  161 + * 功能:根据解码器名称判断解码器是否已经结束
  162 + * 参数:const string name 解码器名称
  163 + * 返回:正在运行返回true,否则返回false
  164 + * 备注:
  165 + **************************************************/
  166 + bool isFinished(const string name);
  167 +
  168 + /**************************************************
  169 + * 接口:isPausing
  170 + * 功能:根据解码器名称判断解码器是否暂停
  171 + * 参数:const string name 解码器名称
  172 + * 返回:正在运行返回true,否则返回false
  173 + * 备注:
  174 + **************************************************/
  175 + bool isPausing(const string name);
  176 +
150 177 /**************************************************
151 178 * 接口:count
152 179 * 功能:获取正在运行的解码器数量
... ... @@ -161,11 +188,58 @@ public:
161 188 * 功能:设置是否只解码关键帧。默认全解
162 189 * 参数:const string name 解码器名称
163 190 * bool bKeyframe 是否只解码关键帧。true,只解码关键帧;false,普通的全解码
164   - * 返回:void
  191 + * 返回:bool 成功返回true,失败返回false
165 192 * 备注:
166 193 **************************************************/
167 194 bool setDecKeyframe(const string name, bool bKeyframe);
168 195  
  196 + /**************************************************
  197 + * 接口:getResolution
  198 + * 功能:获取视频分辨率
  199 + * 参数:const string name 解码器名称
  200 + * int &width 从 width 返回视频宽度
  201 + * int &height 从 height 返回视频高度
  202 + * 返回:bool 成功获取返回true,失败返回false
  203 + * 备注:
  204 + **************************************************/
  205 + bool getResolution(const string name, int &width, int &height);
  206 +
  207 + /**************************************************
  208 + * 接口:getAllDecodeName
  209 + * 功能:获取全部解码器名称
  210 + * 参数:void
  211 + * 返回:vector<string> 返回全部解码器名称
  212 + * 备注:
  213 + **************************************************/
  214 + vector<string> getAllDecodeName();
  215 +
  216 + /**************************************************
  217 + * 接口:getCachedQueueLength
  218 + * 功能:获取解码缓冲队列当前长度
  219 + * 参数:const string name 解码器名称
  220 + * 返回:int 解码缓冲队列当前长度
  221 + * 备注:
  222 + **************************************************/
  223 + int getCachedQueueLength(const string name);
  224 +
  225 + /**************************************************
  226 + * 接口:snapshot
  227 + * 功能:获取视频快照
  228 + * 参数:const string& uri 视频地址
  229 + * 返回:FFImgInfo* 快照信息
  230 + * 备注:
  231 + **************************************************/
  232 + FFImgInfo* snapshot(const string& uri);
  233 +
  234 + /**************************************************
  235 + * 接口:releaseFFImgInfo
  236 + * 功能:释放视频快照信息
  237 + * 参数:FFImgInfo* info 视频快照信息
  238 + * 返回:void
  239 + * 备注:
  240 + **************************************************/
  241 + void releaseFFImgInfo(FFImgInfo* info);
  242 +
169 243 private:
170 244 FFNvDecoderManager(){}
171 245  
... ... @@ -174,5 +248,5 @@ private:
174 248 private:
175 249 map<string, FFNvDecoder*> decoderMap;
176 250  
177   - mutex m_mutex_erase;
  251 + mutex m_mutex;
178 252 };
179 253 \ No newline at end of file
... ...
src/Makefile
... ... @@ -2,14 +2,11 @@
2 2 XX = g++
3 3 NVCC = nvcc
4 4  
5   -
6   -DEFS= -DPOST_USE_RABBITMQ
7   -
8   -PROJECT_ROOT= /home/cmhu/FFNvDecoder
  5 +PROJECT_ROOT= /mnt/e/fiss/FFNvDecoder
9 6  
10 7 DEPEND_DIR = $(PROJECT_ROOT)/bin
11 8 SRC_ROOT = $(PROJECT_ROOT)/src
12   -CUDA_ROOT = /usr/local/cuda-11.7
  9 +CUDA_ROOT = /usr/local/cuda
13 10  
14 11 TARGET= $(DEPEND_DIR)/lib/test
15 12  
... ... @@ -21,12 +18,13 @@ INCLUDE= -I $(DEPEND_DIR)/include \
21 18 -I $(SRC_ROOT)\
22 19  
23 20 LIBSPATH= -L $(DEPEND_DIR)/lib -lavformat -lavcodec -lswscale -lavutil -lavfilter -lswresample -lavdevice \
24   - -L $(CUDA_ROOT)/lib64 -lcuda -lcudart -lnvcuvid -lcurand -lcublas -lnvjpeg \
  21 + -L $(CUDA_ROOT)/lib64 -lcudart -lcurand -lcublas -lnvjpeg \
  22 + -L /usr/lib/wsl/lib -lcuda -lnvcuvid\
25 23  
26   -CFLAGS= -g -fPIC -O0 $(DEFS) $(INCLUDE) -pthread -lrt -lz -std=c++11 -fvisibility=hidden -Wl,-Bsymbolic -ldl
  24 +CFLAGS= -g -fPIC -O0 $(INCLUDE) -pthread -lrt -lz -std=c++11 -fvisibility=hidden -Wl,-Bsymbolic -ldl
27 25 # -DUNICODE -D_UNICODE
28 26  
29   -NFLAGS_LIB=-g -c $(DEFS) -shared -Xcompiler -fPIC -Xcompiler -fvisibility=hidden
  27 +NFLAGS_LIB=-g -c -shared -Xcompiler -fPIC -Xcompiler -fvisibility=hidden
30 28 NFLAGS = $(NFLAGS_LIB) $(INCLUDE) -std=c++11
31 29  
32 30 SRCS:=$(wildcard $(SRC_ROOT)/*.cpp)
... ...
src/common/inc/helper_cuda_drvapi.h
... ... @@ -218,7 +218,8 @@ inline int gpuGetMaxGflopsDeviceIdDRV()
218 218 // Find the best major SM Architecture GPU device
219 219 while (current_device < device_count)
220 220 {
221   - checkCudaErrors(cuDeviceComputeCapability(&major, &minor, current_device));
  221 + checkCudaErrors(cuDeviceGetAttribute(&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, current_device));
  222 + checkCudaErrors(cuDeviceGetAttribute(&minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, current_device));
222 223  
223 224 if (major > 0 && major < 9999)
224 225 {
... ... @@ -239,7 +240,9 @@ inline int gpuGetMaxGflopsDeviceIdDRV()
239 240 checkCudaErrors(cuDeviceGetAttribute(&clockRate,
240 241 CU_DEVICE_ATTRIBUTE_CLOCK_RATE,
241 242 current_device));
242   - checkCudaErrors(cuDeviceComputeCapability(&major, &minor, current_device));
  243 +
  244 + checkCudaErrors(cuDeviceGetAttribute(&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, current_device));
  245 + checkCudaErrors(cuDeviceGetAttribute(&minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, current_device));
243 246  
244 247 int computeMode;
245 248 getCudaAttribute<int>(&computeMode, CU_DEVICE_ATTRIBUTE_COMPUTE_MODE, current_device);
... ... @@ -317,7 +320,9 @@ inline int gpuGetMaxGflopsGLDeviceIdDRV()
317 320 while (current_device < device_count)
318 321 {
319 322 checkCudaErrors(cuDeviceGetName(deviceName, 256, current_device));
320   - checkCudaErrors(cuDeviceComputeCapability(&major, &minor, current_device));
  323 +
  324 + checkCudaErrors(cuDeviceGetAttribute(&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, current_device));
  325 + checkCudaErrors(cuDeviceGetAttribute(&minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, current_device));
321 326  
322 327 #if CUDA_VERSION >= 3020
323 328 checkCudaErrors(cuDeviceGetAttribute(&bTCC, CU_DEVICE_ATTRIBUTE_TCC_DRIVER, current_device));
... ... @@ -369,7 +374,9 @@ inline int gpuGetMaxGflopsGLDeviceIdDRV()
369 374 checkCudaErrors(cuDeviceGetAttribute(&clockRate,
370 375 CU_DEVICE_ATTRIBUTE_CLOCK_RATE,
371 376 current_device));
372   - checkCudaErrors(cuDeviceComputeCapability(&major, &minor, current_device));
  377 +
  378 + checkCudaErrors(cuDeviceGetAttribute(&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, current_device));
  379 + checkCudaErrors(cuDeviceGetAttribute(&minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, current_device));
373 380  
374 381 #if CUDA_VERSION >= 3020
375 382 checkCudaErrors(cuDeviceGetAttribute(&bTCC, CU_DEVICE_ATTRIBUTE_TCC_DRIVER, current_device));
... ... @@ -500,7 +507,9 @@ inline bool checkCudaCapabilitiesDRV(int major_version, int minor_version, int d
500 507  
501 508 checkCudaErrors(cuDeviceGet(&cuDevice, devID));
502 509 checkCudaErrors(cuDeviceGetName(name, 100, cuDevice));
503   - checkCudaErrors(cuDeviceComputeCapability(&major, &minor, devID));
  510 +
  511 + checkCudaErrors(cuDeviceGetAttribute(&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, devID));
  512 + checkCudaErrors(cuDeviceGetAttribute(&minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, devID));
504 513  
505 514 if ((major > major_version) ||
506 515 (major == major_version && minor >= minor_version))
... ...
src/main.cpp
... ... @@ -54,7 +54,7 @@ void postDecoded(const void * userPtr, AVFrame * gpuFrame){
54 54 return;
55 55 }
56 56  
57   - string path = "/home/cmhu/data/" + decoder->getName() + "/" + to_string(sum) + ".jpg";
  57 + string path = "/mnt/f/fiss/data/" + decoder->getName() + "/" + to_string(sum) + ".jpg";
58 58 saveJpeg(path.c_str(), pHwRgb[0], gpuFrame->width, gpuFrame->height, stream[0]); // 验证 CUDAToRGB
59 59 }
60 60 } else if (decoder->getName() == "dec2")
... ... @@ -79,7 +79,7 @@ void postDecoded(const void * userPtr, AVFrame * gpuFrame){
79 79 return;
80 80 }
81 81  
82   - string path = "/home/cmhu/data/" + decoder->getName() + "/" + to_string(sum) + ".jpg";
  82 + string path = "/mnt/f/fiss/data/" + decoder->getName() + "/" + to_string(sum) + ".jpg";
83 83 saveJpeg(path.c_str(), pHwRgb[1], gpuFrame->width, gpuFrame->height, stream[1]); // 验证 CUDAToRGB
84 84 }
85 85 }
... ... @@ -94,14 +94,10 @@ int count_std = 100;
94 94  
95 95 static long long get_cur_time(){
96 96 // 获取操作系统当前时间点(精确到微秒)
97   - chrono::time_point<chrono::system_clock, chrono::microseconds> tpMicro
98   - = chrono::time_point_cast<chrono::microseconds>(chrono::system_clock::now());
  97 + chrono::time_point<chrono::system_clock, chrono::milliseconds> tpMicro
  98 + = chrono::time_point_cast<chrono::milliseconds>(chrono::system_clock::now());
99 99 // (微秒精度的)时间点 => (微秒精度的)时间戳
100   - time_t totalMicroSeconds = tpMicro.time_since_epoch().count();
101   -
102   - long long currentTime = ((long long)totalMicroSeconds)/1000;
103   -
104   - return currentTime;
  100 + return tpMicro.time_since_epoch().count();
105 101 }
106 102  
107 103 static int sum = 0;
... ... @@ -124,47 +120,52 @@ void postDecoded0(const void * userPtr, AVFrame * gpuFrame){
124 120 }
125 121 count++;
126 122 sum ++ ;
127   - // if (count >= count_std)
128   - // {
129   - // // end_time = get_cur_time();
130   - // // long time_using = end_time - start_time;
131   - // // double time_per_frame = double(time_using)/count_std ;
132   - // // cout << count_std << "帧用时:" << time_using << "ms 每帧用时:" << time_per_frame << "ms" << endl;
133   - // cout << "keyframe: " << gpuFrame->key_frame << " width: " << gpuFrame->width << " height: "<< gpuFrame->height << endl;
134   - // cout << gpuFrame->pts << endl;
135   -
136   - // count_flag = false;
137   - // }
138   - // cout << "帧数:" << sum << endl;
139   -
140   - // if (gpuFrame->format == AV_PIX_FMT_CUDA)
141   - // {
142   - // cudaSetDevice(atoi(decoder->m_cfg.gpuid.c_str()));
143   - // // cout << "gpu id : " << decoder->m_cfg.gpuid.c_str() << endl;
144   - // cudaError_t cudaStatus;
145   - // if(pHwData == nullptr){
146   - // cuda_common::setColorSpace2( ITU709, 0 );
147   - // cudaStatus = cudaMalloc((void **)&pHwData, 3 * gpuFrame->width * gpuFrame->height * sizeof(unsigned char));
148   - // }
149   - // cudaStatus = cuda_common::CUDAToBGR((CUdeviceptr)gpuFrame->data[0],(CUdeviceptr)gpuFrame->data[1], gpuFrame->linesize[0], gpuFrame->linesize[1], pHwData, gpuFrame->width, gpuFrame->height);
150   - // cudaDeviceSynchronize();
151   - // if (cudaStatus != cudaSuccess) {
152   - // cout << "CUDAToBGR failed !!!" << endl;
153   - // return;
154   - // }
155   -
156   - // string path = "/home/cmhu/data/test/" + to_string(sum) + ".jpg";
157   - // saveJpeg(path.c_str(), pHwData, gpuFrame->width, gpuFrame->height, nullptr); // 验证 CUDAToRGB
158   - // }
  123 + if (count >= count_std)
  124 + {
  125 + // end_time = get_cur_time();
  126 + // long time_using = end_time - start_time;
  127 + // double time_per_frame = double(time_using)/count_std ;
  128 + // cout << count_std << "帧用时:" << time_using << "ms 每帧用时:" << time_per_frame << "ms" << endl;
  129 + cout << "keyframe: " << gpuFrame->key_frame << " width: " << gpuFrame->width << " height: "<< gpuFrame->height << endl;
  130 + cout << gpuFrame->pts << endl;
  131 +
  132 + count_flag = false;
  133 + }
  134 + cout << "帧数:" << sum << endl;
  135 +
  136 + if (gpuFrame->format == AV_PIX_FMT_CUDA)
  137 + {
  138 + cudaSetDevice(atoi(decoder->m_cfg.gpuid.c_str()));
  139 + // cout << "gpu id : " << decoder->m_cfg.gpuid.c_str() << endl;
  140 + cudaError_t cudaStatus;
  141 + if(pHwData == nullptr){
  142 + cuda_common::setColorSpace2( ITU709, 0 );
  143 + cudaStatus = cudaMalloc((void **)&pHwData, 3 * gpuFrame->width * gpuFrame->height * sizeof(unsigned char));
  144 + }
  145 + cudaStatus = cuda_common::CUDAToBGR((CUdeviceptr)gpuFrame->data[0],(CUdeviceptr)gpuFrame->data[1], gpuFrame->linesize[0], gpuFrame->linesize[1], pHwData, gpuFrame->width, gpuFrame->height);
  146 + cudaDeviceSynchronize();
  147 + if (cudaStatus != cudaSuccess) {
  148 + cout << "CUDAToBGR failed !!!" << endl;
  149 + return;
  150 + }
  151 +
  152 + string path = "/mnt/f/fiss/data/" + to_string(sum) + ".jpg";
  153 + saveJpeg(path.c_str(), pHwData, gpuFrame->width, gpuFrame->height, nullptr); // 验证 CUDAToRGB
  154 + }
159 155 }
160 156 }
161 157 }
162 158  
  159 +void decode_finished_cbk(const void* userPtr){
  160 + cout << "decode_finish timestamp: " << get_cur_time() << endl;
  161 +}
  162 +
163 163 // string test_uri = "rtmp://192.168.10.56:1935/objecteye/1";
164 164 // string test_uri = "/home/cmhu/data/output_800x480.mp4";
165 165 // string test_uri = "/home/cmhu/data/output_1920x1080.mp4";
166 166 // string test_uri = "rtsp://176.10.0.2:8554/stream";
167   -string test_uri = "/home/cmhu/data2/Street.uvf";
  167 +// string test_uri = "/mnt/f/fiss/test_data/h265.mp4";
  168 +string test_uri = "rtsp://176.10.0.4:8554/stream";
168 169  
169 170 void createDecode(int index){
170 171 FFNvDecoderManager* pDecManager = FFNvDecoderManager::getInstance();
... ... @@ -172,15 +173,16 @@ void createDecode(int index){
172 173 config.name = "dec" + to_string(index);
173 174 config.cfg.uri = test_uri;
174 175 config.cfg.post_decoded_cbk = postDecoded;
  176 + config.cfg.decode_finished_cbk = decode_finished_cbk;
175 177 config.cfg.force_tcp = true;
176 178  
177 179 if (index % 2 == 0)
178 180 {
179   - config.cfg.gpuid = "2";
  181 + config.cfg.gpuid = "0";
180 182 }
181 183 else
182 184 {
183   - config.cfg.gpuid = "1";
  185 + config.cfg.gpuid = "0";
184 186 }
185 187  
186 188 FFNvDecoder* decoder = pDecManager->createDecoder(config);
... ... @@ -207,7 +209,10 @@ int CheckCUDAProperty( int devId )
207 209 int major = 0, minor = 0;
208 210 CUresult rlt = CUDA_SUCCESS;
209 211  
210   - rlt = cuDeviceComputeCapability( &major, &minor, dev );
  212 + rlt = cuDeviceGetAttribute(&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, dev);
  213 + checkCudaErrors( rlt );
  214 +
  215 + rlt = cuDeviceGetAttribute(&minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, dev);
211 216 checkCudaErrors( rlt );
212 217  
213 218 rlt = cuDeviceGetName( devName, sizeof( devName ), dev );
... ... @@ -225,9 +230,17 @@ int CheckCUDAProperty( int devId )
225 230 return 0;
226 231 }
227 232  
  233 +void logFF(void *, int level, const char *fmt, va_list ap)
  234 +{
  235 + vfprintf(stdout, fmt, ap);
  236 +}
  237 +
  238 +
228 239 int main(){
229 240  
230   - CheckCUDAProperty(1);
  241 + // av_log_set_callback(&logFF);
  242 +
  243 + CheckCUDAProperty(0);
231 244  
232 245 FFNvDecoderManager* pDecManager = FFNvDecoderManager::getInstance();
233 246  
... ... @@ -241,17 +254,22 @@ int main(){
241 254 config.name = "dec";
242 255 config.cfg.uri = test_uri;
243 256 config.cfg.post_decoded_cbk = postDecoded0;
  257 + config.cfg.decode_finished_cbk = decode_finished_cbk;
244 258 config.cfg.force_tcp = true;
245   - config.cfg.gpuid = "2";
  259 + config.cfg.gpuid = "0";
246 260 FFNvDecoder* dec2 = pDecManager->createDecoder(config);
247 261 if (!dec2)
248 262 {
249 263 return 1;
250 264 }
251 265 pDecManager->setUserPtr(config.name, dec2);
252   - pDecManager->setDecKeyframe(config.name, true);
  266 + // pDecManager->setDecKeyframe(config.name, true);
253 267 pDecManager->startDecodeByName(config.name);
254 268  
  269 + int w,h;
  270 + pDecManager->getResolution(config.name, w,h);
  271 + printf( "%s : %dx%d\n", config.name.c_str() , w,h );
  272 +
255 273 pthread_t m_decode_thread;
256 274 pthread_create(&m_decode_thread,0,
257 275 [](void* arg)
... ...