diff --git a/.vscode/launch.json b/.vscode/launch.json index 8f90775..51b59bd 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -6,7 +6,7 @@ "type": "cppdbg", "request": "launch", "program": "${workspaceFolder}/bin/lib/test", - "args": [], + "args": ["rtsp://176.10.0.4:8554/stream","0"], "stopAtEntry": false, "cwd": "${workspaceFolder}/bin/lib", "environment": [], diff --git a/.vscode/settings.json b/.vscode/settings.json index 7cfc35b..b797d5c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -10,6 +10,57 @@ "iostream": "cpp", "thread": "cpp", "nvdec.h": "c", - "chrono": "cpp" + "chrono": "cpp", + "atomic": "cpp", + "bit": "cpp", + "*.tcc": "cpp", + "bitset": "cpp", + "cctype": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "codecvt": "cpp", + "condition_variable": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "deque": "cpp", + "map": "cpp", + "set": "cpp", + "unordered_map": "cpp", + "vector": "cpp", + "exception": "cpp", + "algorithm": "cpp", + "functional": "cpp", + "iterator": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "numeric": "cpp", + "optional": "cpp", + "random": "cpp", + "ratio": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "fstream": "cpp", + "initializer_list": "cpp", + "iomanip": "cpp", + "istream": "cpp", + "limits": "cpp", + "mutex": "cpp", + "new": "cpp", + "ostream": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "streambuf": "cpp", + "cfenv": "cpp", + "cinttypes": "cpp", + "__nullptr": "cpp" } } \ No newline at end of file diff --git a/check_tool/FFCuContextManager.cpp b/check_tool/FFCuContextManager.cpp new file mode 100644 index 0000000..8f5b09a --- /dev/null +++ b/check_tool/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) + { + av_log(nullptr, AV_LOG_ERROR, "Failed to create specified HW device ! \n"); + return nullptr; + } + ctxMap[gpuid] = hw_device_ctx; + } + return hw_device_ctx; +} \ No newline at end of file diff --git a/check_tool/FFCuContextManager.h b/check_tool/FFCuContextManager.h new file mode 100644 index 0000000..3050641 --- /dev/null +++ b/check_tool/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/check_tool/Makefile b/check_tool/Makefile new file mode 100644 index 0000000..ebc427d --- /dev/null +++ b/check_tool/Makefile @@ -0,0 +1,50 @@ + +XX = g++ +NVCC = nvcc + +PROJECT_ROOT= /mnt/e/fiss/FFNvDecoder + +DEPEND_DIR = $(PROJECT_ROOT)/bin +SRC_ROOT = $(PROJECT_ROOT)/check_tool +CUDA_ROOT = /usr/local/cuda + +TARGET= $(DEPEND_DIR)/lib/check_tool + + +INCLUDE= -I $(DEPEND_DIR)/include \ + -I $(CUDA_ROOT)/include \ + -I $(SRC_ROOT)\ + +LIBSPATH= -L $(DEPEND_DIR)/lib -lavformat -lavcodec -lswscale -lavutil -lavfilter -lswresample -lavdevice \ + -L $(CUDA_ROOT)/lib64 -lcudart -lcurand -lcublas -lnvjpeg \ + -L /usr/lib/wsl/lib -lcuda -lnvcuvid\ + +CFLAGS= -g -fPIC -O0 $(INCLUDE) -pthread -lrt -lz -std=c++11 -fvisibility=hidden -Wl,-Bsymbolic -ldl + # -DUNICODE -D_UNICODE + +NFLAGS_LIB=-g -c -shared -Xcompiler -fPIC -Xcompiler -fvisibility=hidden +NFLAGS = $(NFLAGS_LIB) $(INCLUDE) -std=c++11 + +SRCS:=$(wildcard $(SRC_ROOT)/*.cpp) +OBJS = $(patsubst %.cpp, %.o, $(notdir $(SRCS))) + +CU_SOURCES = $(wildcard ${SRC_ROOT}/*.cu) +CU_OBJS = $(patsubst %.cu, %.o, $(notdir $(CU_SOURCES))) + + +$(TARGET):$(OBJS) $(CU_OBJS) + rm -f $(TARGET) + $(XX) -o $@ $^ $(CFLAGS) $(LIBSPATH) $(LIBS) -Wwrite-strings + rm -f *.o + +%.o:$(SRC_ROOT)/%.cpp + $(XX) $(CFLAGS) -c $< + +%.o:$(SRC_ROOT)/%.cu + @echo "#######################CU_OBJS:$@###############" + $(NVCC) $(NFLAGS) -o $@ $< + +clean: + rm -f *.o $(TARGET) + + diff --git a/check_tool/check_tool.cpp b/check_tool/check_tool.cpp new file mode 100644 index 0000000..03e616f --- /dev/null +++ b/check_tool/check_tool.cpp @@ -0,0 +1,184 @@ +#include"check_tool.h" + +#include "FFCuContextManager.h" + +extern "C" +{ + #include + #include + #include + #include + #include + #include + #include + #include +} + +#include + +static AVPixelFormat get_hw_format(AVCodecContext *avctx, const AVPixelFormat *pix_fmts){ + + const AVPixelFormat *p; + + for (p = pix_fmts; *p != -1; p++) { + if (*p == AV_PIX_FMT_CUDA) + return *p; + } + + av_log(nullptr, AV_LOG_ERROR, "Failed to get HW surface format. \n"); + return AV_PIX_FMT_NONE; +} + +static long long get_cur_time(){ + // 获取操作系统当前时间点(精确到微秒) + chrono::time_point tpMicro + = chrono::time_point_cast(chrono::system_clock::now()); + // (微秒精度的)时间点 => (微秒精度的)时间戳 + time_t currentTime = tpMicro.time_since_epoch().count(); + + return (long long )currentTime; +} + +void evalQuality(const string& uri, const char* gpuid){ + AVFormatContext* ifmt_ctx = nullptr; + AVCodecContext* codec_ctx = nullptr; + AVCodec *decoder = nullptr; + AVCodec* codec = nullptr; + AVPacket* pkt = nullptr; + int video_index = -1; + AVStream* st = nullptr; + SwsContext *img_convert_ctx = nullptr; + uint8_t *buffer = nullptr; + int numBytes = 0; + + long start_time = 0; + long end_time = 0; + long s_time = 0; + long e_time = 0; + long long sum = 0; + double avg_time = 0.0; + + int sep = 0; + + string cuvid_dec_name = "" ; + FFCuContextManager* pCtxMgr = FFCuContextManager::getInstance(); + AVDictionary *op = nullptr; + AVBufferRef *hw_device_ctx = nullptr; + + + avformat_network_init(); + + // 打开输入视频文件 + AVDictionary *options = nullptr; + av_dict_set( &options, "bufsize", "655360", 0 ); + av_dict_set( &options, "rtsp_transport", "tcp", 0 ); + // av_dict_set( &options, "listen_timeout", "30", 0 ); // 单位为s + av_dict_set( &options, "stimeout", "30000000", 0 ); // 单位为 百万分之一秒 + + ///打开输入的流 + ifmt_ctx = avformat_alloc_context(); + int ret = avformat_open_input(&ifmt_ctx, uri.c_str(), nullptr, &options); + if (ret != 0){ + av_log(nullptr, AV_LOG_ERROR, "Couldn't open input stream ! \n"); + goto end_flag ; + } + + //查找流信息 + if (avformat_find_stream_info(ifmt_ctx, nullptr) < 0){ + av_log(nullptr, 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, &decoder, 0); + if (video_index < 0) { + av_log(nullptr, AV_LOG_ERROR, "Cannot find a video stream in the input file ! \n"); + goto end_flag ; + } + + cuvid_dec_name = string(decoder->name) + "_cuvid"; + codec = avcodec_find_decoder_by_name(cuvid_dec_name.c_str()); + if (!codec){ + av_log(nullptr, AV_LOG_ERROR, "Codec not found ! \n"); + goto end_flag ; + } + + //申请AVCodecContext + codec_ctx = avcodec_alloc_context3(codec); + if (!codec_ctx){ + goto end_flag ; + } + + st = ifmt_ctx->streams[video_index]; + if(avcodec_parameters_to_context(codec_ctx, st->codecpar) < 0){ + goto end_flag ; + } + + { + av_log(nullptr, AV_LOG_INFO, "path: %s \n", ifmt_ctx->url); + av_log(nullptr, AV_LOG_INFO, "format: %s \n", ifmt_ctx->iformat->name); + const char* profile = avcodec_profile_name(codec_ctx->codec_id, codec_ctx->profile); + av_log(nullptr, AV_LOG_INFO, "codec: %s(%s) \n", decoder->name, profile); + const char* pix_fmt_name = av_get_pix_fmt_name(codec_ctx->pix_fmt); + av_log(nullptr, AV_LOG_INFO, "pix_fmt_name: %s \n", pix_fmt_name); + av_log(nullptr, AV_LOG_INFO, "width x height: %dX%d \n", st->codecpar->width, st->codecpar->height); + + av_log(NULL, AV_LOG_INFO, "frame_rate: %1.0f ", av_q2d(st->r_frame_rate)); + av_log(NULL, AV_LOG_INFO, " --> reference PPS: %f ms\n", 1/av_q2d(st->r_frame_rate) * 1000); + + } + + // 设置解码器管理器的像素格式回调函数 + codec_ctx->get_format = get_hw_format; + + hw_device_ctx = pCtxMgr->getCuCtx(gpuid); + if(nullptr == hw_device_ctx){ + av_log(nullptr, AV_LOG_ERROR, "create CUDA context failed ! \n"); + goto end_flag ; + } + codec_ctx->hw_device_ctx = av_buffer_ref(hw_device_ctx); + if (nullptr == codec_ctx->hw_device_ctx){ + goto end_flag ; + } + + // 打开解码器流 + av_dict_set( &op, "gpu", gpuid, 0 ); + if (avcodec_open2(codec_ctx, codec, &op) < 0) { + av_log(nullptr, AV_LOG_ERROR, "Failed to open codec for stream ! \n"); + goto end_flag ; + } + + s_time = get_cur_time(); + start_time = get_cur_time(); + pkt = av_packet_alloc(); + while (av_read_frame(ifmt_ctx, pkt) >= 0){ + end_time = get_cur_time(); + sum ++ ; + sep ++ ; + if(end_time - start_time > 1000){ + avg_time = double(end_time - start_time) / sep; + start_time = get_cur_time(); + sep = 0; + av_log(nullptr, AV_LOG_INFO, "PPS: %f ms\n", avg_time); + } + av_packet_unref(pkt); + } + + e_time = get_cur_time(); + avg_time = double(e_time - s_time) / sum; + av_log(nullptr, AV_LOG_INFO, "TOOTAL PPS: %f ms\n", avg_time); + +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 (pkt != nullptr){ + av_packet_free(&pkt); + } +} \ No newline at end of file diff --git a/check_tool/check_tool.h b/check_tool/check_tool.h new file mode 100644 index 0000000..ab31582 --- /dev/null +++ b/check_tool/check_tool.h @@ -0,0 +1,5 @@ +#include + +using namespace std; + +void evalQuality(const string& uri, const char* gpuid); \ No newline at end of file diff --git a/check_tool/main.cpp b/check_tool/main.cpp new file mode 100644 index 0000000..3b981e4 --- /dev/null +++ b/check_tool/main.cpp @@ -0,0 +1,61 @@ +#include"check_tool.h" + +#include + +#include + +using namespace std; + + +#define checkCudaErrors(S) do {CUresult status; \ + status = S; \ + if (status != CUDA_SUCCESS ) {std::cout << __LINE__ <<" checkCudaErrors - status = " << status << std::endl; \ + exit(EXIT_FAILURE);}\ + } 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; + + checkCudaErrors(cuDeviceGetAttribute(&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, dev)); + checkCudaErrors(cuDeviceGetAttribute(&minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, dev)); + + checkCudaErrors( cuDeviceGetName(devName, sizeof( devName ), dev) ); + + 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(int argc, char *argv[]) { + printf("start \n"); + if (argc != 3) { + fprintf(stderr, "./xxx uri gpu_id\n"); + return -1; + } + + char* uri = argv[1]; + char* gpuid = argv[2]; + + CheckCUDAProperty(atoi(gpuid)); + + evalQuality(uri,gpuid); + + return 0; +} \ No newline at end of file diff --git a/src/FFCuContextManager.cpp b/src/FFCuContextManager.cpp index 169cf29..8f5b09a 100644 --- a/src/FFCuContextManager.cpp +++ b/src/FFCuContextManager.cpp @@ -19,7 +19,7 @@ AVBufferRef *FFCuContextManager::getCuCtx(string gpuid) // 初始化硬件解码器 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."; + av_log(nullptr, AV_LOG_ERROR, "Failed to create specified HW device ! \n"); return nullptr; } ctxMap[gpuid] = hw_device_ctx; diff --git a/src/FFNvDecoder.cpp b/src/FFNvDecoder.cpp index d491a17..b9885cc 100644 --- a/src/FFNvDecoder.cpp +++ b/src/FFNvDecoder.cpp @@ -1,12 +1,9 @@ #include "FFNvDecoder.h" -#include #include #include #include -#include - #include "FFCuContextManager.h" using namespace std; @@ -24,7 +21,7 @@ static AVPixelFormat get_hw_format(AVCodecContext *avctx, const AVPixelFormat *p return *p; } - //cout << "Failed to get HW surface format"; + av_log(nullptr, AV_LOG_ERROR, "Failed to get HW surface format. \n"); return AV_PIX_FMT_NONE; } @@ -86,13 +83,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(nullptr, 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(nullptr, AV_LOG_ERROR, "Cannot find input stream information ! \n"); return false; } @@ -100,7 +97,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(nullptr, AV_LOG_ERROR, "Cannot find a video stream in the input file ! \n"); return false; } @@ -121,7 +118,13 @@ 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)); + + AVBufferRef *hw_device_ctx = pCtxMgr->getCuCtx(gpuid); + if(nullptr == hw_device_ctx){ + av_log(nullptr, AV_LOG_ERROR, "create CUDA context failed ! \n"); + return false; + } + avctx->hw_device_ctx = av_buffer_ref(hw_device_ctx); if (nullptr == avctx->hw_device_ctx) { return false; @@ -130,9 +133,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(nullptr, AV_LOG_ERROR, "Failed to open codec for stream ! \n"); return false; } @@ -162,14 +165,12 @@ void FFNvDecoder::start(){ static long long get_cur_time(){ // 获取操作系统当前时间点(精确到微秒) - chrono::time_point tpMicro - = chrono::time_point_cast(chrono::system_clock::now()); + 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; + time_t currentTime = tpMicro.time_since_epoch().count(); - return currentTime; + return (long long )currentTime; } void FFNvDecoder::decode_thread() @@ -208,14 +209,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(nullptr, AV_LOG_ERROR, "Failed to read frame! \n"); break; } @@ -234,19 +230,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(nullptr, AV_LOG_ERROR, "%s - Failed to send pkt: %d \n",name,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(nullptr, AV_LOG_ERROR, "%s - Failed to receive frame: %d \n",name,result); continue; } @@ -255,6 +248,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 +267,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(nullptr, AV_LOG_INFO, "%s - decode thread exited. \n",name); } void FFNvDecoder::decode_finished() @@ -289,7 +292,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 +305,8 @@ void FFNvDecoder::post_decode_thread() mFrameQueue.addHead(); } - - cout << "post decode thread exited." << endl; + + av_log(nullptr, AV_LOG_INFO, "post decode thread exited. \n"); } void FFNvDecoder::close() @@ -338,12 +341,16 @@ bool FFNvDecoder::isFinished() return m_bFinished; } +bool FFNvDecoder::isPausing(){ + return m_bPause; +} + bool FFNvDecoder::getResolution( int &width, int &height ) { - if (avctx != nullptr) + if (stream != nullptr && stream->codecpar != nullptr) { - width = avctx->width; - height = avctx->height; + width = stream->codecpar->width; + height = stream->codecpar->height; return true; } @@ -363,4 +370,145 @@ void FFNvDecoder::resume() void FFNvDecoder::setDecKeyframe(bool bKeyframe) { m_dec_keyframe = bKeyframe; -} \ No newline at end of file +} + +int FFNvDecoder::getCachedQueueLength(){ + return mFrameQueue.length(); +} + +FFImgInfo* FFNvDecoder::snapshot(const string& uri){ + + AVFormatContext* ifmt_ctx = nullptr; + 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 = nullptr; + int numBytes = 0; + + FFImgInfo* imgInfo = nullptr; + + + avformat_network_init(); + + // 打开输入视频文件 + AVDictionary *options = nullptr; + av_dict_set( &options, "bufsize", "655360", 0 ); + av_dict_set( &options, "rtsp_transport", "tcp", 0 ); + // av_dict_set( &options, "listen_timeout", "30", 0 ); // 单位为s + av_dict_set( &options, "stimeout", "30000000", 0 ); // 单位为 百万分之一秒 + + ///打开输入的流 + ifmt_ctx = avformat_alloc_context(); + int ret = avformat_open_input(&ifmt_ctx, uri.c_str(), nullptr, &options); + if (ret != 0){ + av_log(nullptr, AV_LOG_ERROR, "Couldn't open input stream ! \n"); + goto end_flag ; + } + + //查找流信息 + if (avformat_find_stream_info(ifmt_ctx, nullptr) < 0){ + av_log(nullptr, 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, nullptr, 0); + + st = ifmt_ctx->streams[video_index]; + + //找到解码器 + codec = avcodec_find_decoder(st->codecpar->codec_id); + if (!codec){ + av_log(nullptr, 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, nullptr) < 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, nullptr, nullptr, nullptr); + + 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(nullptr, AV_LOG_ERROR, "Failed to receive frame: %d \n", ret); + av_packet_unref(pkt); + 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; + } + } + + av_packet_unref(pkt); + } + +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; + } +} 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/Makefile b/src/Makefile index b3fe018..f5ae7f7 100644 --- a/src/Makefile +++ b/src/Makefile @@ -2,14 +2,11 @@ XX = g++ NVCC = nvcc - -DEFS= -DPOST_USE_RABBITMQ - -PROJECT_ROOT= /home/cmhu/FFNvDecoder +PROJECT_ROOT= /mnt/e/fiss/FFNvDecoder DEPEND_DIR = $(PROJECT_ROOT)/bin SRC_ROOT = $(PROJECT_ROOT)/src -CUDA_ROOT = /usr/local/cuda-11.7 +CUDA_ROOT = /usr/local/cuda TARGET= $(DEPEND_DIR)/lib/test @@ -21,12 +18,13 @@ INCLUDE= -I $(DEPEND_DIR)/include \ -I $(SRC_ROOT)\ LIBSPATH= -L $(DEPEND_DIR)/lib -lavformat -lavcodec -lswscale -lavutil -lavfilter -lswresample -lavdevice \ - -L $(CUDA_ROOT)/lib64 -lcuda -lcudart -lnvcuvid -lcurand -lcublas -lnvjpeg \ + -L $(CUDA_ROOT)/lib64 -lcudart -lcurand -lcublas -lnvjpeg \ + -L /usr/lib/wsl/lib -lcuda -lnvcuvid\ -CFLAGS= -g -fPIC -O0 $(DEFS) $(INCLUDE) -pthread -lrt -lz -std=c++11 -fvisibility=hidden -Wl,-Bsymbolic -ldl +CFLAGS= -g -fPIC -O0 $(INCLUDE) -pthread -lrt -lz -std=c++11 -fvisibility=hidden -Wl,-Bsymbolic -ldl # -DUNICODE -D_UNICODE -NFLAGS_LIB=-g -c $(DEFS) -shared -Xcompiler -fPIC -Xcompiler -fvisibility=hidden +NFLAGS_LIB=-g -c -shared -Xcompiler -fPIC -Xcompiler -fvisibility=hidden NFLAGS = $(NFLAGS_LIB) $(INCLUDE) -std=c++11 SRCS:=$(wildcard $(SRC_ROOT)/*.cpp) diff --git a/src/common/inc/helper_cuda_drvapi.h b/src/common/inc/helper_cuda_drvapi.h index 76eacb5..ffca8e8 100644 --- a/src/common/inc/helper_cuda_drvapi.h +++ b/src/common/inc/helper_cuda_drvapi.h @@ -218,7 +218,8 @@ inline int gpuGetMaxGflopsDeviceIdDRV() // Find the best major SM Architecture GPU device while (current_device < device_count) { - checkCudaErrors(cuDeviceComputeCapability(&major, &minor, current_device)); + checkCudaErrors(cuDeviceGetAttribute(&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, current_device)); + checkCudaErrors(cuDeviceGetAttribute(&minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, current_device)); if (major > 0 && major < 9999) { @@ -239,7 +240,9 @@ inline int gpuGetMaxGflopsDeviceIdDRV() checkCudaErrors(cuDeviceGetAttribute(&clockRate, CU_DEVICE_ATTRIBUTE_CLOCK_RATE, current_device)); - checkCudaErrors(cuDeviceComputeCapability(&major, &minor, current_device)); + + checkCudaErrors(cuDeviceGetAttribute(&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, current_device)); + checkCudaErrors(cuDeviceGetAttribute(&minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, current_device)); int computeMode; getCudaAttribute(&computeMode, CU_DEVICE_ATTRIBUTE_COMPUTE_MODE, current_device); @@ -317,7 +320,9 @@ inline int gpuGetMaxGflopsGLDeviceIdDRV() while (current_device < device_count) { checkCudaErrors(cuDeviceGetName(deviceName, 256, current_device)); - checkCudaErrors(cuDeviceComputeCapability(&major, &minor, current_device)); + + checkCudaErrors(cuDeviceGetAttribute(&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, current_device)); + checkCudaErrors(cuDeviceGetAttribute(&minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, current_device)); #if CUDA_VERSION >= 3020 checkCudaErrors(cuDeviceGetAttribute(&bTCC, CU_DEVICE_ATTRIBUTE_TCC_DRIVER, current_device)); @@ -369,7 +374,9 @@ inline int gpuGetMaxGflopsGLDeviceIdDRV() checkCudaErrors(cuDeviceGetAttribute(&clockRate, CU_DEVICE_ATTRIBUTE_CLOCK_RATE, current_device)); - checkCudaErrors(cuDeviceComputeCapability(&major, &minor, current_device)); + + checkCudaErrors(cuDeviceGetAttribute(&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, current_device)); + checkCudaErrors(cuDeviceGetAttribute(&minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, current_device)); #if CUDA_VERSION >= 3020 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 checkCudaErrors(cuDeviceGet(&cuDevice, devID)); checkCudaErrors(cuDeviceGetName(name, 100, cuDevice)); - checkCudaErrors(cuDeviceComputeCapability(&major, &minor, devID)); + + checkCudaErrors(cuDeviceGetAttribute(&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, devID)); + checkCudaErrors(cuDeviceGetAttribute(&minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, devID)); if ((major > major_version) || (major == major_version && minor >= minor_version)) diff --git a/src/main.cpp b/src/main.cpp index 3f4b14f..1df4833 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -54,7 +54,7 @@ void postDecoded(const void * userPtr, AVFrame * gpuFrame){ return; } - string path = "/home/cmhu/data/" + decoder->getName() + "/" + to_string(sum) + ".jpg"; + string path = "/mnt/f/fiss/data/" + decoder->getName() + "/" + to_string(sum) + ".jpg"; saveJpeg(path.c_str(), pHwRgb[0], gpuFrame->width, gpuFrame->height, stream[0]); // 验证 CUDAToRGB } } else if (decoder->getName() == "dec2") @@ -79,7 +79,7 @@ void postDecoded(const void * userPtr, AVFrame * gpuFrame){ return; } - string path = "/home/cmhu/data/" + decoder->getName() + "/" + to_string(sum) + ".jpg"; + string path = "/mnt/f/fiss/data/" + decoder->getName() + "/" + to_string(sum) + ".jpg"; saveJpeg(path.c_str(), pHwRgb[1], gpuFrame->width, gpuFrame->height, stream[1]); // 验证 CUDAToRGB } } @@ -94,14 +94,10 @@ int count_std = 100; static long long get_cur_time(){ // 获取操作系统当前时间点(精确到微秒) - chrono::time_point tpMicro - = chrono::time_point_cast(chrono::system_clock::now()); + 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; + return tpMicro.time_since_epoch().count(); } static int sum = 0; @@ -124,47 +120,52 @@ void postDecoded0(const void * userPtr, AVFrame * gpuFrame){ } 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; - // } - // cout << "帧数:" << sum << endl; - - // if (gpuFrame->format == AV_PIX_FMT_CUDA) - // { - // cudaSetDevice(atoi(decoder->m_cfg.gpuid.c_str())); - // // cout << "gpu id : " << decoder->m_cfg.gpuid.c_str() << endl; - // cudaError_t cudaStatus; - // if(pHwData == nullptr){ - // cuda_common::setColorSpace2( ITU709, 0 ); - // cudaStatus = cudaMalloc((void **)&pHwData, 3 * gpuFrame->width * gpuFrame->height * sizeof(unsigned char)); - // } - // cudaStatus = cuda_common::CUDAToBGR((CUdeviceptr)gpuFrame->data[0],(CUdeviceptr)gpuFrame->data[1], gpuFrame->linesize[0], gpuFrame->linesize[1], pHwData, gpuFrame->width, gpuFrame->height); - // cudaDeviceSynchronize(); - // if (cudaStatus != cudaSuccess) { - // cout << "CUDAToBGR failed !!!" << endl; - // return; - // } - - // string path = "/home/cmhu/data/test/" + to_string(sum) + ".jpg"; - // saveJpeg(path.c_str(), pHwData, gpuFrame->width, gpuFrame->height, nullptr); // 验证 CUDAToRGB - // } + 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; + } + cout << "帧数:" << sum << endl; + + if (gpuFrame->format == AV_PIX_FMT_CUDA) + { + cudaSetDevice(atoi(decoder->m_cfg.gpuid.c_str())); + // cout << "gpu id : " << decoder->m_cfg.gpuid.c_str() << endl; + cudaError_t cudaStatus; + if(pHwData == nullptr){ + cuda_common::setColorSpace2( ITU709, 0 ); + cudaStatus = cudaMalloc((void **)&pHwData, 3 * gpuFrame->width * gpuFrame->height * sizeof(unsigned char)); + } + cudaStatus = cuda_common::CUDAToBGR((CUdeviceptr)gpuFrame->data[0],(CUdeviceptr)gpuFrame->data[1], gpuFrame->linesize[0], gpuFrame->linesize[1], pHwData, gpuFrame->width, gpuFrame->height); + cudaDeviceSynchronize(); + if (cudaStatus != cudaSuccess) { + cout << "CUDAToBGR failed !!!" << endl; + return; + } + + string path = "/mnt/f/fiss/data/" + to_string(sum) + ".jpg"; + saveJpeg(path.c_str(), pHwData, gpuFrame->width, gpuFrame->height, nullptr); // 验证 CUDAToRGB + } } } } +void decode_finished_cbk(const void* userPtr){ + cout << "decode_finish timestamp: " << get_cur_time() << endl; +} + // string test_uri = "rtmp://192.168.10.56:1935/objecteye/1"; // string test_uri = "/home/cmhu/data/output_800x480.mp4"; // string test_uri = "/home/cmhu/data/output_1920x1080.mp4"; // string test_uri = "rtsp://176.10.0.2:8554/stream"; -string test_uri = "/home/cmhu/data2/Street.uvf"; +// string test_uri = "/mnt/f/fiss/test_data/h265.mp4"; +string test_uri = "rtsp://176.10.0.4:8554/stream"; void createDecode(int index){ FFNvDecoderManager* pDecManager = FFNvDecoderManager::getInstance(); @@ -172,15 +173,16 @@ void createDecode(int index){ config.name = "dec" + to_string(index); config.cfg.uri = test_uri; config.cfg.post_decoded_cbk = postDecoded; + config.cfg.decode_finished_cbk = decode_finished_cbk; config.cfg.force_tcp = true; if (index % 2 == 0) { - config.cfg.gpuid = "2"; + config.cfg.gpuid = "0"; } else { - config.cfg.gpuid = "1"; + config.cfg.gpuid = "0"; } FFNvDecoder* decoder = pDecManager->createDecoder(config); @@ -207,7 +209,10 @@ int CheckCUDAProperty( int devId ) int major = 0, minor = 0; CUresult rlt = CUDA_SUCCESS; - rlt = cuDeviceComputeCapability( &major, &minor, dev ); + rlt = cuDeviceGetAttribute(&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, dev); + checkCudaErrors( rlt ); + + rlt = cuDeviceGetAttribute(&minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, dev); checkCudaErrors( rlt ); rlt = cuDeviceGetName( devName, sizeof( devName ), dev ); @@ -225,9 +230,17 @@ int CheckCUDAProperty( int devId ) return 0; } +void logFF(void *, int level, const char *fmt, va_list ap) +{ + vfprintf(stdout, fmt, ap); +} + + int main(){ - CheckCUDAProperty(1); + // av_log_set_callback(&logFF); + + CheckCUDAProperty(0); FFNvDecoderManager* pDecManager = FFNvDecoderManager::getInstance(); @@ -241,17 +254,22 @@ int main(){ config.name = "dec"; config.cfg.uri = test_uri; config.cfg.post_decoded_cbk = postDecoded0; + config.cfg.decode_finished_cbk = decode_finished_cbk; config.cfg.force_tcp = true; - config.cfg.gpuid = "2"; + config.cfg.gpuid = "0"; FFNvDecoder* dec2 = pDecManager->createDecoder(config); if (!dec2) { return 1; } pDecManager->setUserPtr(config.name, dec2); - pDecManager->setDecKeyframe(config.name, true); + // pDecManager->setDecKeyframe(config.name, true); pDecManager->startDecodeByName(config.name); + int w,h; + pDecManager->getResolution(config.name, w,h); + printf( "%s : %dx%d\n", config.name.c_str() , w,h ); + pthread_t m_decode_thread; pthread_create(&m_decode_thread,0, [](void* arg)