diff --git a/src/FFNvDecoder.cpp b/src/FFNvDecoder.cpp index fe3d5c4..e89e99e 100644 --- a/src/FFNvDecoder.cpp +++ b/src/FFNvDecoder.cpp @@ -1,5 +1,4 @@ #include "FFNvDecoder.h" -#include #include #include @@ -24,7 +23,7 @@ static AVPixelFormat get_hw_format(AVCodecContext *avctx, const AVPixelFormat *p return *p; } - //cout << "Failed to get HW surface format"; + av_log(NULL, AV_LOG_ERROR, "Failed to get HW surface format. \n"); return AV_PIX_FMT_NONE; } @@ -86,13 +85,13 @@ bool FFNvDecoder::init(const char* uri, const char* gpuid, bool force_tcp) fmt_ctx = avformat_alloc_context(); const char* input_file = uri; if (avformat_open_input(&fmt_ctx, input_file, nullptr, &options) != 0) { - cout << "Cannot open input file: " << input_file; + av_log(NULL, AV_LOG_ERROR, "Cannot open input file: %s \n", input_file); return false; } // 查找流信息 if (avformat_find_stream_info(fmt_ctx, nullptr) < 0) { - cout << "Cannot find input stream information"; + av_log(NULL, AV_LOG_ERROR, "Cannot find input stream information ! \n"); return false; } @@ -100,7 +99,7 @@ bool FFNvDecoder::init(const char* uri, const char* gpuid, bool force_tcp) AVCodec *decoder = nullptr; stream_index = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &decoder, 0); if (stream_index < 0) { - cout << "Cannot find a video stream in the input file"; + av_log(NULL, AV_LOG_ERROR, "Cannot find a video stream in the input file ! \n"); return false; } @@ -130,9 +129,9 @@ bool FFNvDecoder::init(const char* uri, const char* gpuid, bool force_tcp) // 打开解码器流 AVDictionary *op = nullptr; av_dict_set( &op, "gpu", gpuid, 0 ); - // av_dict_set( &op, "surfaces", "3", 0 ); + av_dict_set( &op, "surfaces", "10", 0 ); if (avcodec_open2(avctx, vcodec, &op) < 0) { - cout << "Failed to open codec for stream" << stream_index; + av_log(NULL, AV_LOG_ERROR, "Failed to open codec for stream ! \n"); return false; } @@ -208,14 +207,9 @@ void FFNvDecoder::decode_thread() } int result = av_read_frame(fmt_ctx, pkt); - if (result == AVERROR_EOF) + if (result == AVERROR_EOF || result < 0) { - cout << "Failed to read frame!" << endl; - break; - } - if (result < 0) - { - cout << "Failed to read frame!" << endl; + av_log(NULL, AV_LOG_ERROR, "Failed to read frame! \n"); break; } @@ -234,19 +228,16 @@ void FFNvDecoder::decode_thread() } } - if (stream_index == pkt->stream_index) - { + if (stream_index == pkt->stream_index){ result = avcodec_send_packet(avctx, pkt); - if (result < 0) - { - cout << "Failed to send pkt:" << result << endl; + if (result < 0){ + av_log(NULL, AV_LOG_ERROR, "Failed to send pkt: %d \n",result); continue; } result = avcodec_receive_frame(avctx, gpuFrame); - if (result == AVERROR(EAGAIN) || result == AVERROR_EOF || result < 0) - { - cout << "Failed to receive frame"<< endl; + if ((result == AVERROR(EAGAIN) || result == AVERROR_EOF) || result < 0){ + av_log(NULL, AV_LOG_ERROR, "Failed to receive frame: %d \n",result); continue; } @@ -255,6 +246,14 @@ void FFNvDecoder::decode_thread() av_packet_unref(pkt); } + // 队列中没有数据了再结束 + while (mFrameQueue.length() > 0){ + if(!m_bRunning){ + break; + } + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + m_bRunning = false; // long end_time = get_cur_time(); @@ -266,9 +265,11 @@ void FFNvDecoder::decode_thread() pthread_join(m_post_decode_thread,0); } + decode_finished_cbk(m_userPtr); + decode_finished(); - cout << "decode thread exited." << endl; + av_log(NULL, AV_LOG_INFO, "decode thread exited. \n"); } void FFNvDecoder::decode_finished() @@ -289,7 +290,7 @@ void FFNvDecoder::decode_finished() void FFNvDecoder::post_decode_thread() { - while (m_bRunning) + while (m_bRunning || mFrameQueue.length() > 0) { AVFrame * gpuFrame = mFrameQueue.getHead(); if (gpuFrame == nullptr) @@ -302,8 +303,8 @@ void FFNvDecoder::post_decode_thread() mFrameQueue.addHead(); } - - cout << "post decode thread exited." << endl; + + av_log(NULL, AV_LOG_INFO, "post decode thread exited. \n"); } void FFNvDecoder::close() @@ -338,6 +339,10 @@ bool FFNvDecoder::isFinished() return m_bFinished; } +bool FFNvDecoder::isPausing(){ + return m_bPause; +} + bool FFNvDecoder::getResolution( int &width, int &height ) { if (avctx != nullptr) @@ -363,4 +368,135 @@ void FFNvDecoder::resume() void FFNvDecoder::setDecKeyframe(bool bKeyframe) { m_dec_keyframe = bKeyframe; +} + +int FFNvDecoder::getCachedQueueLength(){ + return mFrameQueue.length(); +} + +FFImgInfo* FFNvDecoder::snapshot(const string& uri){ + + AVFormatContext* ifmt_ctx = NULL; + AVCodecContext* codec_ctx = nullptr; + AVCodec* codec = nullptr; + AVPacket* pkt = nullptr; + AVFrame *frame = nullptr; + AVFrame *pFrameRGB = nullptr; + int video_index = -1; + AVStream* st = nullptr; + SwsContext *img_convert_ctx = nullptr; + uint8_t *buffer = NULL; + int numBytes = 0; + + FFImgInfo* imgInfo = nullptr; + + //av_register_all(); + avformat_network_init(); + + ///打开输入的流 + int ret = avformat_open_input(&ifmt_ctx, uri.c_str(), NULL, NULL); + if (ret != 0){ + av_log(NULL, AV_LOG_ERROR, "Couldn't open input stream ! \n"); + goto end_flag ; + } + + //查找流信息 + if (avformat_find_stream_info(ifmt_ctx, NULL) < 0){ + av_log(NULL, AV_LOG_ERROR, "Couldn't find stream information ! \n"); + goto end_flag ; + } + + //找到视频流索引 + video_index = av_find_best_stream(ifmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0); + + st = ifmt_ctx->streams[video_index]; + + //找到解码器 + codec = avcodec_find_decoder(st->codecpar->codec_id); + if (!codec){ + av_log(NULL, AV_LOG_ERROR, "Codec not found ! \n"); + goto end_flag ; + } + + //申请AVCodecContext + codec_ctx = avcodec_alloc_context3(codec); + if (!codec_ctx){ + goto end_flag ; + } + + avcodec_parameters_to_context(codec_ctx, ifmt_ctx->streams[video_index]->codecpar); + + //打开解码器 + if ((ret = avcodec_open2(codec_ctx, codec, NULL) < 0)){ + goto end_flag ; + } + + // 计算解码后原始数据所需缓冲区大小,并分配内存空间 Determine required buffer size and allocate buffer + numBytes = av_image_get_buffer_size(AV_PIX_FMT_RGB24, codec_ctx->width, codec_ctx->height, 1); + buffer = (uint8_t *)av_malloc(numBytes * sizeof(uint8_t)); + + pFrameRGB = av_frame_alloc(); + av_image_fill_arrays(pFrameRGB->data, pFrameRGB->linesize, buffer, AV_PIX_FMT_BGR24, codec_ctx->width, codec_ctx->height, 1); + + 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, + SWS_BICUBIC, NULL, NULL, NULL); + + pkt = av_packet_alloc(); + frame = av_frame_alloc(); + while (av_read_frame(ifmt_ctx, pkt) >= 0){ + if (pkt->stream_index == video_index){ + int ret = avcodec_send_packet(codec_ctx, pkt); + if (ret >= 0){ + ret = avcodec_receive_frame(codec_ctx, frame); + if ((ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) || ret < 0){ + av_log(NULL, AV_LOG_ERROR, "Failed to receive frame: %d \n", ret); + continue; + } + + sws_scale(img_convert_ctx, (const unsigned char* const*)frame->data, frame->linesize, 0, codec_ctx->height, pFrameRGB->data, pFrameRGB->linesize); + + imgInfo = new FFImgInfo(); + imgInfo->pData = buffer; + imgInfo->height = codec_ctx->height; + imgInfo->width = codec_ctx->width; + + break; + } + } + } + +end_flag: + if (codec_ctx != nullptr){ + avcodec_close(codec_ctx); + avcodec_free_context(&codec_ctx); + } + + if (ifmt_ctx != nullptr){ + avformat_close_input(&ifmt_ctx); + } + + if (frame != nullptr){ + av_frame_free(&frame); + } + + if (pFrameRGB != nullptr){ + av_frame_free(&pFrameRGB); + } + + if (pkt != nullptr){ + av_packet_free(&pkt); + } + + return imgInfo; +} + +void FFNvDecoder::releaseFFImgInfo(FFImgInfo* info){ + if(nullptr != info){ + if(info->pData != nullptr){ + av_free(info->pData); + info->pData = nullptr; + } + delete info; + info = nullptr; + } } \ No newline at end of file diff --git a/src/FFNvDecoder.h b/src/FFNvDecoder.h index 35e016e..5a01dae 100644 --- a/src/FFNvDecoder.h +++ b/src/FFNvDecoder.h @@ -12,6 +12,7 @@ extern "C" #include #include #include + #include } using namespace std; @@ -29,14 +30,22 @@ using namespace std; **************************************************/ typedef void(*POST_DECODE_CALLBACK)(const void * userPtr, AVFrame * gpuFrame); -struct FFDecConfig -{ +typedef void(*DECODE_FINISHED_CALLBACK)(const void* userPtr); + +struct FFDecConfig{ string uri; // 视频地址 POST_DECODE_CALLBACK post_decoded_cbk; // 解码数据回调接口 + DECODE_FINISHED_CALLBACK decode_finished_cbk; // 解码线程结束后的回调接口 string gpuid; // gpu id bool force_tcp{true}; // 是否指定使用tcp连接 }; +struct FFImgInfo{ + int width; + int height; + unsigned char * pData; +}; + class FFNvDecoder{ public: FFNvDecoder(); @@ -51,6 +60,7 @@ public: bool isRunning(); bool isFinished(); + bool isPausing(); bool getResolution( int &width, int &height ); void setName(string nm); @@ -58,6 +68,12 @@ public: bool isSurport(FFDecConfig& cfg); + int getCachedQueueLength(); + + static FFImgInfo* snapshot(const string& uri); + + static void releaseFFImgInfo(FFImgInfo*); + public: AVPixelFormat getHwPixFmt(); @@ -69,6 +85,7 @@ private: public: POST_DECODE_CALLBACK post_decoded_cbk; + DECODE_FINISHED_CALLBACK decode_finished_cbk; const void * m_userPtr; FFDecConfig m_cfg; diff --git a/src/FFNvDecoderManager.cpp b/src/FFNvDecoderManager.cpp index 2624c39..8f6ebc2 100644 --- a/src/FFNvDecoderManager.cpp +++ b/src/FFNvDecoderManager.cpp @@ -1,17 +1,17 @@ #include "FFNvDecoderManager.h" -#include using namespace std; -FFNvDecoder* FFNvDecoderManager::createDecoder(MgrDecConfig& config){ +FFNvDecoder* FFNvDecoderManager::createDecoder(MgrDecConfig config){ closeAllFinishedDecoder(); - int num = decoderMap.count(config.name); - if (num > 0) - { - cout << "已存在name所标记的解码器" << endl; + std::lock_guard l(m_mutex); + + auto it = decoderMap.find(config.name); + if (it != decoderMap.end()){ + av_log(NULL, AV_LOG_ERROR, "已存在name所标记的解码器 \n"); return nullptr; } @@ -26,6 +26,7 @@ FFNvDecoder* FFNvDecoderManager::createDecoder(MgrDecConfig& config){ { dec->setName(config.name) ; dec->post_decoded_cbk = config.cfg.post_decoded_cbk; + dec->decode_finished_cbk = config.cfg.decode_finished_cbk; decoderMap[config.name] = dec; return dec; } @@ -41,10 +42,12 @@ bool FFNvDecoderManager::setUserPtr(const string name, const void * userPtr) { if (name.empty()) { - cout << "name 为空!"<< endl; + av_log(NULL, AV_LOG_ERROR, "name 为空! \n"); return false; } + std::lock_guard l(m_mutex); + auto dec = decoderMap.find(name); if (dec != decoderMap.end()) { @@ -52,7 +55,7 @@ bool FFNvDecoderManager::setUserPtr(const string name, const void * userPtr) return true; } - cout << "没有找到name为" << name << "的解码器!" << endl; + av_log(NULL, AV_LOG_ERROR, "没有找到name为 %s 的解码器! \n", name.c_str()); return false; } @@ -60,17 +63,19 @@ FFNvDecoder* FFNvDecoderManager::getDecoderByName(const string name) { if (name.empty()) { - cout << "name 为空!"<< endl; + av_log(NULL, AV_LOG_ERROR, "name 为空! \n"); return nullptr; } + std::lock_guard l(m_mutex); + auto dec = decoderMap.find(name); if (dec != decoderMap.end()) { return dec->second; } - cout << "没有找到name为" << name << "的解码器!" << endl; + av_log(NULL, AV_LOG_ERROR, "没有找到name为 %s 的解码器! \n", name.c_str()); return nullptr; } @@ -84,10 +89,12 @@ void FFNvDecoderManager::startDecode(FFNvDecoder* dec){ bool FFNvDecoderManager::startDecodeByName(const string name){ if (name.empty()) { - cout << "name 为空!"<< endl; + av_log(NULL, AV_LOG_ERROR, "name 为空! \n"); return false; } + std::lock_guard l(m_mutex); + auto dec = decoderMap.find(name); if (dec != decoderMap.end()) { @@ -95,11 +102,14 @@ bool FFNvDecoderManager::startDecodeByName(const string name){ return true; } - cout << "没有找到name为" << name << "的解码器!" << endl; + av_log(NULL, AV_LOG_ERROR, "没有找到name为 %s 的解码器! \n", name.c_str()); return false; } void FFNvDecoderManager::startAllDecode(){ + + std::lock_guard l(m_mutex); + for(auto iter = decoderMap.begin(); iter != decoderMap.end(); iter++){ if (!iter->second->isRunning()) { @@ -111,11 +121,12 @@ void FFNvDecoderManager::startAllDecode(){ bool FFNvDecoderManager::closeDecoderByName(const string name){ if (name.empty()) { - cout << "name 为空!"<< endl; + av_log(NULL, AV_LOG_ERROR, "name 为空! \n"); return false; } - m_mutex_erase.lock(); + std::lock_guard l(m_mutex); + auto dec = decoderMap.find(name); if (dec != decoderMap.end()) { @@ -124,30 +135,29 @@ bool FFNvDecoderManager::closeDecoderByName(const string name){ dec->second = nullptr; decoderMap.erase(dec); - m_mutex_erase.unlock(); return true; } - m_mutex_erase.unlock(); - cout << "没有找到name为" << name << "的解码器!" << endl; + av_log(NULL, AV_LOG_ERROR, "没有找到name为 %s 的解码器! \n", name.c_str()); return false; } void FFNvDecoderManager::closeAllDecoder() { - m_mutex_erase.lock(); + std::lock_guard l(m_mutex); + for(auto iter = decoderMap.begin(); iter != decoderMap.end(); iter++){ iter->second->close(); delete iter->second; iter->second = nullptr; } decoderMap.clear(); - m_mutex_erase.unlock(); } void FFNvDecoderManager::closeAllFinishedDecoder() { - m_mutex_erase.lock(); + std::lock_guard l(m_mutex); + for(auto iter = decoderMap.begin(); iter != decoderMap.end(); ){ if (iter->second->isFinished()) { @@ -160,13 +170,13 @@ void FFNvDecoderManager::closeAllFinishedDecoder() iter++ ; } } - m_mutex_erase.unlock(); } int FFNvDecoderManager::count() { closeAllFinishedDecoder(); + std::lock_guard l(m_mutex); return decoderMap.size(); } @@ -174,10 +184,12 @@ bool FFNvDecoderManager::pauseDecoder(const string name) { if (name.empty()) { - cout << "name 为空!"<< endl; + av_log(NULL, AV_LOG_ERROR, "name 为空! \n"); return false; } + std::lock_guard l(m_mutex); + auto dec = decoderMap.find(name); if (dec != decoderMap.end()) { @@ -185,7 +197,7 @@ bool FFNvDecoderManager::pauseDecoder(const string name) return true; } - cout << "没有找到name为" << name << "的解码器!" << endl; + av_log(NULL, AV_LOG_ERROR, "没有找到name为 %s 的解码器! \n", name.c_str()); return false; } @@ -193,10 +205,12 @@ bool FFNvDecoderManager::resumeDecoder(const string name) { if (name.empty()) { - cout << "name 为空!"<< endl; + av_log(NULL, AV_LOG_ERROR, "name 为空! \n"); return false; } + std::lock_guard l(m_mutex); + auto dec = decoderMap.find(name); if (dec != decoderMap.end()) { @@ -204,7 +218,7 @@ bool FFNvDecoderManager::resumeDecoder(const string name) return true; } - cout << "没有找到name为" << name << "的解码器!" << endl; + av_log(NULL, AV_LOG_ERROR, "没有找到name为 %s 的解码器! \n", name.c_str()); return false; } @@ -217,17 +231,57 @@ bool FFNvDecoderManager::isSurport(FFDecConfig& cfg) bool FFNvDecoderManager::isRunning(const string name){ if (name.empty()) { - cout << "name 为空!"<< endl; + av_log(NULL, AV_LOG_ERROR, "name 为空! \n"); return false; } + std::lock_guard l(m_mutex); + auto dec = decoderMap.find(name); if (dec != decoderMap.end()) { return dec->second->isRunning(); } - cout << "没有找到name为" << name << "的解码器!" << endl; + av_log(NULL, AV_LOG_ERROR, "没有找到name为 %s 的解码器! \n", name.c_str()); + return false; +} + +bool FFNvDecoderManager::isFinished(const string name){ + if (name.empty()) + { + av_log(NULL, AV_LOG_ERROR, "name 为空! \n"); + return false; + } + + std::lock_guard l(m_mutex); + + auto dec = decoderMap.find(name); + if (dec != decoderMap.end()) + { + return dec->second->isFinished(); + } + + av_log(NULL, AV_LOG_ERROR, "没有找到name为 %s 的解码器! \n", name.c_str()); + return false; +} + +bool FFNvDecoderManager::isPausing(const string name){ + if (name.empty()) + { + av_log(NULL, AV_LOG_ERROR, "name 为空! \n"); + return false; + } + + std::lock_guard l(m_mutex); + + auto dec = decoderMap.find(name); + if (dec != decoderMap.end()) + { + return dec->second->isPausing(); + } + + av_log(NULL, AV_LOG_ERROR, "没有找到name为 %s 的解码器! \n", name.c_str()); return false; } @@ -235,10 +289,12 @@ bool FFNvDecoderManager::setDecKeyframe(const string name, bool bKeyframe) { if (name.empty()) { - cout << "name 为空!"<< endl; + av_log(NULL, AV_LOG_ERROR, "name 为空! \n"); return false; } + std::lock_guard l(m_mutex); + auto dec = decoderMap.find(name); if (dec != decoderMap.end()) { @@ -246,6 +302,65 @@ bool FFNvDecoderManager::setDecKeyframe(const string name, bool bKeyframe) return true; } - cout << "没有找到name为" << name << "的解码器!" << endl; + av_log(NULL, AV_LOG_ERROR, "没有找到name为 %s 的解码器! \n", name.c_str()); + return false; +} + +bool FFNvDecoderManager::getResolution(const string name, int &width, int &height) +{ + if (name.empty()) + { + av_log(NULL, AV_LOG_ERROR, "name 为空! \n"); + return false; + } + + std::lock_guard l(m_mutex); + + auto dec = decoderMap.find(name); + if (dec != decoderMap.end()) + { + dec->second->getResolution(width, height); + return true; + } + + av_log(NULL, AV_LOG_ERROR, "没有找到name为 %s 的解码器! \n", name.c_str()); return false; +} + +vector FFNvDecoderManager::getAllDecodeName(){ + + closeAllFinishedDecoder(); + + std::lock_guard l(m_mutex); + + vector decode_names; + for(auto it = decoderMap.begin(); it != decoderMap.end(); ++it){ + decode_names.push_back(it->first); + } + return decode_names; +} + +int FFNvDecoderManager::getCachedQueueLength(const string name){ + if (name.empty()){ + av_log(NULL, AV_LOG_ERROR, "name 为空! \n"); + return -1; + } + + std::lock_guard l(m_mutex); + + auto dec = decoderMap.find(name); + if (dec != decoderMap.end()){ + return dec->second->getCachedQueueLength(); + } + + av_log(NULL, AV_LOG_ERROR, "没有找到name为 %s 的解码器! \n", name.c_str()); + return -1; +} + +FFImgInfo* FFNvDecoderManager::snapshot(const string& uri){ + return FFNvDecoder::snapshot(uri); +} + +void FFNvDecoderManager::releaseFFImgInfo(FFImgInfo* info){ + FFNvDecoder::releaseFFImgInfo(info); } \ No newline at end of file diff --git a/src/FFNvDecoderManager.h b/src/FFNvDecoderManager.h index 0f6f075..bae7838 100644 --- a/src/FFNvDecoderManager.h +++ b/src/FFNvDecoderManager.h @@ -45,7 +45,7 @@ public: * 返回:成功返回解码器, 失败返回 nullptr * 备注: **************************************************/ - FFNvDecoder* createDecoder(MgrDecConfig& config); + FFNvDecoder* createDecoder(MgrDecConfig config); /************************************************** * 接口:setUserPtr @@ -111,6 +111,15 @@ public: **************************************************/ void closeAllDecoder(); + /************************************************** + * 接口:closeAllDecoderByGpuid + * 功能:关闭某张显卡撒花姑娘的全部解码器 + * 参数:const string gpuid gpu的id + * 返回:void + * 备注: + **************************************************/ + void closeAllDecoderByGpuid(const string gpuid); + /************************************************** * 接口:pauseDecoder * 功能:暂停指定名称的解码器 @@ -147,6 +156,24 @@ public: **************************************************/ bool isRunning(const string name); + /************************************************** + * 接口:isFinished + * 功能:根据解码器名称判断解码器是否已经结束 + * 参数:const string name 解码器名称 + * 返回:正在运行返回true,否则返回false + * 备注: + **************************************************/ + bool isFinished(const string name); + + /************************************************** + * 接口:isPausing + * 功能:根据解码器名称判断解码器是否暂停 + * 参数:const string name 解码器名称 + * 返回:正在运行返回true,否则返回false + * 备注: + **************************************************/ + bool isPausing(const string name); + /************************************************** * 接口:count * 功能:获取正在运行的解码器数量 @@ -161,11 +188,58 @@ public: * 功能:设置是否只解码关键帧。默认全解 * 参数:const string name 解码器名称 * bool bKeyframe 是否只解码关键帧。true,只解码关键帧;false,普通的全解码 - * 返回:void + * 返回:bool 成功返回true,失败返回false * 备注: **************************************************/ bool setDecKeyframe(const string name, bool bKeyframe); + /************************************************** + * 接口:getResolution + * 功能:获取视频分辨率 + * 参数:const string name 解码器名称 + * int &width 从 width 返回视频宽度 + * int &height 从 height 返回视频高度 + * 返回:bool 成功获取返回true,失败返回false + * 备注: + **************************************************/ + bool getResolution(const string name, int &width, int &height); + + /************************************************** + * 接口:getAllDecodeName + * 功能:获取全部解码器名称 + * 参数:void + * 返回:vector 返回全部解码器名称 + * 备注: + **************************************************/ + vector getAllDecodeName(); + + /************************************************** + * 接口:getCachedQueueLength + * 功能:获取解码缓冲队列当前长度 + * 参数:const string name 解码器名称 + * 返回:int 解码缓冲队列当前长度 + * 备注: + **************************************************/ + int getCachedQueueLength(const string name); + + /************************************************** + * 接口:snapshot + * 功能:获取视频快照 + * 参数:const string& uri 视频地址 + * 返回:FFImgInfo* 快照信息 + * 备注: + **************************************************/ + FFImgInfo* snapshot(const string& uri); + + /************************************************** + * 接口:releaseFFImgInfo + * 功能:释放视频快照信息 + * 参数:FFImgInfo* info 视频快照信息 + * 返回:void + * 备注: + **************************************************/ + void releaseFFImgInfo(FFImgInfo* info); + private: FFNvDecoderManager(){} @@ -174,5 +248,5 @@ private: private: map decoderMap; - mutex m_mutex_erase; + mutex m_mutex; }; \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 00a61d9..1d08668 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -225,8 +225,16 @@ int CheckCUDAProperty( int devId ) return 0; } +void logFF(void *, int level, const char *fmt, va_list ap) +{ + vfprintf(stdout, fmt, ap); +} + + int main(){ + // av_log_set_callback(&logFF); + CheckCUDAProperty(0); FFNvDecoderManager* pDecManager = FFNvDecoderManager::getInstance();