diff --git a/ffmpeg-4.2.2/libavcodec/cuviddec.c b/ffmpeg-4.2.2/libavcodec/cuviddec.c old mode 100644 new mode 100755 index acee78c..50c4d31 --- a/ffmpeg-4.2.2/libavcodec/cuviddec.c +++ b/ffmpeg-4.2.2/libavcodec/cuviddec.c @@ -1012,7 +1012,7 @@ static av_cold int cuvid_decode_init(AVCodecContext *avctx) } ctx->cuparseinfo.ulMaxNumDecodeSurfaces = ctx->nb_surfaces; - ctx->cuparseinfo.ulMaxDisplayDelay = 4; + ctx->cuparseinfo.ulMaxDisplayDelay = 2; ctx->cuparseinfo.pUserData = avctx; ctx->cuparseinfo.pfnSequenceCallback = cuvid_handle_video_sequence; ctx->cuparseinfo.pfnDecodePicture = cuvid_handle_picture_decode; diff --git a/src/FFCuContextManager.cpp b/src/FFCuContextManager.cpp new file mode 100644 index 0000000..169cf29 --- /dev/null +++ b/src/FFCuContextManager.cpp @@ -0,0 +1,28 @@ +#include "FFCuContextManager.h" +#include + +using namespace std; + +FFCuContextManager::~FFCuContextManager() +{ + for(auto iter = ctxMap.begin(); iter != ctxMap.end(); iter++){ + av_buffer_unref(&iter->second); + } + ctxMap.clear(); +} + +AVBufferRef *FFCuContextManager::getCuCtx(string gpuid) +{ + AVBufferRef *hw_device_ctx = ctxMap[gpuid]; + if (nullptr == hw_device_ctx) + { + // 初始化硬件解码器 + if (av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_CUDA, gpuid.c_str(), nullptr, 0) < 0) + { + cout << "Failed to create specified HW device."; + return nullptr; + } + ctxMap[gpuid] = hw_device_ctx; + } + return hw_device_ctx; +} \ No newline at end of file diff --git a/src/FFCuContextManager.h b/src/FFCuContextManager.h new file mode 100644 index 0000000..3050641 --- /dev/null +++ b/src/FFCuContextManager.h @@ -0,0 +1,37 @@ + +#include +#include + +extern "C" +{ + #include + #include + #include + #include + #include + #include + #include +} + +using namespace std; + +class FFCuContextManager{ +public: + static FFCuContextManager* getInstance(){ + static FFCuContextManager* singleton = nullptr; + if (singleton == nullptr){ + singleton = new FFCuContextManager(); + } + return singleton; + } + + AVBufferRef *getCuCtx(string gpuid); + +private: + FFCuContextManager(){} + ~FFCuContextManager(); + +private: + map ctxMap; + +}; \ No newline at end of file diff --git a/src/FFNvDecoder.cpp b/src/FFNvDecoder.cpp index 6ba885f..7d070ed 100644 --- a/src/FFNvDecoder.cpp +++ b/src/FFNvDecoder.cpp @@ -5,6 +5,8 @@ #include #include +#include "FFCuContextManager.h" + using namespace std; // 参考博客: https://blog.csdn.net/qq_40116098/article/details/120704340 @@ -67,7 +69,8 @@ bool FFNvDecoder::init(FFDecConfig& cfg) bool FFNvDecoder::init(const char* uri, const char* gpuid, bool force_tcp) { - av_register_all(); + // av_log_set_level(AV_LOG_DEBUG); + avformat_network_init(); // 打开输入视频文件 @@ -114,9 +117,17 @@ bool FFNvDecoder::init(const char* uri, const char* gpuid, bool force_tcp) hw_pix_fmt = AV_PIX_FMT_CUDA; + FFCuContextManager* pCtxMgr = FFCuContextManager::getInstance(); + avctx->hw_device_ctx = av_buffer_ref(pCtxMgr->getCuCtx(gpuid)); + if (nullptr == avctx->hw_device_ctx) + { + return false; + } + // 打开解码器流 AVDictionary *op = nullptr; av_dict_set( &op, "gpu", gpuid, 0 ); + av_dict_set( &op, "surfaces", "3", 0 ); if (avcodec_open2(avctx, vcodec, &op) < 0) { cout << "Failed to open codec for stream" << stream_index; return false; @@ -231,10 +242,6 @@ void FFNvDecoder::decode_finished() { if (avctx) { - if (avctx->hw_device_ctx) - { - av_buffer_unref(&avctx->hw_device_ctx); - } avcodec_free_context(&avctx); } diff --git a/src/FFNvDecoderManager.cpp b/src/FFNvDecoderManager.cpp index c7c2057..54373cf 100644 --- a/src/FFNvDecoderManager.cpp +++ b/src/FFNvDecoderManager.cpp @@ -112,38 +112,52 @@ bool FFNvDecoderManager::closeDecoderByName(string name){ return false; } + m_mutex_erase.lock(); auto dec = decoderMap.find(name); if (dec != decoderMap.end()) { dec->second->close(); delete dec->second; + dec->second = nullptr; decoderMap.erase(dec); + + m_mutex_erase.unlock(); return true; } - + m_mutex_erase.unlock(); cout << "没有找到name为" << name << "的解码器!" << endl; return false; } void FFNvDecoderManager::closeAllDecoder() { + m_mutex_erase.lock(); 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() { - for(auto iter = decoderMap.begin(); iter != decoderMap.end(); iter++){ + m_mutex_erase.lock(); + for(auto iter = decoderMap.begin(); iter != decoderMap.end(); ){ if (iter->second->isFinished()) { delete iter->second; - decoderMap.erase(iter); + iter->second = nullptr; + iter = decoderMap.erase(iter); + } + else + { + iter++ ; } } + m_mutex_erase.unlock(); } int FFNvDecoderManager::count() diff --git a/src/FFNvDecoderManager.h b/src/FFNvDecoderManager.h index b609339..3d3fc77 100644 --- a/src/FFNvDecoderManager.h +++ b/src/FFNvDecoderManager.h @@ -3,6 +3,8 @@ #include #include +#include + using namespace std; struct MgrDecConfig @@ -55,4 +57,6 @@ private: private: map decoderMap; + + mutex m_mutex_erase; }; \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index a36d59a..2ecd8d1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,6 +5,11 @@ #include "NvJpegEncoder.h" +#include +#include + +#include + unsigned char *pHwRgb = nullptr; /** @@ -14,15 +19,21 @@ void postDecoded(const void * userPtr, AVFrame * gpuFrame){ FFNvDecoder* decoder = (FFNvDecoder*)userPtr; if (decoder!= nullptr) { - cout << "decode name: " << decoder->getName() << endl; + // cout << "decode name: " << decoder->getName() << endl; + + if (decoder->getName() == "dec1") + { + /* code */ + } + // const char* gpu_pixfmt = av_get_pix_fmt_name((AVPixelFormat)gpuFrame->format); // cout << "pixfmt: " << gpu_pixfmt << endl; - cout << "keyframe: " << gpuFrame->key_frame << " width: " << gpuFrame->width << " height: "<< gpuFrame->height << endl; + // cout << "keyframe: " << gpuFrame->key_frame << " width: " << gpuFrame->width << " height: "<< gpuFrame->height << endl; // cout << "decode successed ✿✿ヽ(°▽°)ノ✿ " << endl; if (gpuFrame->format == AV_PIX_FMT_CUDA) { - cout << "gpuid = " << atoi(decoder->m_cfg.gpuid.c_str()) << endl; + // cout << "gpuid = " << atoi(decoder->m_cfg.gpuid.c_str()) << endl; // cudaSetDevice(atoi(decoder->m_cfg.gpuid.c_str())); // cudaError_t cudaStatus; // if(pHwRgb == nullptr){ @@ -42,14 +53,75 @@ void postDecoded(const void * userPtr, AVFrame * gpuFrame){ } } +long start_time = 0; +long end_time = 0; +bool count_flag = false; +int count = 0; +int count_std = 100; + +long long get_cur_time(){ + // 获取操作系统当前时间点(精确到微秒) + chrono::time_point tpMicro + = chrono::time_point_cast(chrono::system_clock::now()); + // (微秒精度的)时间点 => (微秒精度的)时间戳 + time_t totalMicroSeconds = tpMicro.time_since_epoch().count(); + + long long currentTime = ((long long)totalMicroSeconds)/1000; + + return currentTime; +} + +int sum = 0; +void postDecoded0(const void * userPtr, AVFrame * gpuFrame){ + FFNvDecoder* decoder = (FFNvDecoder*)userPtr; + if (decoder!= nullptr) + { + // cout << "decode name: " << decoder->getName() << endl; + if (decoder->getName() == "dec") + { + if (! count_flag) + { + count_flag = true; + count = 0; + end_time = start_time = get_cur_time(); + } + count++; + sum ++ ; + if (count >= count_std) + { + end_time = get_cur_time(); + long time_using = end_time - start_time; + double time_per_frame = double(time_using)/count_std ; + cout << count_std << "帧用时:" << time_using << "ms 每帧用时:" << time_per_frame << "ms" << endl; + cout << "keyframe: " << gpuFrame->key_frame << " width: " << gpuFrame->width << " height: "<< gpuFrame->height << endl; + cout << gpuFrame->pts << endl; + + count_flag = false; + } + } + } +} + +// string test_uri = "rtmp://192.168.10.56:1935/objecteye/1"; +string test_uri = "/home/cmhu/data/test.mp4"; + void createDecode(int index){ FFNvDecoderManager* pDecManager = FFNvDecoderManager::getInstance(); MgrDecConfig config; config.name = "dec" + to_string(index); - config.cfg.uri = "rtsp://176.10.0.4:8554/stream"; + config.cfg.uri = test_uri; config.cfg.post_decoded_cbk = postDecoded; config.cfg.force_tcp = true; - config.cfg.gpuid = "1"; + + if (index % 2 == 0) + { + config.cfg.gpuid = "2"; + } + else + { + config.cfg.gpuid = "1"; + } + FFNvDecoder* decoder = pDecManager->createDecoder(config); if (!decoder) { @@ -59,21 +131,57 @@ void createDecode(int index){ pDecManager->startDecodeByName(config.name); } +#define checkCudaErrors(S) do {CUresult status; \ + status = S; \ + if (status != CUDA_SUCCESS ) std::cout << __LINE__ <<" checkCudaErrors - status = " << status << std::endl; \ + } while (false) + +int CheckCUDAProperty( int devId ) +{ + cuInit(0); + + CUdevice dev = devId; + size_t memSize = 0; + char devName[256] = {0}; + int major = 0, minor = 0; + CUresult rlt = CUDA_SUCCESS; + + rlt = cuDeviceComputeCapability( &major, &minor, dev ); + checkCudaErrors( rlt ); + + rlt = cuDeviceGetName( devName, sizeof( devName ), dev ); + checkCudaErrors( rlt ); + + printf( "Using GPU Device %d: %s has SM %d.%d compute capability\n", + dev, devName, major, minor ); + + rlt = cuDeviceTotalMem( &memSize, dev ); + checkCudaErrors( rlt ); + + printf( "Total amount of global memory: %4.4f MB\n", + (float)memSize / ( 1024 * 1024 ) ); + + return 0; +} + int main(){ + CheckCUDAProperty(1); + FFNvDecoderManager* pDecManager = FFNvDecoderManager::getInstance(); - // for (size_t i = 0; i < 20; i++) - // { - // createDecode(i); - // } + int count = 105; + for (size_t i = 0; i < count ; i++) + { + createDecode(i); + } MgrDecConfig config; - config.name = "dec2"; - config.cfg.uri = "/home/cmhu/data/test.mp4"; - config.cfg.post_decoded_cbk = postDecoded; + config.name = "dec"; + config.cfg.uri = test_uri; + config.cfg.post_decoded_cbk = postDecoded0; config.cfg.force_tcp = true; - config.cfg.gpuid = "2"; + config.cfg.gpuid = "1"; FFNvDecoder* dec2 = pDecManager->createDecoder(config); if (!dec2) { @@ -82,6 +190,26 @@ int main(){ pDecManager->setUserPtr(config.name, dec2); pDecManager->startDecodeByName(config.name); + pthread_t m_decode_thread; + pthread_create(&m_decode_thread,0, + [](void* arg) + { + while (true) + { + std::this_thread::sleep_for(std::chrono::milliseconds(5000)); + FFNvDecoderManager* pDecManager = FFNvDecoderManager::getInstance(); + int count = pDecManager->count(); + cout << "当前运行路数: " << pDecManager->count() << endl; + if (count <= 0) + { + break; + } + } + + return (void*)0; + } + ,nullptr); + // config.name = "dec0"; // config.cfg.uri = "rtmp://192.168.10.56:1935/objecteye/1"; @@ -116,6 +244,8 @@ int main(){ // // pDecManager->resumeDecoder("dec1"); // pDecManager->resumeDecoder("dec2"); + cout << "总共帧数:" << sum << endl; + while (getchar() != 'q'); pDecManager->closeAllDecoder();