Commit 3c7e3e11e19bf471a835a17f40ae895783bbf6ab

Authored by Hu Chunming
1 parent 0a826b3d

1.修改日志

2.添加DECODE_FINISHED_CALLBACK
3.添加isPausing接口
4.添加getCachedQueueLength接口
5.添加snapshot和releaseFFImgInfo接口
6.测试代码添加log回调的自定义设置
src/FFNvDecoder.cpp
1 #include "FFNvDecoder.h" 1 #include "FFNvDecoder.h"
2 -#include<iostream>  
3 2
4 #include <chrono> 3 #include <chrono>
5 #include <thread> 4 #include <thread>
@@ -24,7 +23,7 @@ static AVPixelFormat get_hw_format(AVCodecContext *avctx, const AVPixelFormat *p @@ -24,7 +23,7 @@ static AVPixelFormat get_hw_format(AVCodecContext *avctx, const AVPixelFormat *p
24 return *p; 23 return *p;
25 } 24 }
26 25
27 - //cout << "Failed to get HW surface format"; 26 + av_log(NULL, AV_LOG_ERROR, "Failed to get HW surface format. \n");
28 return AV_PIX_FMT_NONE; 27 return AV_PIX_FMT_NONE;
29 } 28 }
30 29
@@ -86,13 +85,13 @@ bool FFNvDecoder::init(const char* uri, const char* gpuid, bool force_tcp) @@ -86,13 +85,13 @@ bool FFNvDecoder::init(const char* uri, const char* gpuid, bool force_tcp)
86 fmt_ctx = avformat_alloc_context(); 85 fmt_ctx = avformat_alloc_context();
87 const char* input_file = uri; 86 const char* input_file = uri;
88 if (avformat_open_input(&fmt_ctx, input_file, nullptr, &options) != 0) { 87 if (avformat_open_input(&fmt_ctx, input_file, nullptr, &options) != 0) {
89 - cout << "Cannot open input file: " << input_file; 88 + av_log(NULL, AV_LOG_ERROR, "Cannot open input file: %s \n", input_file);
90 return false; 89 return false;
91 } 90 }
92 91
93 // 查找流信息 92 // 查找流信息
94 if (avformat_find_stream_info(fmt_ctx, nullptr) < 0) { 93 if (avformat_find_stream_info(fmt_ctx, nullptr) < 0) {
95 - cout << "Cannot find input stream information"; 94 + av_log(NULL, AV_LOG_ERROR, "Cannot find input stream information ! \n");
96 return false; 95 return false;
97 } 96 }
98 97
@@ -100,7 +99,7 @@ bool FFNvDecoder::init(const char* uri, const char* gpuid, bool force_tcp) @@ -100,7 +99,7 @@ bool FFNvDecoder::init(const char* uri, const char* gpuid, bool force_tcp)
100 AVCodec *decoder = nullptr; 99 AVCodec *decoder = nullptr;
101 stream_index = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &decoder, 0); 100 stream_index = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &decoder, 0);
102 if (stream_index < 0) { 101 if (stream_index < 0) {
103 - cout << "Cannot find a video stream in the input file"; 102 + av_log(NULL, AV_LOG_ERROR, "Cannot find a video stream in the input file ! \n");
104 return false; 103 return false;
105 } 104 }
106 105
@@ -130,9 +129,9 @@ bool FFNvDecoder::init(const char* uri, const char* gpuid, bool force_tcp) @@ -130,9 +129,9 @@ bool FFNvDecoder::init(const char* uri, const char* gpuid, bool force_tcp)
130 // 打开解码器流 129 // 打开解码器流
131 AVDictionary *op = nullptr; 130 AVDictionary *op = nullptr;
132 av_dict_set( &op, "gpu", gpuid, 0 ); 131 av_dict_set( &op, "gpu", gpuid, 0 );
133 - // av_dict_set( &op, "surfaces", "3", 0 ); 132 + av_dict_set( &op, "surfaces", "10", 0 );
134 if (avcodec_open2(avctx, vcodec, &op) < 0) { 133 if (avcodec_open2(avctx, vcodec, &op) < 0) {
135 - cout << "Failed to open codec for stream" << stream_index; 134 + av_log(NULL, AV_LOG_ERROR, "Failed to open codec for stream ! \n");
136 return false; 135 return false;
137 } 136 }
138 137
@@ -208,14 +207,9 @@ void FFNvDecoder::decode_thread() @@ -208,14 +207,9 @@ void FFNvDecoder::decode_thread()
208 } 207 }
209 208
210 int result = av_read_frame(fmt_ctx, pkt); 209 int result = av_read_frame(fmt_ctx, pkt);
211 - if (result == AVERROR_EOF) 210 + if (result == AVERROR_EOF || result < 0)
212 { 211 {
213 - cout << "Failed to read frame!" << endl;  
214 - break;  
215 - }  
216 - if (result < 0)  
217 - {  
218 - cout << "Failed to read frame!" << endl; 212 + av_log(NULL, AV_LOG_ERROR, "Failed to read frame! \n");
219 break; 213 break;
220 } 214 }
221 215
@@ -234,19 +228,16 @@ void FFNvDecoder::decode_thread() @@ -234,19 +228,16 @@ void FFNvDecoder::decode_thread()
234 } 228 }
235 } 229 }
236 230
237 - if (stream_index == pkt->stream_index)  
238 - { 231 + if (stream_index == pkt->stream_index){
239 result = avcodec_send_packet(avctx, pkt); 232 result = avcodec_send_packet(avctx, pkt);
240 - if (result < 0)  
241 - {  
242 - cout << "Failed to send pkt:" << result << endl; 233 + if (result < 0){
  234 + av_log(NULL, AV_LOG_ERROR, "Failed to send pkt: %d \n",result);
243 continue; 235 continue;
244 } 236 }
245 237
246 result = avcodec_receive_frame(avctx, gpuFrame); 238 result = avcodec_receive_frame(avctx, gpuFrame);
247 - if (result == AVERROR(EAGAIN) || result == AVERROR_EOF || result < 0)  
248 - {  
249 - cout << "Failed to receive frame"<< endl; 239 + if ((result == AVERROR(EAGAIN) || result == AVERROR_EOF) || result < 0){
  240 + av_log(NULL, AV_LOG_ERROR, "Failed to receive frame: %d \n",result);
250 continue; 241 continue;
251 } 242 }
252 243
@@ -255,6 +246,14 @@ void FFNvDecoder::decode_thread() @@ -255,6 +246,14 @@ void FFNvDecoder::decode_thread()
255 av_packet_unref(pkt); 246 av_packet_unref(pkt);
256 } 247 }
257 248
  249 + // 队列中没有数据了再结束
  250 + while (mFrameQueue.length() > 0){
  251 + if(!m_bRunning){
  252 + break;
  253 + }
  254 + std::this_thread::sleep_for(std::chrono::milliseconds(10));
  255 + }
  256 +
258 m_bRunning = false; 257 m_bRunning = false;
259 258
260 // long end_time = get_cur_time(); 259 // long end_time = get_cur_time();
@@ -266,9 +265,11 @@ void FFNvDecoder::decode_thread() @@ -266,9 +265,11 @@ void FFNvDecoder::decode_thread()
266 pthread_join(m_post_decode_thread,0); 265 pthread_join(m_post_decode_thread,0);
267 } 266 }
268 267
  268 + decode_finished_cbk(m_userPtr);
  269 +
269 decode_finished(); 270 decode_finished();
270 271
271 - cout << "decode thread exited." << endl; 272 + av_log(NULL, AV_LOG_INFO, "decode thread exited. \n");
272 } 273 }
273 274
274 void FFNvDecoder::decode_finished() 275 void FFNvDecoder::decode_finished()
@@ -289,7 +290,7 @@ void FFNvDecoder::decode_finished() @@ -289,7 +290,7 @@ void FFNvDecoder::decode_finished()
289 290
290 void FFNvDecoder::post_decode_thread() 291 void FFNvDecoder::post_decode_thread()
291 { 292 {
292 - while (m_bRunning) 293 + while (m_bRunning || mFrameQueue.length() > 0)
293 { 294 {
294 AVFrame * gpuFrame = mFrameQueue.getHead(); 295 AVFrame * gpuFrame = mFrameQueue.getHead();
295 if (gpuFrame == nullptr) 296 if (gpuFrame == nullptr)
@@ -302,8 +303,8 @@ void FFNvDecoder::post_decode_thread() @@ -302,8 +303,8 @@ void FFNvDecoder::post_decode_thread()
302 303
303 mFrameQueue.addHead(); 304 mFrameQueue.addHead();
304 } 305 }
305 -  
306 - cout << "post decode thread exited." << endl; 306 +
  307 + av_log(NULL, AV_LOG_INFO, "post decode thread exited. \n");
307 } 308 }
308 309
309 void FFNvDecoder::close() 310 void FFNvDecoder::close()
@@ -338,6 +339,10 @@ bool FFNvDecoder::isFinished() @@ -338,6 +339,10 @@ bool FFNvDecoder::isFinished()
338 return m_bFinished; 339 return m_bFinished;
339 } 340 }
340 341
  342 +bool FFNvDecoder::isPausing(){
  343 + return m_bPause;
  344 +}
  345 +
341 bool FFNvDecoder::getResolution( int &width, int &height ) 346 bool FFNvDecoder::getResolution( int &width, int &height )
342 { 347 {
343 if (avctx != nullptr) 348 if (avctx != nullptr)
@@ -363,4 +368,135 @@ void FFNvDecoder::resume() @@ -363,4 +368,135 @@ void FFNvDecoder::resume()
363 void FFNvDecoder::setDecKeyframe(bool bKeyframe) 368 void FFNvDecoder::setDecKeyframe(bool bKeyframe)
364 { 369 {
365 m_dec_keyframe = bKeyframe; 370 m_dec_keyframe = bKeyframe;
  371 +}
  372 +
  373 +int FFNvDecoder::getCachedQueueLength(){
  374 + return mFrameQueue.length();
  375 +}
  376 +
  377 +FFImgInfo* FFNvDecoder::snapshot(const string& uri){
  378 +
  379 + AVFormatContext* ifmt_ctx = NULL;
  380 + AVCodecContext* codec_ctx = nullptr;
  381 + AVCodec* codec = nullptr;
  382 + AVPacket* pkt = nullptr;
  383 + AVFrame *frame = nullptr;
  384 + AVFrame *pFrameRGB = nullptr;
  385 + int video_index = -1;
  386 + AVStream* st = nullptr;
  387 + SwsContext *img_convert_ctx = nullptr;
  388 + uint8_t *buffer = NULL;
  389 + int numBytes = 0;
  390 +
  391 + FFImgInfo* imgInfo = nullptr;
  392 +
  393 + //av_register_all();
  394 + avformat_network_init();
  395 +
  396 + ///打开输入的流
  397 + int ret = avformat_open_input(&ifmt_ctx, uri.c_str(), NULL, NULL);
  398 + if (ret != 0){
  399 + av_log(NULL, AV_LOG_ERROR, "Couldn't open input stream ! \n");
  400 + goto end_flag ;
  401 + }
  402 +
  403 + //查找流信息
  404 + if (avformat_find_stream_info(ifmt_ctx, NULL) < 0){
  405 + av_log(NULL, AV_LOG_ERROR, "Couldn't find stream information ! \n");
  406 + goto end_flag ;
  407 + }
  408 +
  409 + //找到视频流索引
  410 + video_index = av_find_best_stream(ifmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
  411 +
  412 + st = ifmt_ctx->streams[video_index];
  413 +
  414 + //找到解码器
  415 + codec = avcodec_find_decoder(st->codecpar->codec_id);
  416 + if (!codec){
  417 + av_log(NULL, AV_LOG_ERROR, "Codec not found ! \n");
  418 + goto end_flag ;
  419 + }
  420 +
  421 + //申请AVCodecContext
  422 + codec_ctx = avcodec_alloc_context3(codec);
  423 + if (!codec_ctx){
  424 + goto end_flag ;
  425 + }
  426 +
  427 + avcodec_parameters_to_context(codec_ctx, ifmt_ctx->streams[video_index]->codecpar);
  428 +
  429 + //打开解码器
  430 + if ((ret = avcodec_open2(codec_ctx, codec, NULL) < 0)){
  431 + goto end_flag ;
  432 + }
  433 +
  434 + // 计算解码后原始数据所需缓冲区大小,并分配内存空间 Determine required buffer size and allocate buffer
  435 + numBytes = av_image_get_buffer_size(AV_PIX_FMT_RGB24, codec_ctx->width, codec_ctx->height, 1);
  436 + buffer = (uint8_t *)av_malloc(numBytes * sizeof(uint8_t));
  437 +
  438 + pFrameRGB = av_frame_alloc();
  439 + av_image_fill_arrays(pFrameRGB->data, pFrameRGB->linesize, buffer, AV_PIX_FMT_BGR24, codec_ctx->width, codec_ctx->height, 1);
  440 +
  441 + 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,
  442 + SWS_BICUBIC, NULL, NULL, NULL);
  443 +
  444 + pkt = av_packet_alloc();
  445 + frame = av_frame_alloc();
  446 + while (av_read_frame(ifmt_ctx, pkt) >= 0){
  447 + if (pkt->stream_index == video_index){
  448 + int ret = avcodec_send_packet(codec_ctx, pkt);
  449 + if (ret >= 0){
  450 + ret = avcodec_receive_frame(codec_ctx, frame);
  451 + if ((ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) || ret < 0){
  452 + av_log(NULL, AV_LOG_ERROR, "Failed to receive frame: %d \n", ret);
  453 + continue;
  454 + }
  455 +
  456 + sws_scale(img_convert_ctx, (const unsigned char* const*)frame->data, frame->linesize, 0, codec_ctx->height, pFrameRGB->data, pFrameRGB->linesize);
  457 +
  458 + imgInfo = new FFImgInfo();
  459 + imgInfo->pData = buffer;
  460 + imgInfo->height = codec_ctx->height;
  461 + imgInfo->width = codec_ctx->width;
  462 +
  463 + break;
  464 + }
  465 + }
  466 + }
  467 +
  468 +end_flag:
  469 + if (codec_ctx != nullptr){
  470 + avcodec_close(codec_ctx);
  471 + avcodec_free_context(&codec_ctx);
  472 + }
  473 +
  474 + if (ifmt_ctx != nullptr){
  475 + avformat_close_input(&ifmt_ctx);
  476 + }
  477 +
  478 + if (frame != nullptr){
  479 + av_frame_free(&frame);
  480 + }
  481 +
  482 + if (pFrameRGB != nullptr){
  483 + av_frame_free(&pFrameRGB);
  484 + }
  485 +
  486 + if (pkt != nullptr){
  487 + av_packet_free(&pkt);
  488 + }
  489 +
  490 + return imgInfo;
  491 +}
  492 +
  493 +void FFNvDecoder::releaseFFImgInfo(FFImgInfo* info){
  494 + if(nullptr != info){
  495 + if(info->pData != nullptr){
  496 + av_free(info->pData);
  497 + info->pData = nullptr;
  498 + }
  499 + delete info;
  500 + info = nullptr;
  501 + }
366 } 502 }
367 \ No newline at end of file 503 \ No newline at end of file
src/FFNvDecoder.h
@@ -12,6 +12,7 @@ extern &quot;C&quot; @@ -12,6 +12,7 @@ extern &quot;C&quot;
12 #include <libavutil/avutil.h> 12 #include <libavutil/avutil.h>
13 #include <libavutil/pixdesc.h> 13 #include <libavutil/pixdesc.h>
14 #include <libswscale/swscale.h> 14 #include <libswscale/swscale.h>
  15 + #include <libavutil/imgutils.h>
15 } 16 }
16 17
17 using namespace std; 18 using namespace std;
@@ -29,14 +30,22 @@ using namespace std; @@ -29,14 +30,22 @@ using namespace std;
29 **************************************************/ 30 **************************************************/
30 typedef void(*POST_DECODE_CALLBACK)(const void * userPtr, AVFrame * gpuFrame); 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 string uri; // 视频地址 36 string uri; // 视频地址
35 POST_DECODE_CALLBACK post_decoded_cbk; // 解码数据回调接口 37 POST_DECODE_CALLBACK post_decoded_cbk; // 解码数据回调接口
  38 + DECODE_FINISHED_CALLBACK decode_finished_cbk; // 解码线程结束后的回调接口
36 string gpuid; // gpu id 39 string gpuid; // gpu id
37 bool force_tcp{true}; // 是否指定使用tcp连接 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 class FFNvDecoder{ 49 class FFNvDecoder{
41 public: 50 public:
42 FFNvDecoder(); 51 FFNvDecoder();
@@ -51,6 +60,7 @@ public: @@ -51,6 +60,7 @@ public:
51 60
52 bool isRunning(); 61 bool isRunning();
53 bool isFinished(); 62 bool isFinished();
  63 + bool isPausing();
54 bool getResolution( int &width, int &height ); 64 bool getResolution( int &width, int &height );
55 65
56 void setName(string nm); 66 void setName(string nm);
@@ -58,6 +68,12 @@ public: @@ -58,6 +68,12 @@ public:
58 68
59 bool isSurport(FFDecConfig& cfg); 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 public: 77 public:
62 AVPixelFormat getHwPixFmt(); 78 AVPixelFormat getHwPixFmt();
63 79
@@ -69,6 +85,7 @@ private: @@ -69,6 +85,7 @@ private:
69 85
70 public: 86 public:
71 POST_DECODE_CALLBACK post_decoded_cbk; 87 POST_DECODE_CALLBACK post_decoded_cbk;
  88 + DECODE_FINISHED_CALLBACK decode_finished_cbk;
72 const void * m_userPtr; 89 const void * m_userPtr;
73 FFDecConfig m_cfg; 90 FFDecConfig m_cfg;
74 91
src/FFNvDecoderManager.cpp
1 #include "FFNvDecoderManager.h" 1 #include "FFNvDecoderManager.h"
2 -#include<iostream>  
3 2
4 using namespace std; 3 using namespace std;
5 4
6 5
7 -FFNvDecoder* FFNvDecoderManager::createDecoder(MgrDecConfig& config){ 6 +FFNvDecoder* FFNvDecoderManager::createDecoder(MgrDecConfig config){
8 7
9 closeAllFinishedDecoder(); 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 return nullptr; 15 return nullptr;
16 } 16 }
17 17
@@ -26,6 +26,7 @@ FFNvDecoder* FFNvDecoderManager::createDecoder(MgrDecConfig&amp; config){ @@ -26,6 +26,7 @@ FFNvDecoder* FFNvDecoderManager::createDecoder(MgrDecConfig&amp; config){
26 { 26 {
27 dec->setName(config.name) ; 27 dec->setName(config.name) ;
28 dec->post_decoded_cbk = config.cfg.post_decoded_cbk; 28 dec->post_decoded_cbk = config.cfg.post_decoded_cbk;
  29 + dec->decode_finished_cbk = config.cfg.decode_finished_cbk;
29 decoderMap[config.name] = dec; 30 decoderMap[config.name] = dec;
30 return dec; 31 return dec;
31 } 32 }
@@ -41,10 +42,12 @@ bool FFNvDecoderManager::setUserPtr(const string name, const void * userPtr) @@ -41,10 +42,12 @@ bool FFNvDecoderManager::setUserPtr(const string name, const void * userPtr)
41 { 42 {
42 if (name.empty()) 43 if (name.empty())
43 { 44 {
44 - cout << "name 为空!"<< endl; 45 + av_log(NULL, AV_LOG_ERROR, "name 为空! \n");
45 return false; 46 return false;
46 } 47 }
47 48
  49 + std::lock_guard<std::mutex> l(m_mutex);
  50 +
48 auto dec = decoderMap.find(name); 51 auto dec = decoderMap.find(name);
49 if (dec != decoderMap.end()) 52 if (dec != decoderMap.end())
50 { 53 {
@@ -52,7 +55,7 @@ bool FFNvDecoderManager::setUserPtr(const string name, const void * userPtr) @@ -52,7 +55,7 @@ bool FFNvDecoderManager::setUserPtr(const string name, const void * userPtr)
52 return true; 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 return false; 59 return false;
57 } 60 }
58 61
@@ -60,17 +63,19 @@ FFNvDecoder* FFNvDecoderManager::getDecoderByName(const string name) @@ -60,17 +63,19 @@ FFNvDecoder* FFNvDecoderManager::getDecoderByName(const string name)
60 { 63 {
61 if (name.empty()) 64 if (name.empty())
62 { 65 {
63 - cout << "name 为空!"<< endl; 66 + av_log(NULL, AV_LOG_ERROR, "name 为空! \n");
64 return nullptr; 67 return nullptr;
65 } 68 }
66 69
  70 + std::lock_guard<std::mutex> l(m_mutex);
  71 +
67 auto dec = decoderMap.find(name); 72 auto dec = decoderMap.find(name);
68 if (dec != decoderMap.end()) 73 if (dec != decoderMap.end())
69 { 74 {
70 return dec->second; 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 return nullptr; 79 return nullptr;
75 } 80 }
76 81
@@ -84,10 +89,12 @@ void FFNvDecoderManager::startDecode(FFNvDecoder* dec){ @@ -84,10 +89,12 @@ void FFNvDecoderManager::startDecode(FFNvDecoder* dec){
84 bool FFNvDecoderManager::startDecodeByName(const string name){ 89 bool FFNvDecoderManager::startDecodeByName(const string name){
85 if (name.empty()) 90 if (name.empty())
86 { 91 {
87 - cout << "name 为空!"<< endl; 92 + av_log(NULL, AV_LOG_ERROR, "name 为空! \n");
88 return false; 93 return false;
89 } 94 }
90 95
  96 + std::lock_guard<std::mutex> l(m_mutex);
  97 +
91 auto dec = decoderMap.find(name); 98 auto dec = decoderMap.find(name);
92 if (dec != decoderMap.end()) 99 if (dec != decoderMap.end())
93 { 100 {
@@ -95,11 +102,14 @@ bool FFNvDecoderManager::startDecodeByName(const string name){ @@ -95,11 +102,14 @@ bool FFNvDecoderManager::startDecodeByName(const string name){
95 return true; 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 return false; 106 return false;
100 } 107 }
101 108
102 void FFNvDecoderManager::startAllDecode(){ 109 void FFNvDecoderManager::startAllDecode(){
  110 +
  111 + std::lock_guard<std::mutex> l(m_mutex);
  112 +
103 for(auto iter = decoderMap.begin(); iter != decoderMap.end(); iter++){ 113 for(auto iter = decoderMap.begin(); iter != decoderMap.end(); iter++){
104 if (!iter->second->isRunning()) 114 if (!iter->second->isRunning())
105 { 115 {
@@ -111,11 +121,12 @@ void FFNvDecoderManager::startAllDecode(){ @@ -111,11 +121,12 @@ void FFNvDecoderManager::startAllDecode(){
111 bool FFNvDecoderManager::closeDecoderByName(const string name){ 121 bool FFNvDecoderManager::closeDecoderByName(const string name){
112 if (name.empty()) 122 if (name.empty())
113 { 123 {
114 - cout << "name 为空!"<< endl; 124 + av_log(NULL, AV_LOG_ERROR, "name 为空! \n");
115 return false; 125 return false;
116 } 126 }
117 127
118 - m_mutex_erase.lock(); 128 + std::lock_guard<std::mutex> l(m_mutex);
  129 +
119 auto dec = decoderMap.find(name); 130 auto dec = decoderMap.find(name);
120 if (dec != decoderMap.end()) 131 if (dec != decoderMap.end())
121 { 132 {
@@ -124,30 +135,29 @@ bool FFNvDecoderManager::closeDecoderByName(const string name){ @@ -124,30 +135,29 @@ bool FFNvDecoderManager::closeDecoderByName(const string name){
124 dec->second = nullptr; 135 dec->second = nullptr;
125 decoderMap.erase(dec); 136 decoderMap.erase(dec);
126 137
127 - m_mutex_erase.unlock();  
128 return true; 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 return false; 142 return false;
134 } 143 }
135 144
136 void FFNvDecoderManager::closeAllDecoder() 145 void FFNvDecoderManager::closeAllDecoder()
137 { 146 {
138 - m_mutex_erase.lock(); 147 + std::lock_guard<std::mutex> l(m_mutex);
  148 +
139 for(auto iter = decoderMap.begin(); iter != decoderMap.end(); iter++){ 149 for(auto iter = decoderMap.begin(); iter != decoderMap.end(); iter++){
140 iter->second->close(); 150 iter->second->close();
141 delete iter->second; 151 delete iter->second;
142 iter->second = nullptr; 152 iter->second = nullptr;
143 } 153 }
144 decoderMap.clear(); 154 decoderMap.clear();
145 - m_mutex_erase.unlock();  
146 } 155 }
147 156
148 void FFNvDecoderManager::closeAllFinishedDecoder() 157 void FFNvDecoderManager::closeAllFinishedDecoder()
149 { 158 {
150 - m_mutex_erase.lock(); 159 + std::lock_guard<std::mutex> l(m_mutex);
  160 +
151 for(auto iter = decoderMap.begin(); iter != decoderMap.end(); ){ 161 for(auto iter = decoderMap.begin(); iter != decoderMap.end(); ){
152 if (iter->second->isFinished()) 162 if (iter->second->isFinished())
153 { 163 {
@@ -160,13 +170,13 @@ void FFNvDecoderManager::closeAllFinishedDecoder() @@ -160,13 +170,13 @@ void FFNvDecoderManager::closeAllFinishedDecoder()
160 iter++ ; 170 iter++ ;
161 } 171 }
162 } 172 }
163 - m_mutex_erase.unlock();  
164 } 173 }
165 174
166 int FFNvDecoderManager::count() 175 int FFNvDecoderManager::count()
167 { 176 {
168 closeAllFinishedDecoder(); 177 closeAllFinishedDecoder();
169 178
  179 + std::lock_guard<std::mutex> l(m_mutex);
170 return decoderMap.size(); 180 return decoderMap.size();
171 } 181 }
172 182
@@ -174,10 +184,12 @@ bool FFNvDecoderManager::pauseDecoder(const string name) @@ -174,10 +184,12 @@ bool FFNvDecoderManager::pauseDecoder(const string name)
174 { 184 {
175 if (name.empty()) 185 if (name.empty())
176 { 186 {
177 - cout << "name 为空!"<< endl; 187 + av_log(NULL, AV_LOG_ERROR, "name 为空! \n");
178 return false; 188 return false;
179 } 189 }
180 190
  191 + std::lock_guard<std::mutex> l(m_mutex);
  192 +
181 auto dec = decoderMap.find(name); 193 auto dec = decoderMap.find(name);
182 if (dec != decoderMap.end()) 194 if (dec != decoderMap.end())
183 { 195 {
@@ -185,7 +197,7 @@ bool FFNvDecoderManager::pauseDecoder(const string name) @@ -185,7 +197,7 @@ bool FFNvDecoderManager::pauseDecoder(const string name)
185 return true; 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 return false; 201 return false;
190 } 202 }
191 203
@@ -193,10 +205,12 @@ bool FFNvDecoderManager::resumeDecoder(const string name) @@ -193,10 +205,12 @@ bool FFNvDecoderManager::resumeDecoder(const string name)
193 { 205 {
194 if (name.empty()) 206 if (name.empty())
195 { 207 {
196 - cout << "name 为空!"<< endl; 208 + av_log(NULL, AV_LOG_ERROR, "name 为空! \n");
197 return false; 209 return false;
198 } 210 }
199 211
  212 + std::lock_guard<std::mutex> l(m_mutex);
  213 +
200 auto dec = decoderMap.find(name); 214 auto dec = decoderMap.find(name);
201 if (dec != decoderMap.end()) 215 if (dec != decoderMap.end())
202 { 216 {
@@ -204,7 +218,7 @@ bool FFNvDecoderManager::resumeDecoder(const string name) @@ -204,7 +218,7 @@ bool FFNvDecoderManager::resumeDecoder(const string name)
204 return true; 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 return false; 222 return false;
209 } 223 }
210 224
@@ -217,17 +231,57 @@ bool FFNvDecoderManager::isSurport(FFDecConfig&amp; cfg) @@ -217,17 +231,57 @@ bool FFNvDecoderManager::isSurport(FFDecConfig&amp; cfg)
217 bool FFNvDecoderManager::isRunning(const string name){ 231 bool FFNvDecoderManager::isRunning(const string name){
218 if (name.empty()) 232 if (name.empty())
219 { 233 {
220 - cout << "name 为空!"<< endl; 234 + av_log(NULL, AV_LOG_ERROR, "name 为空! \n");
221 return false; 235 return false;
222 } 236 }
223 237
  238 + std::lock_guard<std::mutex> l(m_mutex);
  239 +
224 auto dec = decoderMap.find(name); 240 auto dec = decoderMap.find(name);
225 if (dec != decoderMap.end()) 241 if (dec != decoderMap.end())
226 { 242 {
227 return dec->second->isRunning(); 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 return false; 285 return false;
232 } 286 }
233 287
@@ -235,10 +289,12 @@ bool FFNvDecoderManager::setDecKeyframe(const string name, bool bKeyframe) @@ -235,10 +289,12 @@ bool FFNvDecoderManager::setDecKeyframe(const string name, bool bKeyframe)
235 { 289 {
236 if (name.empty()) 290 if (name.empty())
237 { 291 {
238 - cout << "name 为空!"<< endl; 292 + av_log(NULL, AV_LOG_ERROR, "name 为空! \n");
239 return false; 293 return false;
240 } 294 }
241 295
  296 + std::lock_guard<std::mutex> l(m_mutex);
  297 +
242 auto dec = decoderMap.find(name); 298 auto dec = decoderMap.find(name);
243 if (dec != decoderMap.end()) 299 if (dec != decoderMap.end())
244 { 300 {
@@ -246,6 +302,65 @@ bool FFNvDecoderManager::setDecKeyframe(const string name, bool bKeyframe) @@ -246,6 +302,65 @@ bool FFNvDecoderManager::setDecKeyframe(const string name, bool bKeyframe)
246 return true; 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 return false; 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 \ No newline at end of file 367 \ No newline at end of file
src/FFNvDecoderManager.h
@@ -45,7 +45,7 @@ public: @@ -45,7 +45,7 @@ public:
45 * 返回:成功返回解码器, 失败返回 nullptr 45 * 返回:成功返回解码器, 失败返回 nullptr
46 * 备注: 46 * 备注:
47 **************************************************/ 47 **************************************************/
48 - FFNvDecoder* createDecoder(MgrDecConfig& config); 48 + FFNvDecoder* createDecoder(MgrDecConfig config);
49 49
50 /************************************************** 50 /**************************************************
51 * 接口:setUserPtr 51 * 接口:setUserPtr
@@ -111,6 +111,15 @@ public: @@ -111,6 +111,15 @@ public:
111 **************************************************/ 111 **************************************************/
112 void closeAllDecoder(); 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 * 接口:pauseDecoder 124 * 接口:pauseDecoder
116 * 功能:暂停指定名称的解码器 125 * 功能:暂停指定名称的解码器
@@ -147,6 +156,24 @@ public: @@ -147,6 +156,24 @@ public:
147 **************************************************/ 156 **************************************************/
148 bool isRunning(const string name); 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 * 接口:count 178 * 接口:count
152 * 功能:获取正在运行的解码器数量 179 * 功能:获取正在运行的解码器数量
@@ -161,11 +188,58 @@ public: @@ -161,11 +188,58 @@ public:
161 * 功能:设置是否只解码关键帧。默认全解 188 * 功能:设置是否只解码关键帧。默认全解
162 * 参数:const string name 解码器名称 189 * 参数:const string name 解码器名称
163 * bool bKeyframe 是否只解码关键帧。true,只解码关键帧;false,普通的全解码 190 * bool bKeyframe 是否只解码关键帧。true,只解码关键帧;false,普通的全解码
164 - * 返回:void 191 + * 返回:bool 成功返回true,失败返回false
165 * 备注: 192 * 备注:
166 **************************************************/ 193 **************************************************/
167 bool setDecKeyframe(const string name, bool bKeyframe); 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 private: 243 private:
170 FFNvDecoderManager(){} 244 FFNvDecoderManager(){}
171 245
@@ -174,5 +248,5 @@ private: @@ -174,5 +248,5 @@ private:
174 private: 248 private:
175 map<string, FFNvDecoder*> decoderMap; 249 map<string, FFNvDecoder*> decoderMap;
176 250
177 - mutex m_mutex_erase; 251 + mutex m_mutex;
178 }; 252 };
179 \ No newline at end of file 253 \ No newline at end of file
src/main.cpp
@@ -225,8 +225,16 @@ int CheckCUDAProperty( int devId ) @@ -225,8 +225,16 @@ int CheckCUDAProperty( int devId )
225 return 0; 225 return 0;
226 } 226 }
227 227
  228 +void logFF(void *, int level, const char *fmt, va_list ap)
  229 +{
  230 + vfprintf(stdout, fmt, ap);
  231 +}
  232 +
  233 +
228 int main(){ 234 int main(){
229 235
  236 + // av_log_set_callback(&logFF);
  237 +
230 CheckCUDAProperty(0); 238 CheckCUDAProperty(0);
231 239
232 FFNvDecoderManager* pDecManager = FFNvDecoderManager::getInstance(); 240 FFNvDecoderManager* pDecManager = FFNvDecoderManager::getInstance();