diff --git a/.gitignore b/.gitignore index 43dff6d..a9dec06 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ ffmpeg-4.2.2/ -.vscode/ bin/ .idea/ -3rdparty/ \ No newline at end of file +3rdparty/* +src/build/* diff --git a/.vscode/launch.json b/.vscode/launch.json index 517f8c5..4a3c19c 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -2,31 +2,13 @@ "version": "0.2.0", "configurations": [ { - "name": "(gdb) Launch", + "name": "dvpp", "type": "cppdbg", "request": "launch", "program": "${workspaceFolder}/bin/lib/test", "args": ["rtsp://192.168.10.4:8554/street","3", "30012"], "stopAtEntry": false, - "cwd": "${workspaceFolder}/bin/lib", - "environment": [], - "externalConsole": false, - "MIMode": "gdb", - "setupCommands": [ - { - "description": "Enable pretty-printing for gdb", - "text": "-enable-pretty-printing", - "ignoreFailures": true - } - ] - },{ - "name": "ffmpeg", - "type": "cppdbg", - "request": "launch", - "program": "${workspaceFolder}/bin/lib/ffmpeg_g", - "args": ["-vsync","0","-hwaccel","cuvid","-hwaccel_device","1","-c:v","h264_cuvid","-i","rtmp://192.168.10.56:1935/objecteye/116","-c:a","copy","-vf","scale_npp=800:480","-c:v","h264","/mnt/data/cmhu/FFNvDecoder/data/output1.mp4"], - "stopAtEntry": false, - "cwd": "${workspaceFolder}/bin/lib", + "cwd": "${workspaceFolder}/src/build/bin", "environment": [], "externalConsole": false, "MIMode": "gdb", @@ -38,11 +20,11 @@ } ] },{ - "name": "jrtp", + "name": "nvdec", "type": "cppdbg", "request": "launch", - "program": "${workspaceFolder}/bin/lib/jrtp_exe", - "args": ["40030","t"], + "program": "${workspaceFolder}/bin/lib/demo", + "args": ["/mnt/data/cmhu/data/caishenkezhan.mp4","0", "0"], "stopAtEntry": false, "cwd": "${workspaceFolder}/bin/lib", "environment": [], diff --git a/.vscode/settings.json b/.vscode/settings.json index 69283fc..ab95e37 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -62,6 +62,14 @@ "cfenv": "cpp", "cinttypes": "cpp", "__nullptr": "cpp", - "list": "cpp" + "list": "cpp", + "hash_map": "cpp", + "hash_set": "cpp", + "complex": "cpp", + "unordered_set": "cpp", + "regex": "cpp", + "shared_mutex": "cpp", + "variant": "cpp", + "ios": "cpp" } } \ No newline at end of file diff --git a/README.md b/README.md index 4f3dc70..ad6bb4d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -#### ffmpeg编译配置 +#### 基于CUDA的ffmpeg编译配置 1. 安装cuda 2. 安装 nv-codec-headers 支持 cuvid 需要安装 nv-codec-headers, 进入 nv-codec-headers 文件夹后以sudo权限make && make install即可 @@ -11,5 +11,10 @@ --enable-debug --extra-cflags=-g --extra-ldflags=-g --disable-optimizations --disable-stripping ~~~ +#### 普通ffmpeg编译配置 +~~~ +./configure --enable-debug --extra-cflags=-g --extra-ldflags=-g --disable-optimizations --disable-stripping --disable-x86asm --enable-nonfree --disable-vaapi --extra-cflags=-fPIC --enable-shared --enable-pic --enable-ffplay --prefix=../bin +~~~ + #### SDK说明 1. 对外接口主要是 FFNvDecoderManager 类,可支持多个解码器;也可直接使用 FFNvDecoder ,但是不建议,FFNvDecoderManager已经封装了 FFNvDecoder 的接口 \ No newline at end of file diff --git a/build/Makefile b/build/Makefile index 9f642c4..ab75d97 100644 --- a/build/Makefile +++ b/build/Makefile @@ -1,23 +1,24 @@ -XX = g++ +# 项目根目录 +TOP_DIR:=$(patsubst %/, %, $(dir $(abspath $(lastword $(MAKEFILE_LIST))))) +export TOP_DIR -CUDA_ROOT = /usr/local/cuda-11.1 -NVCC = $(CUDA_ROOT)/bin/nvcc - - -PROJECT_ROOT= /mnt/data/cmhu/FFNvDecoder +# 各项目录 +BUILD_DIR:=$(TOP_DIR)/build +BIN_DIR:=$(BUILD_DIR)/bin +export BUILD_DIR -DEPEND_DIR = $(PROJECT_ROOT)/bin -SRC_ROOT = $(PROJECT_ROOT)/src +PROJECT_ROOT= /home/huchunming/FFNvDecoder THIRDPARTY_ROOT = $(PROJECT_ROOT)/3rdparty +export PROJECT_ROOT THIRDPARTY_ROOT +CUDA_ROOT = /usr/local/cuda-11.1 +export CUDA_ROOT -TARGET= $(DEPEND_DIR)/lib/test - - +FFMPEG_DIR = $(PROJECT_ROOT)/bin SPDLOG_ROOT = $(THIRDPARTY_ROOT)/spdlog-1.9.2/release -JRTP_ROOT = $(THIRDPARTY_ROOT)/jrtp_export -CURL_ROOT = $(THIRDPARTY_ROOT)/curl/bin +#编译器 +CXX:=g++ INCLUDE= -I $(DEPEND_DIR)/include \ -I $(CUDA_ROOT)/include \ @@ -37,34 +38,40 @@ LIBSPATH= -L $(DEPEND_DIR)/lib -lavformat -lavcodec -lswscale -lavutil -lavfilte -L $(JRTP_ROOT)/jrtplib/lib -l:libjrtp.a \ -L $(CURL_ROOT)/lib -l:libcurl.a \ -CFLAGS= -g -fPIC -O0 $(INCLUDE) -pthread -lrt -lz -std=c++11 -fvisibility=hidden -Wl,-Bsymbolic -ldl - # -DUNICODE -D_UNICODE +export CXX INCS MACROS LIBS -NFLAGS_LIB=-g -c -shared -Xcompiler -fPIC -Xcompiler -fvisibility=hidden -NFLAGS = $(NFLAGS_LIB) $(INCLUDE) -std=c++11 +MACROS:= -DUSE_DVPP -SRCS:=$(wildcard $(SRC_ROOT)/*.cpp) \ - $(wildcard $(SRC_ROOT)/gb28181/*.cpp) -OBJS = $(patsubst %.cpp, %.o, $(notdir $(SRCS))) +# 各个模块 +MODULES:= dvpp interface demo -CU_SOURCES = $(wildcard ${SRC_ROOT}/*.cu) -CU_OBJS = $(patsubst %.cu, %.o, $(notdir $(CU_SOURCES))) +# 各个模块对应的库 +# MODULE_LIBS:=$(BUILD_DIR)/nvdec/lib/nvdec.a\ +# $(BUILD_DIR)/nvdec/lib/gb28181.a\ +# $(BUILD_DIR)/interface/lib/interface.a\ +# 最终目标文件 +TARGET:=$(BIN_DIR)/test -$(TARGET):$(OBJS) $(CU_OBJS) - rm -f $(TARGET) - $(XX) -o $@ $^ $(CFLAGS) $(LIBSPATH) $(LIBS) -Wwrite-strings - rm -f *.o +# 默认最终目标 +.PHONY:all +all:$(TARGET) -%.o:$(SRC_ROOT)/%.cpp - $(XX) $(CFLAGS) -c $< +# 最终目标依赖关系 +$(TARGET):FORCE | $(BIN_DIR) + @for n in $(MODULES); do make -s -f $(TOP_DIR)/$$n/Makefile MODULE=$$n || exit "$$?"; done +# @echo -e "\e[32m""Linking executable $(TARGET)""\e[0m" +#@$(LD) $(LDFLAGS) -o $@ $(MODULE_LIBS) $(LIBS) -%.o:$(SRC_ROOT)/gb28181/%.cpp - $(XX) $(CFLAGS) -c $< +# 若没有bin目录则自动生成 +$(BIN_DIR): + @mkdir -p $@ -%.o:$(SRC_ROOT)/%.cu - @echo "#######################CU_OBJS:$@###############" - $(NVCC) $(NFLAGS) -o $@ $< +# 强制执行命令 +.PHONY:FORCE +FORCE: +# make clean直接删除整个build目录 +.PHONY:clean clean: - rm -f *.o $(TARGET) \ No newline at end of file + @rm -rf $(BUILD_DIR) diff --git a/src/AbstractDecoder.cpp b/src/AbstractDecoder.cpp deleted file mode 100644 index 0e51524..0000000 --- a/src/AbstractDecoder.cpp +++ /dev/null @@ -1,114 +0,0 @@ -#include "AbstractDecoder.h" - -#include "logger.hpp" -#include "GpuRgbMemory.hpp" -#include "cuda_kernels.h" - -#include "utiltools.hpp" - - -FFImgInfo* AbstractDecoder::snapshot(){ - - // 锁住停止队列消耗 - std::lock_guard l(m_snapshot_mutex); - - AVFrame * gpuFrame = nullptr; - - bool bFirst = true; - while(true){ - m_queue_mutex.lock(); - if(mFrameQueue.size() <= 0){ - m_queue_mutex.unlock(); - if(bFirst){ - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - bFirst = false; - continue; - }else{ - // 再进来说明前面已经等了 100 ms - // 100 ms都没有等到解码数据,则退出 - return nullptr; - } - } - - // 队列中数据大于1 - gpuFrame = mFrameQueue.front(); - m_queue_mutex.unlock(); - break; - } - - if (gpuFrame != nullptr && gpuFrame->format == AV_PIX_FMT_CUDA ){ - LOG_DEBUG("decode task: gpuid: {} width: {} height: {}", m_cfg.gpuid, gpuFrame->width, gpuFrame->height); - GpuRgbMemory* gpuMem = new GpuRgbMemory(3, gpuFrame->width, gpuFrame->height, getName(), m_cfg.gpuid , true); - - if (gpuMem->getMem() == nullptr){ - LOG_ERROR("new GpuRgbMemory failed !!!"); - return nullptr; - } - - cudaSetDevice(atoi(m_cfg.gpuid.c_str())); - cuda_common::setColorSpace( ITU_709, 0 ); - cudaError_t cudaStatus = cuda_common::CUDAToBGR((CUdeviceptr)gpuFrame->data[0],(CUdeviceptr)gpuFrame->data[1], gpuFrame->linesize[0], gpuFrame->linesize[1], gpuMem->getMem(), gpuFrame->width, gpuFrame->height); - cudaDeviceSynchronize(); - if (cudaStatus != cudaSuccess) { - LOG_ERROR("CUDAToBGR failed failed !!!"); - return nullptr; - } - - unsigned char * pHwRgb = gpuMem->getMem(); - int channel = gpuMem->getChannel(); - int width = gpuMem->getWidth(); - int height = gpuMem->getHeight(); - - if (pHwRgb != nullptr && channel > 0 && width > 0 && height > 0){ - int nSize = channel * height * width; - - LOG_INFO("channel:{} height:{} width:{}", channel, height, width); - // unsigned char* cpu_data = new unsigned char[nSize]; - - unsigned char* cpu_data = (unsigned char *)av_malloc(nSize * sizeof(unsigned char)); - - cudaMemcpy(cpu_data, pHwRgb, nSize * sizeof(unsigned char), cudaMemcpyDeviceToHost); - cudaDeviceSynchronize(); - - delete gpuMem; - gpuMem = nullptr; - - FFImgInfo* imgInfo = new FFImgInfo(); - imgInfo->dec_name = m_dec_name; - imgInfo->pData = cpu_data; - imgInfo->height = height; - imgInfo->width = width; - imgInfo->timestamp = UtilTools::get_cur_time_ms(); - imgInfo->index = m_index; - - m_index++; - - return imgInfo; - } - - delete gpuMem; - gpuMem = nullptr; - } - - return nullptr; -} - -bool AbstractDecoder::isSnapTime(){ - if(m_snap_time_interval <= 0){ - return false; - } - long cur_time = UtilTools::get_cur_time_ms(); - if(cur_time - m_last_snap_time > m_snap_time_interval){ - return true; - } - return false; -} - -void AbstractDecoder::updateLastSnapTime(){ - m_last_snap_time = UtilTools::get_cur_time_ms(); -} - -void AbstractDecoder::setSnapTimeInterval(long interval){ - m_snap_time_interval = interval; - m_last_snap_time = UtilTools::get_cur_time_ms(); -} \ No newline at end of file diff --git a/src/Makefile.bak b/src/Makefile.bak new file mode 100644 index 0000000..af26493 --- /dev/null +++ b/src/Makefile.bak @@ -0,0 +1,69 @@ +XX = g++ + +CUDA_ROOT = /usr/local/cuda-11.1 +NVCC = $(CUDA_ROOT)/bin/nvcc + + +PROJECT_ROOT= /home/huchunming/FFNvDecoder + +DEPEND_DIR = $(PROJECT_ROOT)/bin +SRC_ROOT = $(PROJECT_ROOT)/src + +TARGET= $(DEPEND_DIR)/lib/test + +THIRDPARTY_ROOT = $(PROJECT_ROOT)/3rdparty +SPDLOG_ROOT = $(THIRDPARTY_ROOT)/spdlog-1.9.2/release +JRTP_ROOT = $(THIRDPARTY_ROOT)/jrtp_export + + +INCLUDE= -I $(DEPEND_DIR)/include \ + -I $(CUDA_ROOT)/include \ + -I $(SRC_ROOT)/common/inc \ + -I $(SRC_ROOT)/common/UtilNPP \ + -I $(SRC_ROOT)\ + -I $(SPDLOG_ROOT)/include \ + -I $(SRC_ROOT)/gb28181 \ + -I $(JRTP_ROOT)/jrtplib/include/jrtplib3 \ + -I $(JRTP_ROOT)/jthread/include/jthread + +LIBSPATH= -L $(DEPEND_DIR)/lib -lavformat -lavcodec -lswscale -lavutil -lavfilter -lswresample -lavdevice \ + -L $(CUDA_ROOT)/lib64 -lcuda -lcudart -lnvcuvid -lcurand -lcublas -lnvjpeg \ + -L $(SPDLOG_ROOT) -l:libspdlog.a \ + -L $(JRTP_ROOT)/jthread/lib -l:libjthread.a \ + -L $(JRTP_ROOT)/jrtplib/lib -l:libjrtp.a + +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)/nvdec/*.cpp) \ + $(wildcard $(SRC_ROOT)/gb28181/*.cpp) \ + $(wildcard $(SRC_ROOT)/dvpp/*.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)/nvdec/%.cpp +# $(XX) $(CFLAGS) -c $< + +%.o:$(SRC_ROOT)/gb28181/%.cpp + $(XX) $(CFLAGS) -c $< + +%.o:$(SRC_ROOT)/dvpp/%.cpp + $(XX) $(CFLAGS) -c $< + +%.o:$(SRC_ROOT)/%.cu + @echo "#######################CU_OBJS:$@###############" + $(NVCC) $(NFLAGS) -o $@ $< + +clean: + rm -f *.o $(TARGET) \ No newline at end of file diff --git a/src/demo/Makefile b/src/demo/Makefile new file mode 100644 index 0000000..a456115 --- /dev/null +++ b/src/demo/Makefile @@ -0,0 +1,80 @@ +# 各项目录 +LIB_DIR:=$(BUILD_DIR)/$(MODULE)/lib +DEP_DIR:=$(BUILD_DIR)/$(MODULE)/.dep +OBJ_DIR:=$(BUILD_DIR)/$(MODULE)/obj +SRC_DIR:=$(TOP_DIR)/$(MODULE) + +# 源文件以及中间目标文件和依赖文件 +SRCS:=$(notdir $(wildcard $(SRC_DIR)/*.cpp)) +OBJS:=$(addprefix $(OBJ_DIR)/, $(patsubst %.cpp, %.o, $(SRCS))) +DEPS:=$(addprefix $(DEP_DIR)/, $(patsubst %.cpp, %.d,a $(SRCS))) + +# 自动生成头文件依赖选项 +DEPFLAGS=-MT $@ -MMD -MP -MF $(DEP_DIR)/$*.d + +DEFS = -DENABLE_DVPP_INTERFACE + +# 最终目标文件 +TARGET:=$(BUILD_DIR)/bin/demo + + +include_dir=-I/usr/local/Ascend/ascend-toolkit/6.3.RC1.alpha001/runtime/include + +lib_dir=-L/usr/lib \ + -L/usr/local/lib \ + -L/usr/local/Ascend/driver/lib64 \ + -L/usr/local/Ascend/ascend-toolkit/6.3.RC1.alpha001/atc/lib64\ + -L/usr/local/Ascend/ascend-toolkit/6.3.RC1.alpha001/runtime/lib64 \ + -L/usr/local/Ascend/ascend-toolkit/6.3.RC1.alpha001/runtime/lib64/stub \ + -L/usr/local/Ascend/ascend-toolkit/6.3.RC1.alpha001/lib64 \ + -L/usr/local/Ascend/driver/lib64/driver + +lib=-lacl_dvpp -lascendcl -lmmpa -lglog -lgflags -lpthread -lz -lacl_dvpp_mpi -lruntime -lascendalog -lc_sec -lmsprofiler -lgert -lge_executor -lge_common \ + -lgraph -lascend_protobuf -lprofapi -lerror_manager -lexe_graph -lregister -lplatform + +INCLUDE= -I $(TOP_DIR)/interface \ + +LIBSPATH= -L $(BUILD_DIR)/interface/lib -l:interface.a \ + -L $(BUILD_DIR)/dvpp/lib -l:dvpp.a + +CXXFLAGS= -g -O0 -fPIC $(INCLUDE) $(include_dir) $(LIBSPATH) $(INCS) $(LIBS) $(lib_dir) $(lib) $(DEFS) -lpthread -lrt -lz -fexceptions -std=c++11 -fvisibility=hidden -Wl,-Bsymbolic -ldl + # -DUNICODE -D_UNICODE + +# 默认最终目标 +.PHONY:all +all:$(TARGET) + +# 生成最终目标 +$(TARGET): $(OBJS) | $(LIB_DIR) + @echo -e "\e[32m""Linking static library $(TARGET)""\e[0m" + @echo -e "$(CXX) -o $@ $^ $(DEPFLAGS) $(CXXFLAGS) $(MACROS)" + $(CXX) -o $@ $^ $(DEPFLAGS) $(CXXFLAGS) $(MACROS) + +# 若没有lib目录则自动生成 +$(LIB_DIR): + @mkdir -p $@ + +# 生成中间目标文件 +$(OBJ_DIR)/%.o:$(SRC_DIR)/%.cpp $(DEP_DIR)/%.d | $(OBJ_DIR) $(DEP_DIR) + @echo -e "\e[33m""Building object $@""\e[0m" + @echo -e "$(CXX) -c $(DEPFLAGS) $(CXXFLAGS) -o $@ $<" + $(CXX) -c $(DEPFLAGS) $(CXXFLAGS) -o $@ $< + +# 若没有obj目录则自动生成 +$(OBJ_DIR): + @mkdir -p $@ + +# 若没有.dep目录则自动生成 +$(DEP_DIR): + @mkdir -p $@ + +# 依赖文件会在生成中间文件的时候自动生成,这里只是为了防止报错 +$(DEPS): + +# 引入中间目标文件头文件依赖关系 +include $(wildcard $(DEPS)) + +# 直接删除组件build目录 +.PHONY:clean +clean: + @rm -rf $(BUILD_DIR)/$(MODULE) diff --git a/src/demo/Makefile.dvpp b/src/demo/Makefile.dvpp new file mode 100644 index 0000000..a456115 --- /dev/null +++ b/src/demo/Makefile.dvpp @@ -0,0 +1,80 @@ +# 各项目录 +LIB_DIR:=$(BUILD_DIR)/$(MODULE)/lib +DEP_DIR:=$(BUILD_DIR)/$(MODULE)/.dep +OBJ_DIR:=$(BUILD_DIR)/$(MODULE)/obj +SRC_DIR:=$(TOP_DIR)/$(MODULE) + +# 源文件以及中间目标文件和依赖文件 +SRCS:=$(notdir $(wildcard $(SRC_DIR)/*.cpp)) +OBJS:=$(addprefix $(OBJ_DIR)/, $(patsubst %.cpp, %.o, $(SRCS))) +DEPS:=$(addprefix $(DEP_DIR)/, $(patsubst %.cpp, %.d,a $(SRCS))) + +# 自动生成头文件依赖选项 +DEPFLAGS=-MT $@ -MMD -MP -MF $(DEP_DIR)/$*.d + +DEFS = -DENABLE_DVPP_INTERFACE + +# 最终目标文件 +TARGET:=$(BUILD_DIR)/bin/demo + + +include_dir=-I/usr/local/Ascend/ascend-toolkit/6.3.RC1.alpha001/runtime/include + +lib_dir=-L/usr/lib \ + -L/usr/local/lib \ + -L/usr/local/Ascend/driver/lib64 \ + -L/usr/local/Ascend/ascend-toolkit/6.3.RC1.alpha001/atc/lib64\ + -L/usr/local/Ascend/ascend-toolkit/6.3.RC1.alpha001/runtime/lib64 \ + -L/usr/local/Ascend/ascend-toolkit/6.3.RC1.alpha001/runtime/lib64/stub \ + -L/usr/local/Ascend/ascend-toolkit/6.3.RC1.alpha001/lib64 \ + -L/usr/local/Ascend/driver/lib64/driver + +lib=-lacl_dvpp -lascendcl -lmmpa -lglog -lgflags -lpthread -lz -lacl_dvpp_mpi -lruntime -lascendalog -lc_sec -lmsprofiler -lgert -lge_executor -lge_common \ + -lgraph -lascend_protobuf -lprofapi -lerror_manager -lexe_graph -lregister -lplatform + +INCLUDE= -I $(TOP_DIR)/interface \ + +LIBSPATH= -L $(BUILD_DIR)/interface/lib -l:interface.a \ + -L $(BUILD_DIR)/dvpp/lib -l:dvpp.a + +CXXFLAGS= -g -O0 -fPIC $(INCLUDE) $(include_dir) $(LIBSPATH) $(INCS) $(LIBS) $(lib_dir) $(lib) $(DEFS) -lpthread -lrt -lz -fexceptions -std=c++11 -fvisibility=hidden -Wl,-Bsymbolic -ldl + # -DUNICODE -D_UNICODE + +# 默认最终目标 +.PHONY:all +all:$(TARGET) + +# 生成最终目标 +$(TARGET): $(OBJS) | $(LIB_DIR) + @echo -e "\e[32m""Linking static library $(TARGET)""\e[0m" + @echo -e "$(CXX) -o $@ $^ $(DEPFLAGS) $(CXXFLAGS) $(MACROS)" + $(CXX) -o $@ $^ $(DEPFLAGS) $(CXXFLAGS) $(MACROS) + +# 若没有lib目录则自动生成 +$(LIB_DIR): + @mkdir -p $@ + +# 生成中间目标文件 +$(OBJ_DIR)/%.o:$(SRC_DIR)/%.cpp $(DEP_DIR)/%.d | $(OBJ_DIR) $(DEP_DIR) + @echo -e "\e[33m""Building object $@""\e[0m" + @echo -e "$(CXX) -c $(DEPFLAGS) $(CXXFLAGS) -o $@ $<" + $(CXX) -c $(DEPFLAGS) $(CXXFLAGS) -o $@ $< + +# 若没有obj目录则自动生成 +$(OBJ_DIR): + @mkdir -p $@ + +# 若没有.dep目录则自动生成 +$(DEP_DIR): + @mkdir -p $@ + +# 依赖文件会在生成中间文件的时候自动生成,这里只是为了防止报错 +$(DEPS): + +# 引入中间目标文件头文件依赖关系 +include $(wildcard $(DEPS)) + +# 直接删除组件build目录 +.PHONY:clean +clean: + @rm -rf $(BUILD_DIR)/$(MODULE) diff --git a/src/demo/Makefile.o.nvdec b/src/demo/Makefile.o.nvdec new file mode 100644 index 0000000..91b0cac --- /dev/null +++ b/src/demo/Makefile.o.nvdec @@ -0,0 +1,78 @@ +# 各项目录 +LIB_DIR:=$(BUILD_DIR)/$(MODULE)/lib +DEP_DIR:=$(BUILD_DIR)/$(MODULE)/.dep +OBJ_DIR:=$(BUILD_DIR)/$(MODULE)/obj +SRC_DIR:=$(TOP_DIR)/$(MODULE) + +# 源文件以及中间目标文件和依赖文件 +SRCS:=$(notdir $(wildcard $(SRC_DIR)/*.cpp)) +OBJS:=$(addprefix $(OBJ_DIR)/, $(patsubst %.cpp, %.o, $(SRCS))) +DEPS:=$(addprefix $(DEP_DIR)/, $(patsubst %.cpp, %.d,a $(SRCS))) + +# 自动生成头文件依赖选项 +DEPFLAGS=-MT $@ -MMD -MP -MF $(DEP_DIR)/$*.d + +# 最终目标文件 +TARGET:=/mnt/data/cmhu/FFNvDecoder/bin/lib/demo + + +JRTP_ROOT = $(THIRDPARTY_ROOT)/jrtp_export + +INCLUDE= -I $(TOP_DIR)/interface \ + -I $(TOP_DIR)/nvdec \ + -I $(TOP_DIR)/gb28181 \ + -I $(CUDA_ROOT)/include \ + -I $(TOP_DIR)/common/inc \ + -I $(TOP_DIR)/common/UtilNPP \ + -I $(TOP_DIR)/ \ + -I $(JRTP_ROOT)/jrtplib/include/jrtplib3 \ + -I $(JRTP_ROOT)/jthread/include/jthread + +LIBSPATH= -L $(BUILD_DIR)/interface/lib -l:interface.a \ + -L $(BUILD_DIR)/nvdec/lib -l:nvdec.a \ + -L $(BUILD_DIR)/gb28181/lib -l:gb28181.a \ + -L $(CUDA_ROOT)/lib64 -lcuda -lcudart -lnvcuvid -lcurand -lcublas -lnvjpeg \ + -L $(JRTP_ROOT)/jthread/lib -l:libjthread.a \ + -L $(JRTP_ROOT)/jrtplib/lib -l:libjrtp.a + +CXXFLAGS= -g -O0 -fPIC $(INCLUDE) $(LIBSPATH) $(INCS) $(LIBS) $(MACROS) -lpthread -lrt -lz -fexceptions -std=c++11 -fvisibility=hidden -Wl,-Bsymbolic -ldl -Wwrite-strings + # -DUNICODE -D_UNICODE + +# 默认最终目标 +.PHONY:all +all:$(TARGET) + +# 生成最终目标 +$(TARGET): $(OBJS) | $(LIB_DIR) + @echo -e "\e[32m""Linking static library $(TARGET)""\e[0m" + @echo -e "$(CXX) -o $@ $^ $(DEPFLAGS) $(CXXFLAGS) $(LIBSPATH) $(MACROS)" + $(CXX) -o $@ $^ $(DEPFLAGS) $(CXXFLAGS) $(LIBSPATH) $(MACROS) + +# 若没有lib目录则自动生成 +$(LIB_DIR): + @mkdir -p $@ + +# 生成中间目标文件 +$(OBJ_DIR)/%.o:$(SRC_DIR)/%.cpp $(DEP_DIR)/%.d | $(OBJ_DIR) $(DEP_DIR) + @echo -e "\e[33m""Building object $@""\e[0m" + @echo -e "$(CXX) -c $(DEPFLAGS) $(CXXFLAGS) -o $@ $<" + $(CXX) -c $(DEPFLAGS) $(CXXFLAGS) -o $@ $< + +# 若没有obj目录则自动生成 +$(OBJ_DIR): + @mkdir -p $@ + +# 若没有.dep目录则自动生成 +$(DEP_DIR): + @mkdir -p $@ + +# 依赖文件会在生成中间文件的时候自动生成,这里只是为了防止报错 +$(DEPS): + +# 引入中间目标文件头文件依赖关系 +include $(wildcard $(DEPS)) + +# 直接删除组件build目录 +.PHONY:clean +clean: + @rm -rf $(BUILD_DIR)/$(MODULE) diff --git a/src/main.cpp b/src/demo/main_dvpp.cpp index bfc1241..f6e2ca2 100644 --- a/src/main.cpp +++ b/src/demo/main_dvpp.cpp @@ -1,15 +1,7 @@ -#include "FFNvDecoderManager.h" #include - -#include "cuda_kernels.h" - -#include "NvJpegEncoder.h" - #include #include - #include - #include #include "FFSaveImg.h" @@ -23,7 +15,8 @@ #include "arpa/inet.h" #endif -#include "utiltools.hpp" +#include "../interface/FFNvDecoderManager.h" +#include "../interface/utiltools.hpp" #include "curl/curl.h" @@ -89,75 +82,11 @@ unsigned char *pHwRgb[2] = {nullptr, nullptr}; int sum1 = 0; int sum2 = 0; -cudaStream_t stream[2]; string data_home = "/mnt/data/cmhu/tmp/"; -#define checkCudaErrors(S) do {CUresult status; \ - status = S; \ - if (status != CUDA_SUCCESS ) std::cout << __LINE__ <<" checkCudaErrors - status = " << status << std::endl; \ - } while (false) - - -static void gpu_helper(int gpuid) -{ - cudaSetDevice(gpuid); - - // int *dn; - // cudaMalloc((void **)&dn, 1 * sizeof(int)); - size_t free_byte; - size_t total_byte; - - CUresult cuda_status = cuMemGetInfo(&free_byte, &total_byte); - - const char *pStr = nullptr; - if (CUDA_SUCCESS != cuda_status) { - cuGetErrorString(cuda_status, &pStr); - printf("Error: cudaMemGetInfo fails, %s \n", pStr); - return; - } - - double free_db = (double)free_byte; - double total_db = (double)total_byte; - double used_db_1 = (total_db - free_db) / 1024.0 / 1024.0; - - std::cout <<"显存已使用 " << used_db_1 << " MB\n"; - - // cudaFree(dn); -} - -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 = 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 ); - 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; -} static long get_cur_time_ms() { chrono::time_point tpMicro @@ -168,87 +97,15 @@ static long get_cur_time_ms() { /** * 注意: gpuFrame 在解码器设置的显卡上,后续操作要十分注意这一点,尤其是多线程情况 * */ -void postDecoded(const void * userPtr, AVFrame * gpuFrame){ - - // long first_time = get_cur_time_ms(); - // long second_time = 0; - // int a = 1; - // while(true){ - // a = a * 99; - // if(a > 1000000){ - // a = 1; - // } - // second_time = get_cur_time_ms(); - // if(second_time - first_time > 100){ - // break; - // } - // } - // return ; - - // std::this_thread::sleep_for(std::chrono::milliseconds(100)); - +void postDecoded(const void * userPtr, DeviceRgbMemory* devFrame){ AbstractDecoder* decoder = (AbstractDecoder*)userPtr; if (decoder!= nullptr) { - // cout << "decode name: " << decoder->getName() << endl; - - // 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 << "decode successed ✿✿ヽ(°▽°)ノ✿ " << endl; + } - int sum = sum1; - if (decoder->getName() == "dec0") - { - sum1 ++ ; - sum = sum1; - - if (gpuFrame->format == AV_PIX_FMT_CUDA) - { - // cout << "gpuid = " << atoi(decoder->m_cfg.gpuid.c_str()) << endl; - cudaSetDevice(atoi(decoder->m_cfg.gpuid.c_str())); - cudaError_t cudaStatus; - if(pHwRgb[0] == nullptr){ - // cudaStreamCreate(&stream[0]); - cuda_common::setColorSpace( ITU_709, 0 ); - cudaStatus = cudaMalloc((void **)&pHwRgb[0], 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], pHwRgb[0], gpuFrame->width, gpuFrame->height); - cudaDeviceSynchronize(); - if (cudaStatus != cudaSuccess) { - cout << "CUDAToBGR failed !!!" << endl; - return; - } - - string path = data_home + decoder->getName() + ".jpg"; - saveJpeg(path.c_str(), pHwRgb[0], gpuFrame->width, gpuFrame->height, stream[0]); // 验证 CUDAToRGB - } - } else if (decoder->getName() == "dec2") - { - sum2 ++ ; - sum = sum2; - - if (gpuFrame->format == AV_PIX_FMT_CUDA) - { - // cout << "gpuid = " << atoi(decoder->m_cfg.gpuid.c_str()) << endl; - cudaSetDevice(atoi(decoder->m_cfg.gpuid.c_str())); - cudaError_t cudaStatus; - if(pHwRgb[1] == nullptr){ - // cudaStreamCreate(&stream[1]); - cuda_common::setColorSpace( ITU_709, 0 ); - cudaStatus = cudaMalloc((void **)&pHwRgb[1], 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], pHwRgb[1], gpuFrame->width, gpuFrame->height); - cudaDeviceSynchronize(); - if (cudaStatus != cudaSuccess) { - cout << "CUDAToBGR failed !!!" << endl; - return; - } - - string path = data_home + decoder->getName() + ".jpg"; - saveJpeg(path.c_str(), pHwRgb[1], gpuFrame->width, gpuFrame->height, stream[1]); // 验证 CUDAToRGB - } - } + if(devFrame){ + delete devFrame; + devFrame = nullptr; } } @@ -262,9 +119,8 @@ int count_std = 100; static int sum = 0; unsigned char *pHwData = nullptr; -void postDecoded0(const void * userPtr, AVFrame * gpuFrame){ - - std::this_thread::sleep_for(std::chrono::milliseconds(100)); +void postDecoded0(const void * userPtr, DeviceRgbMemory* devFrame){ + // std::this_thread::sleep_for(std::chrono::milliseconds(30000)); AbstractDecoder* decoder = (AbstractDecoder*)userPtr; if (decoder!= nullptr) @@ -286,32 +142,12 @@ void postDecoded0(const void * userPtr, AVFrame * gpuFrame){ // 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 << decoder->getName() << " keyframe: " << gpuFrame->key_frame << " width: " << gpuFrame->width << " height: "<< gpuFrame->height << endl; + cout << decoder->getName() << " keyframe: " << devFrame->isKeyFrame() << " width: " << devFrame->getWidth() << " height: "<< devFrame->getHeight() << 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::setColorSpace( ITU_709, 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 = data_home + decoder->getName() + ".jpg"; - saveJpeg(path.c_str(), pHwData, gpuFrame->width, gpuFrame->height, nullptr); // 验证 CUDAToRGB - } } } } @@ -514,7 +350,9 @@ bool decode_request_stream_cbk(const char* deviceId){ // string test_uri = "/home/cmhu/data/output_1920x1080.mp4"; // string test_uri = "rtsp://176.10.0.2:8554/stream"; // string test_uri = "/mnt/f/fiss/test_data/h265.mp4"; -string test_uri = "rtsp://192.168.10.4:8554/street"; +// string test_uri = "rtsp://176.10.0.4:8554/stream"; +// string test_uri = "rtsp://admin:admin@123456@192.168.60.176:554/cam/realmonitor?channel=1&subtype=0"; +string test_uri = "/home/huchunming/data/woyikewangh265.mp4"; void createDecode(int index, const char* gpu_id){ FFNvDecoderManager* pDecManager = FFNvDecoderManager::getInstance(); @@ -575,6 +413,29 @@ void createGB28181Decode(char* devid, char* gpu_id, int port){ pDecManager->startDecodeByName(config.name); } +void createDvppDecoder(int index, char* devId, int channelId){ + FFNvDecoderManager* pDecManager = FFNvDecoderManager::getInstance(); + MgrDecConfig config; + 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; + config.dec_type = DECODER_TYPE_DVPP; + + config.cfg.gpuid = devId; + + AbstractDecoder* decoder = pDecManager->createDecoder(config); + if (!decoder) + { + cout << "创建解码器失败" << endl; + return ; + } + pDecManager->setPostDecArg(config.name, decoder); + pDecManager->setFinishedDecArg(config.name, decoder); + pDecManager->startDecodeByName(config.name); +} + void logFF(void *, int level, const char *fmt, va_list ap) { vfprintf(stdout, fmt, ap); @@ -583,7 +444,7 @@ void logFF(void *, int level, const char *fmt, va_list ap) int main(int argc, char* argv[]){ - test_uri = argv[1]; + // test_uri = argv[1]; char* gpuid = argv[2]; int port = atoi(argv[3]); char* devId = argv[4]; @@ -591,7 +452,7 @@ int main(int argc, char* argv[]){ // av_log_set_callback(&logFF); - CheckCUDAProperty(atoi(gpuid)); + // CheckCUDAProperty(atoi(gpuid)); pthread_t m_decode_thread; pthread_create(&m_decode_thread,0, @@ -644,6 +505,11 @@ int main(int argc, char* argv[]){ createGB28181Decode(devId, gpuid, port); i++; break; + case 'd': + case 'D': + createDvppDecoder(i, gpuid, 0); + i++; + break; case 'r': case 'R': pDecManager->resumeDecoder("dec0"); diff --git a/src/demo/main_nvdec.cpp1 b/src/demo/main_nvdec.cpp1 new file mode 100644 index 0000000..227bc8a --- /dev/null +++ b/src/demo/main_nvdec.cpp1 @@ -0,0 +1,456 @@ +#include "FFNvDecoderManager.h" +#include + +// #include "cuda_kernels.h" +// #include "NvJpegEncoder.h" + +#include +#include + +#include + +#include + + +#ifdef _WIN32 +#include "Winsock2.h" +#pragma comment(lib, "ws2_32.lib") +#endif + +#ifdef __linux__ +#include "arpa/inet.h" +#endif + +#include "utiltools.hpp" + +#define MIN_RTP_PORT 10000 +#define MAX_RTP_PORT 60000 + +// ȡ MIN_RTP_PORT(10000)~MAX_RTP_PORT(60000)֮�������˿�(ż���������������˿ڿ���) +int allocRtpPort() { + + static int s_rtpPort = MIN_RTP_PORT; + if (MIN_RTP_PORT == s_rtpPort) + { + srand((unsigned int)time(NULL)); + s_rtpPort = MIN_RTP_PORT + (rand() % MIN_RTP_PORT); + } + + if (s_rtpPort % 2) + ++s_rtpPort; + + while (true) + { + s_rtpPort += 2; + s_rtpPort = s_rtpPort >= MAX_RTP_PORT ? MIN_RTP_PORT : s_rtpPort; + + int i = 0; + for (; i < 2; i++) + { + sockaddr_in sRecvAddr; + int s = socket(AF_INET, SOCK_DGRAM, 0); + + sRecvAddr.sin_family = AF_INET; + sRecvAddr.sin_addr.s_addr = htonl(INADDR_ANY); + sRecvAddr.sin_port = htons(s_rtpPort + i); + + int nResult = bind(s, (sockaddr *)&sRecvAddr, sizeof(sRecvAddr)); + if (nResult != 0) + { + break; + } + + nResult = close(s); + if (nResult != 0) + { + printf("closesocket failed:%d\n", nResult); + break; + } + } + + if (i == 2) + break; + } + + return s_rtpPort; +} + + + + + +unsigned char *pHwRgb[2] = {nullptr, nullptr}; + +int sum1 = 0; +int sum2 = 0; + +// cudaStream_t stream[2]; + +string data_home = "/mnt/data/cmhu/tmp/"; + + +// #define checkCudaErrors(S) do {CUresult status; \ +// status = S; \ +// if (status != CUDA_SUCCESS ) std::cout << __LINE__ <<" checkCudaErrors - status = " << status << std::endl; \ +// } while (false) + + +// static void gpu_helper(int gpuid) +// { +// cudaSetDevice(gpuid); + +// // int *dn; +// // cudaMalloc((void **)&dn, 1 * sizeof(int)); + +// size_t free_byte; +// size_t total_byte; + +// CUresult cuda_status = cuMemGetInfo(&free_byte, &total_byte); + +// const char *pStr = nullptr; +// if (CUDA_SUCCESS != cuda_status) { +// cuGetErrorString(cuda_status, &pStr); +// printf("Error: cudaMemGetInfo fails, %s \n", pStr); +// return; +// } + +// double free_db = (double)free_byte; +// double total_db = (double)total_byte; +// double used_db_1 = (total_db - free_db) / 1024.0 / 1024.0; + +// std::cout <<"显存已使用 " << used_db_1 << " MB\n"; + +// // cudaFree(dn); +// } + +// 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 = 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 ); +// 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; +// } + +/** + * 注意: gpuFrame 在解码器设置的显卡上,后续操作要十分注意这一点,尤其是多线程情况 + * */ +static long lastpts = 0; +void postDecoded(const void * userPtr, DeviceRgbMemory * gpuFrame){ + AbstractDecoder* decoder = (AbstractDecoder*)userPtr; + if (decoder!= nullptr) + { + long curpts = UtilTools::get_cur_time_ms(); + cout << decoder->getName() << " " << gpuFrame->getWidth() << "x" << gpuFrame->getHeight() << " " << curpts - lastpts << endl; + lastpts = curpts; + delete gpuFrame; + gpuFrame = nullptr; + + // 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 << "decode successed ✿✿ヽ(°▽°)ノ✿ " << endl; + + // int sum = sum1; + // if (decoder->getName() == "dec0") + // { + // sum1 ++ ; + // sum = sum1; + + // if (gpuFrame->format == AV_PIX_FMT_CUDA) + // { + // // cout << "gpuid = " << atoi(decoder->m_cfg.gpuid.c_str()) << endl; + // cudaSetDevice(atoi(decoder->m_cfg.gpuid.c_str())); + // cudaError_t cudaStatus; + // if(pHwRgb[0] == nullptr){ + // // cudaStreamCreate(&stream[0]); + // cuda_common::setColorSpace( ITU_709, 0 ); + // cudaStatus = cudaMalloc((void **)&pHwRgb[0], 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], pHwRgb[0], gpuFrame->width, gpuFrame->height); + // cudaDeviceSynchronize(); + // if (cudaStatus != cudaSuccess) { + // cout << "CUDAToBGR failed !!!" << endl; + // return; + // } + + // string path = data_home + decoder->getName() + ".jpg"; + // saveJpeg(path.c_str(), pHwRgb[0], gpuFrame->width, gpuFrame->height, stream[0]); // 验证 CUDAToRGB + // } + // } else if (decoder->getName() == "dec2") + // { + // sum2 ++ ; + // sum = sum2; + + // if (gpuFrame->format == AV_PIX_FMT_CUDA) + // { + // // cout << "gpuid = " << atoi(decoder->m_cfg.gpuid.c_str()) << endl; + // cudaSetDevice(atoi(decoder->m_cfg.gpuid.c_str())); + // cudaError_t cudaStatus; + // if(pHwRgb[1] == nullptr){ + // // cudaStreamCreate(&stream[1]); + // cuda_common::setColorSpace( ITU_709, 0 ); + // cudaStatus = cudaMalloc((void **)&pHwRgb[1], 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], pHwRgb[1], gpuFrame->width, gpuFrame->height); + // cudaDeviceSynchronize(); + // if (cudaStatus != cudaSuccess) { + // cout << "CUDAToBGR failed !!!" << endl; + // return; + // } + + // string path = data_home + decoder->getName() + ".jpg"; + // saveJpeg(path.c_str(), pHwRgb[1], gpuFrame->width, gpuFrame->height, stream[1]); // 验证 CUDAToRGB + // } + // } + } +} + +long start_time = 0; +long end_time = 0; +bool count_flag = false; +int count = 0; +int count_std = 100; + + +static int sum = 0; +unsigned char *pHwData = nullptr; + +void postDecoded0(const void * userPtr, DeviceRgbMemory* gpuFrame){ + // std::this_thread::sleep_for(std::chrono::milliseconds(30000)); + + AbstractDecoder* decoder = (AbstractDecoder*)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 = UtilTools::get_cur_time_ms(); + // } + // count++; + // sum ++ ; + // if (count >= count_std) + // { + // // end_time = UtilTools::get_cur_time_ms(); + // // 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 << decoder->getName() << " 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::setColorSpace( ITU_709, 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 = data_home + decoder->getName() + ".jpg"; + // saveJpeg(path.c_str(), pHwData, gpuFrame->width, gpuFrame->height, nullptr); // 验证 CUDAToRGB + // } + // } + } +} + +void decode_finished_cbk(const void* userPtr){ + cout << "当前时间戳: " << UtilTools::get_cur_time_ms() << endl; +} + +bool decode_request_stream_cbk(const char* deviceId){ + cout << "需在此请求流" << endl; + return true; +} + +// 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 = "/mnt/f/fiss/test_data/h265.mp4"; +string test_uri = "rtsp://176.10.0.4:8554/stream"; + +void createDecode(int index, const char* gpu_id){ + FFNvDecoderManager* pDecManager = FFNvDecoderManager::getInstance(); + MgrDecConfig config; + 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; + config.dec_type = DECODER_TYPE_FFMPEG; + + config.cfg.gpuid = gpu_id; + // if (index % 2 == 0) + // { + // config.cfg.gpuid = "0"; + // } + // else + // { + // config.cfg.gpuid = "0"; + // } + + AbstractDecoder* decoder = pDecManager->createDecoder(config); + if (!decoder) + { + return ; + } + pDecManager->setPostDecArg(config.name, decoder); + pDecManager->setFinishedDecArg(config.name, decoder); + pDecManager->startDecodeByName(config.name); +} + +void createGB28181Decode(int index, char* gpu_id, int port){ + FFNvDecoderManager* pDecManager = FFNvDecoderManager::getInstance(); + MgrDecConfig config; + config.name = "dec" + to_string(index); + config.cfg.uri = config.name; + config.cfg.post_decoded_cbk = postDecoded; + config.cfg.decode_finished_cbk = decode_finished_cbk; + config.cfg.request_stream_cbk = decode_request_stream_cbk; + config.cfg.force_tcp = true; + + config.dec_type = DECODER_TYPE_GB28181; + config.cfg.port = port;//allocRtpPort(); + + config.cfg.gpuid = gpu_id; + + AbstractDecoder* decoder = pDecManager->createDecoder(config); + if (!decoder) + { + return ; + } + pDecManager->setPostDecArg(config.name, decoder); + pDecManager->setFinishedDecArg(config.name, decoder); + pDecManager->startDecodeByName(config.name); +} + +void logFF(void *, int level, const char *fmt, va_list ap) +{ + vfprintf(stdout, fmt, ap); +} + + +int main(int argc, char* argv[]){ + + test_uri = "rtsp://admin:admin@123456@192.168.60.176:554/cam/realmonitor?channel=1&subtype=0";//argv[1]; + char* gpuid = argv[2]; + int port = atoi(argv[3]); + cout << test_uri << " gpu_id:" << gpuid << " port:" << port << endl; + + // av_log_set_callback(&logFF); + + // CheckCUDAProperty(atoi(gpuid)); + + pthread_t m_decode_thread; + pthread_create(&m_decode_thread,0, + [](void* arg) + { + // cudaSetDevice(atoi(gpuid)); + while (true) + { + std::this_thread::sleep_for(std::chrono::minutes(1)); + FFNvDecoderManager* pDecManager = FFNvDecoderManager::getInstance(); + int count = pDecManager->count(); + cout << "当前时间:" << UtilTools::get_cur_time_ms() << " 当前运行路数: " << pDecManager->count() << endl; + } + + return (void*)0; + } + ,nullptr); + + + FFNvDecoderManager* pDecManager = FFNvDecoderManager::getInstance(); + int i = 0; + + while (true) + { + int ch = getchar(); + if (ch == 'q') + { + break; + } + + switch (ch) + { + case 'f': + case 'F': + createDecode(i, gpuid); + i++; + break; + case 'g': + case 'G': + createGB28181Decode(i, gpuid, port); + i++; + break; + case 'r': + case 'R': + pDecManager->resumeDecoder("dec0"); + break; + case 'p': + case 'P': + pDecManager->pauseDecoder("dec0"); + break; + + case 'c': + case 'C': + i--; + pDecManager->closeDecoderByName("dec" + to_string(i)); + break; + + case 'i': + case 'I': + { + int w,h; + pDecManager->getResolution("dec0", w,h); + printf( "%s : %dx%d\n", "dec0" , w,h ); + } + break; + + default: + break; + } + + /* code */ + } + + cout << "总共帧数:" << sum << endl; + pDecManager->closeAllDecoder(); +} \ No newline at end of file diff --git a/src/dvpp/CircularQueue.hpp b/src/dvpp/CircularQueue.hpp new file mode 100644 index 0000000..368291c --- /dev/null +++ b/src/dvpp/CircularQueue.hpp @@ -0,0 +1,138 @@ +#ifndef __CIRCULAR_QUEUE_HPP__ +#define __CIRCULAR_QUEUE_HPP__ + +#include +#include +#include +#include + +using namespace std; + + +// 循环队列 +template +class CircularQueue +{ +private: + /* data */ +public: + CircularQueue(); + ~CircularQueue(); + + bool init(vector data); + T getTail(); + void addTail(); + T deQueue(); + T getHead(); + void addHead(); + void clearQueue(); + + int length(); + bool isEmpty(); + +private: + vector base; + atomic front; + atomic rear; + mutex m_mutex; + int max_size; +}; + + +template +CircularQueue::CircularQueue() +{ + front = rear = 0;//头指针和尾指针置为零,队列为空 +} + +template +CircularQueue::~CircularQueue() +{ + base.clear(); + rear = front = 0; +} + +template +bool CircularQueue::init(vector data){ + base = data; + front = rear = 0;//头指针和尾指针置为零,队列为空 + max_size = data.size(); + + return true; +} + +//循环队列的入队 +template +T CircularQueue::getTail() +{ + std::lock_guard l(m_mutex); + //插入一个元素e为Q的新的队尾元素 + if ((rear + 1) % max_size == front) + return nullptr;//队满 + return base[rear];//获取队尾元素 +} + +// 将队尾元素添加到队列中 +template +void CircularQueue::addTail() +{ + std::lock_guard l(m_mutex); + rear = (rear + 1) % max_size;//队尾指针加1 +} + +//循环队列的出队 +template +T CircularQueue::deQueue() +{ + std::lock_guard l(m_mutex); + //删除Q的队头元素,用e返回其值 + if (front == rear) + return nullptr;//队空 + T e = base[front];//保存队头元素 + front = (front + 1) % max_size;//队头指针加1 + return e; +} + +//取循环队列的队头元素 +template +T CircularQueue::getHead() +{ + std::lock_guard l(m_mutex); + //返回Q的队头元素,不修改队头指针 + if (front == rear) + return nullptr;//队列为空,取元素失败 + return base[front]; +} + +template +void CircularQueue::addHead() +{ + std::lock_guard l(m_mutex); + front = (front + 1) % max_size;//队头指针加1 +} + +template +int CircularQueue::length() +{ + std::lock_guard l(m_mutex); + return (rear - front + max_size) % max_size; +} + +template +bool CircularQueue::isEmpty() +{ + std::lock_guard l(m_mutex); + if (front == rear) + return true; + + return false; +} + +template +void CircularQueue::clearQueue() +{ + std::lock_guard l(m_mutex); + rear = front = 0; +} + +#endif \ No newline at end of file diff --git a/src/dvpp/DvppDec.cpp b/src/dvpp/DvppDec.cpp new file mode 100644 index 0000000..1f94c5c --- /dev/null +++ b/src/dvpp/DvppDec.cpp @@ -0,0 +1,426 @@ +#include "DvppDec.h" +#include "DvppSourceManager.h" + +struct Vdec_CallBack_UserData { + uint64_t frameId; + long startTime; + long sendTime; + // void* vdecOutputBuf; + DvppDec* self; + shared_ptr inBufNode; + Vdec_CallBack_UserData() { + frameId = 0; + } +}; + +static const int g_pkt_size = 1024 * 1024; + + DvppDec::DvppDec(){ + m_decode_thread = 0; + } + + DvppDec::~DvppDec(){ + releaseResource(); + } + + bool DvppDec::init_vdpp(DvppDecConfig cfg){ + + m_dec_name = cfg.dec_name; + + LOG_INFO("[{}]- Init device start...", m_dec_name); + + m_dvpp_deviceId = atoi(cfg.dev_id.c_str()); + + if(cfg.codec_id == 0){ + // 66:Baseline,77:Main,>=100:High + if(cfg.profile == 77){ + enType = H264_MAIN_LEVEL; + }else if(cfg.profile < 77){ + enType = H264_BASELINE_LEVEL; + }else{ + enType = H264_HIGH_LEVEL; + } + }else if(cfg.codec_id == 1){ + // h265只有main + enType = H265_MAIN_LEVEL; + }else { + LOG_ERROR("[{}]- codec_id is not supported!", m_dec_name); + return false; + } + + post_decoded_cbk = cfg.post_decoded_cbk; + m_pktQueueptr = cfg.pktQueueptr; + + // DvppSourceManager 创建时包含 aclInit,析构时包含 aclFinalize + DvppSourceManager* pSrcMgr = DvppSourceManager::getInstance(); + m_context = pSrcMgr->getContext(m_dvpp_deviceId); + m_dvpp_channel = pSrcMgr->getChannel(m_dvpp_deviceId); + if(m_dvpp_channel < 0){ + LOG_ERROR("[{}]-该设备channel已经用完了!", m_dec_name); + return false; + } + + do + { + CHECK_AND_BREAK(aclrtSetCurrentContext(m_context), "aclrtSetCurrentContext failed !"); + + int ret = picConverter.init(m_context, m_dec_name); + if(ret != ACL_ERROR_NONE){ + LOG_ERROR("[{}]- acldvppMalloc failed!, ret:{}", m_dec_name, ret); + break; + } + + // queue_size 最小应大于16,否则关键帧之间距离太远的时候会导致回调函数与循环队列卡死 + for (size_t i = 0; i < 20; i++){ + void *vdecInputbuf = nullptr; + ret = acldvppMalloc((void **)&vdecInputbuf, g_pkt_size); + if(ret != ACL_ERROR_NONE){ + LOG_ERROR("[{}]- acldvppMalloc failed!, ret:{}", m_dec_name, ret); + // 析构函数中有对channel 的补救性释放,所以这里可以直接return + return false;; + } + m_vec_vdec.push_back(vdecInputbuf); + } + + if(!m_vdecQueue.init(m_vec_vdec)){ + break; + } + + m_vdec_out_size = cfg.width * cfg.height * 3 / 2; + + LOG_INFO("[{}]- init vdpp success! device:{} channel:{}", m_dec_name, m_dvpp_deviceId, m_dvpp_channel); + return true; + + } while (0); + + LOG_INFO("[{}]- init vdpp failed!", m_dec_name); + // 初始化失败,释放channel + pSrcMgr->releaseChannel(m_dvpp_deviceId, m_dvpp_channel); + return false; +} + +bool DvppDec::start(){ + m_bRunning = true; + + pthread_create(&m_decode_thread,0, + [](void* arg) + { + DvppDec* a=(DvppDec*)arg; + a->decode_thread(); + return (void*)0; + } + ,this); + + return true; +} + +static void *ReportThd(void *arg) +{ + DvppDec *self = (DvppDec *)arg; + if(nullptr != self){ + self->doProcessReport(); + } + return (void *)0; +} + +void DvppDec::doProcessReport(){ + + CHECK_AND_RETURN_NOVALUE(aclrtSetCurrentContext(m_context), "aclrtSetCurrentContext failed"); + // 阻塞等待vdec线程开始 + + int ret; + while (!m_bExitReportThd) { + aclrtProcessReport(1000); + } +} + +static void VdecCallback(acldvppStreamDesc *input, acldvppPicDesc *output, void *pUserData) +{ + Vdec_CallBack_UserData *userData = (Vdec_CallBack_UserData *) pUserData; + if(nullptr != userData){ + DvppDec* self = userData->self; + if(self != nullptr){ + + self->doVdppVdecCallBack(input, output); + } + delete userData; + userData = nullptr; + } +} + +void DvppDec::doVdppVdecCallBack(acldvppStreamDesc *input, acldvppPicDesc *output){ + + CHECK_AND_RETURN_NOVALUE(aclrtSetCurrentContext(m_context), "aclrtSetCurrentContext failed"); + + void *inputDataDev = acldvppGetStreamDescData(input); + void *outputDataDev = acldvppGetPicDescData(output); + uint32_t outputSize = acldvppGetPicDescSize(output); + uint32_t width = acldvppGetPicDescWidth(output); + uint32_t height = acldvppGetPicDescHeight(output); + + + DvppRgbMemory* rgbMem = picConverter.convert2bgr(output, width, height, false); + if(rgbMem != nullptr){ +#ifdef TEST_DECODER + // D2H + if(vdecHostAddr == nullptr){ + CHECK_NOT_RETURN(aclrtMallocHost(&vdecHostAddr, width * height * 3), "aclrtMallocHost failed"); + } + uint32_t data_size = rgbMem->getSize(); + CHECK_AND_RETURN_NOVALUE(aclrtMemcpy(vdecHostAddr, data_size, rgbMem->getMem(), data_size, ACL_MEMCPY_DEVICE_TO_HOST), "D2H aclrtMemcpy failed"); + + // 保存vdec结果 + if(count_frame > 45 && count_frame < 50) + { + string file_name = "./yuv_pic/vdec_out_"+ m_dec_name +".rgb" ; + FILE *outputFile = fopen(file_name.c_str(), "a"); + if(outputFile){ + fwrite(vdecHostAddr, data_size, sizeof(char), outputFile); + fclose(outputFile); + } + } + else if(count_frame > 50 && vdecHostAddr != nullptr){ + CHECK_NOT_RETURN(aclrtFreeHost(vdecHostAddr), "aclrtFreeHost failed"); + vdecHostAddr = nullptr; + } + count_frame++; +#endif + post_decoded_cbk(m_postDecArg, rgbMem); + }else{ + LOG_ERROR("[{}]- convert2bgr failed !", m_dec_name); + } + + acldvppFree((uint8_t*)outputDataDev); + outputDataDev = nullptr; + + m_vdecQueue.addHead(); + + CHECK_AND_RETURN_NOVALUE(acldvppDestroyStreamDesc(input), "acldvppDestroyStreamDesc failed"); + CHECK_AND_RETURN_NOVALUE(acldvppDestroyPicDesc(output), "acldvppDestroyPicDesc failed"); +} + +void DvppDec::close(){ + m_bRunning=false; + + if(m_decode_thread != 0){ + pthread_join(m_decode_thread,0); + } +} + +bool DvppDec::sendVdecEos(aclvdecChannelDesc *vdecChannelDesc){ + // create stream desc + acldvppStreamDesc *streamInputDesc = acldvppCreateStreamDesc(); + if (streamInputDesc == nullptr) { + LOG_ERROR("[{}]- fail to create input stream desc", m_dec_name); + return false; + } + aclError ret = acldvppSetStreamDescEos(streamInputDesc, 1); + if (ret != ACL_SUCCESS) { + LOG_ERROR("[{}]- fail to set eos for stream desc, errorCode = {}", m_dec_name, static_cast(ret)); + (void)acldvppDestroyStreamDesc(streamInputDesc); + return false; + } + + // send vdec eos frame. when all vdec callback are completed, aclvdecSendFrame can be returned. + LOG_INFO("[{}]- send eos", m_dec_name); + ret = aclvdecSendFrame(vdecChannelDesc, streamInputDesc, nullptr, nullptr, nullptr); + if (ret != ACL_SUCCESS) { + LOG_ERROR("[{}]- fail to send eos frame, ret={}", m_dec_name, ret); + (void)acldvppDestroyStreamDesc(streamInputDesc); + return false; + } + (void)acldvppDestroyStreamDesc(streamInputDesc); + + return true; +} + +void DvppDec::releaseResource(){ + for(int i = 0; i < m_vec_vdec.size(); i++){ + if(m_vec_vdec[i] != nullptr){ + acldvppFree(m_vec_vdec[i]); + m_vec_vdec[i] = nullptr; + } + } + m_vec_vdec.clear(); + + DvppSourceManager* pSrcMgr = DvppSourceManager::getInstance(); + pSrcMgr->releaseChannel(m_dvpp_deviceId, m_dvpp_channel); +} + +void DvppDec::decode_thread(){ + + long startTime = UtilTools::get_cur_time_ms(); + + int ret = -1; + + // dvpp解码参数 + CHECK_AND_RETURN_NOVALUE(aclrtSetCurrentContext(m_context), "aclrtSetCurrentContext failed"); + + m_bExitReportThd = false; + pthread_t report_thread; + ret = pthread_create(&report_thread, nullptr, ReportThd, (void *)this); + if(ret != 0){ + LOG_ERROR("[{}]- pthread_create failed", m_dec_name); + return; + } + + // 创建aclvdecChannelDesc类型的数据 + aclvdecChannelDesc *vdecChannelDesc = aclvdecCreateChannelDesc(); + if (vdecChannelDesc == nullptr) { + LOG_ERROR("[{}]- aclvdecCreateChannelDesc failed", m_dec_name); + return; + } + do{ + // 创建 channel dec结构体 + // 通道ID在dvpp层面为0~31 + CHECK_AND_BREAK(aclvdecSetChannelDescChannelId(vdecChannelDesc, m_dvpp_channel), "aclvdecSetChannelDescChannelId failed"); + CHECK_AND_BREAK(aclvdecSetChannelDescThreadId(vdecChannelDesc, report_thread), "aclvdecSetChannelDescThreadId failed"); + CHECK_AND_BREAK(aclvdecSetChannelDescCallback(vdecChannelDesc, VdecCallback), "aclvdecSetChannelDescCallback failed"); + CHECK_AND_BREAK(aclvdecSetChannelDescEnType(vdecChannelDesc, enType), "aclvdecSetChannelDescEnType failed"); + CHECK_AND_BREAK(aclvdecSetChannelDescOutPicFormat(vdecChannelDesc, PIXEL_FORMAT_YUV_SEMIPLANAR_420), "aclvdecSetChannelDescOutPicFormat failed"); + CHECK_AND_BREAK(aclvdecCreateChannel(vdecChannelDesc), "aclvdecCreateChannel failed"); + + uint64_t frame_count = 0; + bool bBreak = false; + while (m_bRunning) + { + if (m_bPause){ + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + continue; + } + int ret = sentFrame(vdecChannelDesc, frame_count); + if(ret == 2){ + break; + bBreak = true; + }else if(ret == 1){ + continue; + } + + frame_count++; + } + + // 尽量保证数据全部解码完成 + int sum = 0; + if(!bBreak){ + while(!m_pktQueueptr->isEmpty()){ + int ret = sentFrame(vdecChannelDesc, frame_count); + if(ret == 2){ + break; + } + std::this_thread::sleep_for(std::chrono::milliseconds(3)); + sum++; + if(sum > 40){ + // 避免卡死 + break; + } + } + } + + sendVdecEos(vdecChannelDesc); + + CHECK_NOT_RETURN(aclvdecDestroyChannel(vdecChannelDesc), "aclvdecDestroyChannel failed"); + }while(0); + + CHECK_NOT_RETURN(aclvdecDestroyChannelDesc(vdecChannelDesc), "aclvdecDestroyChannelDesc failed"); + + // report_thread 需后于destroy退出 + m_bRunning = false; + m_bExitReportThd = true; + CHECK_NOT_RETURN(pthread_join(report_thread, nullptr), "pthread_join failed"); + + releaseResource(); + LOG_INFO("[{}]- decode thread exit.", m_dec_name); +} + +int DvppDec::sentFrame(aclvdecChannelDesc *vdecChannelDesc, uint64_t frame_count){ + + AVPacket * pkt = m_pktQueueptr->getHead(); + if(pkt == nullptr){ + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + return 1; + } + // 解码 + void *vdecInputbuf = m_vdecQueue.getTail(); + if(vdecInputbuf == nullptr){ + std::this_thread::sleep_for(std::chrono::milliseconds(3)); + return 1; + } + + int ret = aclrtMemcpy(vdecInputbuf, pkt->size, pkt->data, pkt->size, ACL_MEMCPY_HOST_TO_DEVICE); + if(ACL_ERROR_NONE != ret){ + LOG_ERROR("[{}]- aclrtMemcpy failed", m_dec_name); + return 2; + } + + void *vdecOutputBuf = nullptr; + ret = acldvppMalloc((void **)&vdecOutputBuf, m_vdec_out_size); + if(ret != ACL_ERROR_NONE){ + LOG_ERROR("[{}]- acldvppMalloc failed", m_dec_name); + return 2; + } + + acldvppStreamDesc *input_stream_desc = nullptr; + acldvppPicDesc *output_pic_desc = nullptr; + do{ + input_stream_desc = acldvppCreateStreamDesc(); + if (input_stream_desc == nullptr) { + LOG_ERROR("[{}]- acldvppCreateStreamDesc failed", m_dec_name); + break; + } + output_pic_desc = acldvppCreatePicDesc(); + if (output_pic_desc == nullptr) { + LOG_ERROR("[{}]- acldvppCreatePicDesc failed", m_dec_name); + break; + } + CHECK_AND_BREAK(acldvppSetStreamDescData(input_stream_desc, vdecInputbuf), "acldvppSetStreamDescData failed"); + CHECK_AND_BREAK(acldvppSetStreamDescSize(input_stream_desc, pkt->size), "acldvppSetStreamDescSize failed"); + CHECK_AND_BREAK(acldvppSetPicDescData(output_pic_desc, vdecOutputBuf), "acldvppSetPicDescData failed"); + CHECK_AND_BREAK(acldvppSetPicDescSize(output_pic_desc, m_vdec_out_size), "acldvppSetPicDescSize failed"); + + Vdec_CallBack_UserData *user_data = NULL; + user_data = new Vdec_CallBack_UserData; + user_data->frameId = frame_count; + // user_data->startTime = startTime; + user_data->sendTime = UtilTools::get_cur_time_ms(); + user_data->self = this; + ret = aclvdecSendFrame(vdecChannelDesc, input_stream_desc, output_pic_desc, nullptr, reinterpret_cast(user_data)); + av_packet_unref(pkt); + m_pktQueueptr->addHead(); + if(ret != ACL_ERROR_NONE){ + delete user_data; + user_data = nullptr; + LOG_ERROR("[{}]- aclvdecSendFrame failed", m_dec_name); + break; + } + + m_vdecQueue.addTail(); + + return 0; + }while (0); + + // 报错情形 + if(input_stream_desc){ + CHECK_NOT_RETURN(acldvppDestroyStreamDesc(input_stream_desc), "acldvppDestroyStreamDesc failed"); + } + if(output_pic_desc){ + CHECK_NOT_RETURN(acldvppDestroyPicDesc(output_pic_desc), "acldvppDestroyPicDesc failed"); + } + + acldvppFree(vdecOutputBuf); + vdecOutputBuf = nullptr; + + return 1; +} + + +void DvppDec::setPostDecArg(const void* postDecArg){ + m_postDecArg = postDecArg; +} + +void DvppDec::pause(){ + m_bPause = true; +} + +void DvppDec::resume(){ + m_bPause = false; +} \ No newline at end of file diff --git a/src/dvpp/DvppDec.h b/src/dvpp/DvppDec.h new file mode 100644 index 0000000..adc9dda --- /dev/null +++ b/src/dvpp/DvppDec.h @@ -0,0 +1,85 @@ +#include +#include + +#include "dvpp_headers.h" +#include "depend_headers.h" +#include "user_mem.h" +#include "CircularQueue.hpp" +#include "VpcPicConverter.h" +#include "FFReceiver.h" + +#include + +using namespace std; + +#define TEST_DECODER + +struct DvppDecConfig{ + string dec_name; + POST_DECODE_CALLBACK post_decoded_cbk; // 解码数据回调接口 + string dev_id; // gpu id + bool force_tcp{true}; // 是否指定使用tcp连接 + int skip_frame{1}; // 跳帧数 + int codec_id; // 0 : h264 1:h265 + int profile; + CircularQueue *pktQueueptr; + + int width; + int height; +}; + + +class DvppDec { +public: + DvppDec(); + ~DvppDec(); + bool init_vdpp(DvppDecConfig cfg); + void setPostDecArg(const void* postDecArg); + bool start(); + void close(); + void pause(); + void resume(); + +public: + void doProcessReport(); + void doVdppVdecCallBack(acldvppStreamDesc *input, acldvppPicDesc *output); + +private: + void decode_thread(); + void releaseResource(); + bool sendVdecEos(aclvdecChannelDesc *vdecChannelDesc); + int sentFrame(aclvdecChannelDesc *vdecChannelDesc, uint64_t frame_count); + +private: + + bool m_bRunning{false}; + bool m_bPause{false}; + bool m_bExitReportThd{false}; + + int m_dvpp_deviceId {-1}; + int m_dvpp_channel {-1}; + aclrtContext m_context; + acldvppStreamFormat enType; + + pthread_t m_decode_thread; + + DvppDecConfig m_cfg; + string m_dec_name; + + vector m_vec_vdec; + CircularQueue m_vdecQueue; + CircularQueue *m_pktQueueptr; + + const void * m_postDecArg; + POST_DECODE_CALLBACK post_decoded_cbk; + + VpcPicConverter picConverter; + + int m_vdec_out_size {-1}; + +#ifdef TEST_DECODER + void *vdecHostAddr = nullptr; + int count_frame = 0; +#endif + +}; \ No newline at end of file diff --git a/src/dvpp/DvppDecoder.cpp b/src/dvpp/DvppDecoder.cpp new file mode 100644 index 0000000..45c4738 --- /dev/null +++ b/src/dvpp/DvppDecoder.cpp @@ -0,0 +1,137 @@ +#include "DvppDecoder.h" + +void receiver_finish_cbk(const void* userPtr){ + if(userPtr != nullptr){ + DvppDecoder* self = (DvppDecoder*)userPtr; + self->taskFinishing(); + } +} + +DvppDecoder::DvppDecoder(){ + m_pktQueueptr = new CircularQueue(); +} + +DvppDecoder::~DvppDecoder(){ + delete m_pktQueueptr; + m_pktQueueptr = nullptr; +} + +bool DvppDecoder::init(FFDecConfig cfg){ + + m_dec_name = cfg.dec_name; + + ReceiverConfig receiver_config; + receiver_config.uri = cfg.uri.c_str(); + receiver_config.dec_name = cfg.dec_name; + receiver_config.force_tcp = cfg.force_tcp; + receiver_config.pktQueueptr = m_pktQueueptr; + receiver_config.receiver_finished_cbk = receiver_finish_cbk; + AVCodecContext* avctx = m_receiver.init_FFmpeg(receiver_config); + if(avctx == nullptr){ + return false; + } + m_receiver.setFinishCbkArg(this); + + DvppDecConfig dec_cfg; + if(avctx->codec_id == AV_CODEC_ID_H264){ + dec_cfg.codec_id = 0; + }else if(avctx->codec_id == AV_CODEC_ID_HEVC){ + dec_cfg.codec_id = 1; + }else { + return false; + } + dec_cfg.dec_name = cfg.dec_name; + dec_cfg.post_decoded_cbk = cfg.post_decoded_cbk; + dec_cfg.dev_id = cfg.gpuid; + dec_cfg.force_tcp = cfg.force_tcp; + dec_cfg.skip_frame = cfg.skip_frame; + dec_cfg.profile = avctx->profile; + dec_cfg.pktQueueptr = m_pktQueueptr; + dec_cfg.width = avctx->width; + dec_cfg.height = avctx->height; + bool bRet = m_decoder.init_vdpp(dec_cfg); + if(!bRet){ + return false; + } + + m_cfg = cfg; + + decode_finished_cbk = cfg.decode_finished_cbk; + + m_bFinished = false; + + return true; +} + +bool DvppDecoder::isSurport(FFDecConfig& cfg){ + return true; +} + +bool DvppDecoder::start(){ + m_receiver.start(); + m_decoder.start(); + return true; +} + +void DvppDecoder::close(){ + m_receiver.close(); +} + +void DvppDecoder::setPostDecArg(const void* postDecArg){ + m_decoder.setPostDecArg(postDecArg); +} + +void DvppDecoder::setFinishedDecArg(const void* finishedDecArg){ + m_finishedDecArg = finishedDecArg; +} + +void DvppDecoder::pause(){ + m_receiver.pause(); +} + +void DvppDecoder::resume(){ + m_receiver.resume(); +} + +void DvppDecoder::setDecKeyframe(bool bKeyframe){ + m_receiver.setDecKeyframe(bKeyframe); +} + +bool DvppDecoder::isRunning(){ + return m_receiver.isRunning(); +} + +bool DvppDecoder::isFinished(){ + return m_bFinished; +} + +bool DvppDecoder::isPausing(){ + return m_receiver.isPausing(); +} + +bool DvppDecoder::getResolution(int &width, int &height){ + return m_receiver.getResolution(width, height); +} + +float DvppDecoder::fps(){ + return m_receiver.fps(); +} + +FFImgInfo* DvppDecoder::snapshot(){ + // TODO + return nullptr; +} + +int DvppDecoder::getCachedQueueLength(){ + return 0; +} + +void DvppDecoder::taskFinishing(){ + // receiver 中读取线程结束时执行 + m_decoder.close(); + decode_finished_cbk(m_finishedDecArg); + + m_bFinished = true; + + LOG_INFO("[{}]- task finished.", m_dec_name); +} \ No newline at end of file diff --git a/src/dvpp/DvppDecoder.h b/src/dvpp/DvppDecoder.h new file mode 100644 index 0000000..c6b32fd --- /dev/null +++ b/src/dvpp/DvppDecoder.h @@ -0,0 +1,62 @@ +#include + +#include "depend_headers.h" +#include "CircularQueue.hpp" +#include "FFReceiver.h" +#include "DvppDec.h" + +using namespace std; + +class DvppDecoder{ +public: + DvppDecoder(); + ~DvppDecoder(); + bool init(FFDecConfig cfg); + void close(); + bool start(); + void pause(); + void resume(); + + void setDecKeyframe(bool bKeyframe); + + bool isRunning(); + bool isFinished(); + bool isPausing(); + bool getResolution( int &width, int &height ); + + bool isSurport(FFDecConfig& cfg); + + float fps(); + + void setName(string nm){ + m_dec_name = nm; + } + + string getName(){ + return m_dec_name; + } + + FFImgInfo* snapshot(); + + void setPostDecArg(const void* postDecArg); + void setFinishedDecArg(const void* finishedDecArg); + + int getCachedQueueLength(); + +public: + void taskFinishing(); + +private: + FFDecConfig m_cfg; + string m_dec_name; + + CircularQueue *m_pktQueueptr; + FFReceiver m_receiver; + DvppDec m_decoder; + + const void * m_finishedDecArg; + DECODE_FINISHED_CALLBACK decode_finished_cbk; + + bool m_bFinished{false}; + +}; \ No newline at end of file diff --git a/src/dvpp/DvppDecoderApi.cpp b/src/dvpp/DvppDecoderApi.cpp new file mode 100644 index 0000000..44ed20e --- /dev/null +++ b/src/dvpp/DvppDecoderApi.cpp @@ -0,0 +1,133 @@ +#include "DvppDecoderApi.h" +#include "DvppDecoder.h" + +DvppDecoderApi::DvppDecoderApi(){ + m_pDecoder = nullptr; +} + +DvppDecoderApi::~DvppDecoderApi(){ + if(m_pDecoder != nullptr){ + delete m_pDecoder; + m_pDecoder = nullptr; + } +} + +bool DvppDecoderApi::init(FFDecConfig& cfg){ + m_pDecoder = new DvppDecoder(); + if(m_pDecoder != nullptr){ + return m_pDecoder->init(cfg); + } + return false; +} + +void DvppDecoderApi::close(){ + if(m_pDecoder != nullptr){ + return m_pDecoder->close(); + } +} + +bool DvppDecoderApi::start(){ + if(m_pDecoder != nullptr){ + return m_pDecoder->start(); + } + return false; +} + +void DvppDecoderApi::pause(){ + if(m_pDecoder != nullptr){ + return m_pDecoder->pause(); + } +} + +void DvppDecoderApi::resume(){ + if(m_pDecoder != nullptr){ + return m_pDecoder->resume(); + } +} + +void DvppDecoderApi::setDecKeyframe(bool bKeyframe){ + if(m_pDecoder != nullptr){ + return m_pDecoder->setDecKeyframe(bKeyframe); + } +} + +bool DvppDecoderApi::isRunning(){ + if(m_pDecoder != nullptr){ + return m_pDecoder->isRunning(); + } + return false; +} + +bool DvppDecoderApi::isFinished(){ + if(m_pDecoder != nullptr){ + return m_pDecoder->isFinished(); + } + return false; +} + +bool DvppDecoderApi::isPausing(){ + if(m_pDecoder != nullptr){ + return m_pDecoder->isPausing(); + } + return false; +} + +bool DvppDecoderApi::getResolution(int &width, int &height){ + if(m_pDecoder != nullptr){ + return m_pDecoder->getResolution(width, height); + } + return false; +} + +bool DvppDecoderApi::isSurport(FFDecConfig& cfg){ + if(m_pDecoder != nullptr){ + return m_pDecoder->isSurport(cfg); + } + return false; +} + +float DvppDecoderApi::fps(){ + if(m_pDecoder != nullptr){ + return m_pDecoder->fps(); + } + return 0.0; +} + +int DvppDecoderApi::getCachedQueueLength(){ + if(m_pDecoder != nullptr){ + return m_pDecoder->getCachedQueueLength(); + } + return 0; +} + +void DvppDecoderApi::setName(string nm){ + if(m_pDecoder != nullptr){ + return m_pDecoder->setName(nm); + } +} + +string DvppDecoderApi::getName(){ + if(m_pDecoder != nullptr){ + return m_pDecoder->getName(); + } + return nullptr; +} + +FFImgInfo* DvppDecoderApi::snapshot(){ + if(m_pDecoder != nullptr){ + return m_pDecoder->snapshot(); + } + return nullptr; +} + +void DvppDecoderApi::setPostDecArg(const void* postDecArg){ + if(m_pDecoder != nullptr){ + return m_pDecoder->setPostDecArg(postDecArg); + } +} + +void DvppDecoderApi::setFinishedDecArg(const void* finishedDecArg){ + if(m_pDecoder != nullptr){ + return m_pDecoder->setFinishedDecArg(finishedDecArg); + } +} \ No newline at end of file diff --git a/src/dvpp/DvppDecoderApi.h b/src/dvpp/DvppDecoderApi.h new file mode 100644 index 0000000..b020d75 --- /dev/null +++ b/src/dvpp/DvppDecoderApi.h @@ -0,0 +1,44 @@ +#include +#include + +#include "depend_headers.h" +#include "../interface/AbstractDecoder.h" + +using namespace std; + +class DvppDecoder; + +class DvppDecoderApi : public AbstractDecoder { +public: + DvppDecoderApi(); + ~DvppDecoderApi(); + bool init(FFDecConfig& cfg); + void close(); + bool start(); + void pause(); + void resume(); + + void setDecKeyframe(bool bKeyframe); + + bool isRunning(); + bool isFinished(); + bool isPausing(); + bool getResolution( int &width, int &height ); + + bool isSurport(FFDecConfig& cfg); + + int getCachedQueueLength(); + + float fps(); + + FFImgInfo* snapshot(); + + DECODER_TYPE getDecoderType(){ return DECODER_TYPE_DVPP; } + void setName(string nm); + string getName(); + + void setPostDecArg(const void* postDecArg); + void setFinishedDecArg(const void* finishedDecArg); +private: + DvppDecoder* m_pDecoder; +}; \ No newline at end of file diff --git a/src/dvpp/DvppRgbMemory.hpp b/src/dvpp/DvppRgbMemory.hpp new file mode 100644 index 0000000..b6bc750 --- /dev/null +++ b/src/dvpp/DvppRgbMemory.hpp @@ -0,0 +1,25 @@ +#include + +#include "dvpp_headers.h" + +using namespace std; + +class DvppRgbMemory : public DeviceRgbMemory +{ +public: + DvppRgbMemory(int _channel, int _width, int _height, int _size, string _id, string _dev_id, bool _key_frame) + :DeviceRgbMemory(_channel, _width, _height, _id, _dev_id, _key_frame, false){ + data_size = _size; + int ret = acldvppMalloc((void **)&pHwRgb, data_size); + if(ret != ACL_ERROR_NONE){ + cout << "acldvppMalloc failed" << endl; + } + } + + ~DvppRgbMemory(){ + if (pHwRgb) { + acldvppFree((uint8_t*)pHwRgb); + pHwRgb = nullptr; + } + } +}; \ No newline at end of file diff --git a/src/dvpp/DvppSourceManager.cpp b/src/dvpp/DvppSourceManager.cpp new file mode 100644 index 0000000..4f4ce47 --- /dev/null +++ b/src/dvpp/DvppSourceManager.cpp @@ -0,0 +1,66 @@ +#include "DvppSourceManager.h" + +#include "dvpp_headers.h" +#include "depend_headers.h" + +using namespace std; + +DvppSourceManager::~DvppSourceManager() +{ + for(auto iter = ctxMap.begin(); iter != ctxMap.end(); iter++){ + aclError ret = aclrtDestroyContext(iter->second); + if(ret != ACL_ERROR_NONE){ + LOG_ERROR("aclrtDestroyContext failed !"); + continue; + } + } + ctxMap.clear(); + channelMap.clear(); + + aclFinalize(); +} + +aclrtContext DvppSourceManager::getContext(int devId) +{ + aclrtContext ctx = ctxMap[devId]; + if (ctx == nullptr) + { + // 初始化硬件解码器 + aclError ret = aclrtSetDevice(devId); + if(ret != ACL_ERROR_NONE){ + // cout << "aclrtSetDevice failed" << endl; + LOG_ERROR("aclrtSetDevice failed !"); + return nullptr; + } + + ret = aclrtCreateContext(&ctx, devId); + if (ret != ACL_ERROR_NONE) { + // cout << "aclrtCreateContext failed " << endl; + LOG_ERROR("aclrtCreateContext failed !"); + return nullptr; + } + ctxMap[devId] = ctx; + } + return ctx; +} + +int DvppSourceManager::getChannel(int devId){ + // channel 最大值暂定为32, 华为没有接口获取最大channel,只有文档说明 + for(int iChannel = 0; iChannel < 32; iChannel++){ + string channelKey = "channel_" + to_string(devId) + "_" + to_string(iChannel) ; + auto it = channelMap.find(channelKey); + if(it == channelMap.end()){ + channelMap[channelKey] = iChannel; + return iChannel; + } + } + return -1; +} + +void DvppSourceManager::releaseChannel(int devId, int iChannel){ + string channelKey = "channel_" + to_string(devId) + "_" + to_string(iChannel) ; + auto it = channelMap.find(channelKey); + if(it != channelMap.end()){ + channelMap.erase(channelKey); + } +} \ No newline at end of file diff --git a/src/dvpp/DvppSourceManager.h b/src/dvpp/DvppSourceManager.h new file mode 100644 index 0000000..36a4b07 --- /dev/null +++ b/src/dvpp/DvppSourceManager.h @@ -0,0 +1,36 @@ + +#include +#include + +#include "dvpp_headers.h" + +using namespace std; + +class DvppSourceManager{ +public: + static DvppSourceManager* getInstance(){ + static DvppSourceManager* singleton = nullptr; + if (singleton == nullptr){ + singleton = new DvppSourceManager(); + int ret = aclInit(nullptr); + if (ret != ACL_ERROR_NONE) { + cout << "aclInit failed" << endl; + return nullptr; + } + } + return singleton; + } + + aclrtContext getContext(int devId); + + int getChannel(int devId); + void releaseChannel(int devId, int channel); + +private: + DvppSourceManager(){} + ~DvppSourceManager(); + +private: + map ctxMap; + map channelMap; +}; \ No newline at end of file diff --git a/src/dvpp/FFReceiver.cpp b/src/dvpp/FFReceiver.cpp new file mode 100644 index 0000000..26685a6 --- /dev/null +++ b/src/dvpp/FFReceiver.cpp @@ -0,0 +1,282 @@ +#include "FFReceiver.h" +#include + +const int g_pkt_size = 1024 * 1024; // 单个AVPacket大小的最大值 + +FFReceiver::FFReceiver(/* args */) +{ + fmt_ctx = nullptr; + m_bRunning = false; + + stream = nullptr; + stream_index = -1; + pix_fmt = AV_PIX_FMT_NONE; + m_dec_name = ""; + + m_bPause = false; + m_bReal = true; + + m_bFinished = false; + m_dec_keyframe = false; + m_fps = 0.0; + + m_read_thread = 0; +} + +FFReceiver::~FFReceiver() +{ + releaseFFmpeg(); + + // 这个只能放在析构函数中,因为会影响到解码类中的m_pktQueueptr队列 + // 所以应当确保在所有工作线程都退出后才释放 + for(int i = 0; i < m_vec_pkt.size(); i++){ + av_packet_free(&m_vec_pkt[i]); + } +} + +AVCodecContext* FFReceiver::init_FFmpeg(ReceiverConfig config){ + +#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 9, 100) + av_register_all(); +#endif +#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 10, 100) + avcodec_register_all(); +#endif + + avformat_network_init(); + + const char* uri = config.uri; + fstream infile(uri); + if (infile.is_open()){ + m_bReal = false; + infile.close(); + }else { + m_bReal = true; + } + + m_dec_name = config.dec_name; + m_pktQueueptr = config.pktQueueptr; + receiver_finished_cbk = config.receiver_finished_cbk; + + // 打开输入视频文件 + AVDictionary *options = nullptr; + av_dict_set( &options, "bufsize", "655360", 0 ); + av_dict_set( &options, "rtsp_transport", config.force_tcp ? "tcp" : "udp", 0 ); + av_dict_set( &options, "stimeout", "30000000", 0 ); // 单位为 百万分之一秒 + + fmt_ctx = avformat_alloc_context(); + const char* input_file = uri; + if (avformat_open_input(&fmt_ctx, input_file, nullptr, &options) != 0) { + LOG_ERROR("[{}]- Cannot open input file: {}", m_dec_name, input_file); + return nullptr; + } + av_dump_format(fmt_ctx, 0, input_file, 0); + + // 查找流信息 + if (avformat_find_stream_info(fmt_ctx, nullptr) < 0) { + LOG_ERROR("[{}]- Cannot find input stream information!", m_dec_name); + return nullptr; + } + + // 查找视频流信息 + AVCodec *decoder = nullptr; + stream_index = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &decoder, 0); + if (stream_index < 0) { + LOG_ERROR("[{}]- Cannot find a video stream in the input file!", m_dec_name); + return nullptr; + } + AVCodec *vcodec = avcodec_find_decoder(decoder->id); + + avctx = avcodec_alloc_context3(vcodec); + if(avctx == nullptr){ + LOG_ERROR("[{}]- alloc AVCodecContext failed!", m_dec_name); + return nullptr; + } + + do{ + // 得到视频流对象 + AVStream* stream = fmt_ctx->streams[stream_index]; + AVCodecParameters *codecpar = stream->codecpar; + if (avcodec_parameters_to_context(avctx, codecpar) < 0) + break; + + const AVBitStreamFilter * filter = nullptr; + if(codecpar->codec_id == AV_CODEC_ID_H264){ + filter = av_bsf_get_by_name("h264_mp4toannexb"); + }else if(codecpar->codec_id == AV_CODEC_ID_HEVC){ + filter = av_bsf_get_by_name("hevc_mp4toannexb"); + }else { + LOG_ERROR("[{}]- codec_id is not supported!", m_dec_name); + break; + } + + int ret = av_bsf_alloc(filter, &h264bsfc); + if (ret < 0){ + break; + } + + avcodec_parameters_copy(h264bsfc->par_in, codecpar); + av_bsf_init(h264bsfc); + + frame_width = codecpar->width; + frame_height = codecpar->height; + pix_fmt = (AVPixelFormat)codecpar->format; + m_fps = av_q2d(stream ->avg_frame_rate); + + LOG_INFO("[{}]- init ffmpeg success! input:{} frame_width:{} frame_height:{} fps:{} ", m_dec_name, input_file, frame_width, frame_height, m_fps); + + for(int i = 0; i<5; i++){ + AVPacket* pkt = av_packet_alloc(); + av_init_packet( pkt ); + m_vec_pkt.push_back(pkt); + } + m_pktQueueptr->init(m_vec_pkt); + + return avctx; + }while(0); + + LOG_ERROR("[{}]- init ffmpeg failed ! input:{} ", m_dec_name); + + return nullptr; +} + +void FFReceiver::releaseFFmpeg(){ + m_dec_keyframe = false; + if(h264bsfc){ + av_bsf_free(&h264bsfc); + h264bsfc = nullptr; + } + if (fmt_ctx){ + avformat_close_input(&fmt_ctx); + fmt_ctx = nullptr; + } + if(avctx){ + avcodec_free_context(&avctx); + avctx = nullptr; + } +} + +void FFReceiver::read_thread(){ + + int frame_count = 0; + int ret = -1; + while (m_bRunning) + { + if (!m_bReal) + { + if (m_bPause) + { + std::this_thread::sleep_for(std::chrono::milliseconds(3)); + continue; + } + } + + AVPacket* pkt = m_pktQueueptr->getTail(); + if(pkt == nullptr){ + std::this_thread::sleep_for(std::chrono::milliseconds(3)); + continue; + } + + int result = av_read_frame(fmt_ctx, pkt); + if (result == AVERROR_EOF || result < 0) + { + LOG_ERROR("[{}]- Failed to read frame!", m_dec_name); + break; + } + + if (m_dec_keyframe && !(pkt->flags & AV_PKT_FLAG_KEY)) { + av_packet_unref(pkt); + continue; + } + + if (stream_index == pkt->stream_index){ + + ret = av_bsf_send_packet(h264bsfc, pkt); + if(ret < 0) { + LOG_ERROR("[{}]- av_bsf_send_packet error!", m_dec_name); + } + + while ((ret = av_bsf_receive_packet(h264bsfc, pkt)) == 0) { + if(pkt->size > g_pkt_size){ + LOG_ERROR("[{}]- pkt size 大于最大预设值!", m_dec_name); + break; + } + + if(!m_bRunning){ + break; + } + + m_pktQueueptr->addTail(); + + frame_count++; + } + } + } + + LOG_INFO("[{}]- read thread exit.", m_dec_name); + m_bFinished = true; + + receiver_finished_cbk(m_finishedReceiveArg); +} + +bool FFReceiver::start(){ + m_bRunning = true; + + pthread_create(&m_read_thread,0, + [](void* arg) + { + FFReceiver* a=(FFReceiver*)arg; + a->read_thread(); + return (void*)0; + } + ,this); + + return true; +} + +void FFReceiver::close(){ + m_bRunning=false; + + if(m_read_thread != 0){ + pthread_join(m_read_thread,0); + } +} + +float FFReceiver::fps(){ + return m_fps; +} + +bool FFReceiver::getResolution( int &width, int &height ){ + width = frame_width; + height = frame_height; + return true; +} + +void FFReceiver::pause(){ + m_bPause = true; +} + +void FFReceiver::resume(){ + m_bPause = false; +} + +void FFReceiver::setDecKeyframe(bool bKeyframe) +{ + m_dec_keyframe = bKeyframe; +} + +bool FFReceiver::isRunning(){ + return m_bRunning; +} + +bool FFReceiver::isFinished(){ + return m_bFinished; +} + +bool FFReceiver::isPausing(){ + return m_bPause; +} + +void FFReceiver::setFinishCbkArg(const void* userPtr){ + m_finishedReceiveArg = userPtr; +} \ No newline at end of file diff --git a/src/dvpp/FFReceiver.h b/src/dvpp/FFReceiver.h new file mode 100644 index 0000000..a380628 --- /dev/null +++ b/src/dvpp/FFReceiver.h @@ -0,0 +1,81 @@ +#ifndef __FFRECEIVER_H__ +#define __FFRECEIVER_H__ + +#include "depend_headers.h" +#include "CircularQueue.hpp" + +typedef void(*RECEIVER_FINISHED_CALLBACK)(const void* userPtr); + +struct ReceiverConfig{ + const char* uri; + string dec_name; + bool force_tcp; + CircularQueue *pktQueueptr; + RECEIVER_FINISHED_CALLBACK receiver_finished_cbk; // 解码线程结束后的回调接口 +}; + +class FFReceiver +{ +public: + FFReceiver(/* args */); + ~FFReceiver(); + + AVCodecContext* init_FFmpeg(ReceiverConfig config); + void releaseFFmpeg(); + void close(); + bool start(); + + void pause(); + void resume(); + void setDecKeyframe(bool bKeyframe); + bool isRunning(); + bool isFinished(); + bool isPausing(); + bool getResolution( int &width, int &height ); + float fps(); + + void setName(string nm){ + m_dec_name = nm; + } + + void setFinishCbkArg(const void* userPtr); + +private: + void read_thread(); + +private: + string m_dec_name; + + AVStream* stream; + int stream_index; + AVFormatContext *fmt_ctx; + AVPixelFormat pix_fmt; + int frame_width{0}; + int frame_height{0}; + + pthread_t m_read_thread; + + bool m_bRunning; + bool m_bFinished; + + bool m_bPause; + + bool m_bReal; // 是否实时流 + + float m_fps; + + FFDecConfig m_cfg; + bool m_dec_keyframe; + + AVCodecContext *avctx{nullptr}; + AVBSFContext * h264bsfc{nullptr}; + + vector m_vec_pkt; + CircularQueue *m_pktQueueptr; + + const void * m_finishedReceiveArg; + RECEIVER_FINISHED_CALLBACK receiver_finished_cbk; +}; + + +#endif \ No newline at end of file diff --git a/src/dvpp/Makefile b/src/dvpp/Makefile new file mode 100644 index 0000000..8bca911 --- /dev/null +++ b/src/dvpp/Makefile @@ -0,0 +1,66 @@ +# 各项目录 +LIB_DIR:=$(BUILD_DIR)/$(MODULE)/lib +DEP_DIR:=$(BUILD_DIR)/$(MODULE)/.dep +OBJ_DIR:=$(BUILD_DIR)/$(MODULE)/obj +SRC_DIR:=$(TOP_DIR)/$(MODULE) + +# 源文件以及中间目标文件和依赖文件 +SRCS:=$(notdir $(wildcard $(SRC_DIR)/*.cpp)) +OBJS:=$(addprefix $(OBJ_DIR)/, $(patsubst %.cpp, %.o, $(SRCS))) +DEPS:=$(addprefix $(DEP_DIR)/, $(patsubst %.cpp, %.d,a $(SRCS))) + +# 自动生成头文件依赖选项 +DEPFLAGS=-MT $@ -MMD -MP -MF $(DEP_DIR)/$*.d + +DEFS = -DENABLE_DVPP_INTERFACE + +# 最终目标文件 +TARGET:=$(LIB_DIR)/$(MODULE).a + +export LD_LIBRARY_PATH=/usr/local/Ascend/ascend-toolkit/6.3.RC1.alpha001/runtime/lib64:$LD_LIBRARY_PATH +export LD_LIBRARY_PATH=/usr/local/Ascend/ascend-toolkit/6.3.RC1.alpha001/lib64:$LD_LIBRARY_PATH +export LD_LIBRARY_PATH=/usr/local/Ascend/driver/lib64/driver:$LD_LIBRARY_PATH + +include_dir=-I/usr/local/Ascend/ascend-toolkit/latest/acllib/include +lib_dir=-L/usr/lib -L/usr/local/lib -L/usr/local/Ascend/ascend-toolkit/latest/acllib/lib64 -L/usr/local/Ascend/driver/lib64 -L/usr/local/Ascend/ascend-toolkit/latest/atc/lib64 +lib=-lacl_dvpp -lascendcl -lmmpa -lglog -lgflags -lpthread -lz + +CXXFLAGS= -g -O0 -fPIC $(include_dir) $(INCS) $(LIBS) $(DEFS) -lpthread -lrt -lz -fexceptions -std=c++11 -fvisibility=hidden -Wl,-Bsymbolic -ldl + # -DUNICODE -D_UNICODE + +# 默认最终目标 +.PHONY:all +all:$(TARGET) + +# 生成最终目标 +$(TARGET):$(OBJS) | $(LIB_DIR) + @echo -e "\e[32m""Linking static library $(TARGET)""\e[0m" + @ar -rc $@ $^ + +# 若没有lib目录则自动生成 +$(LIB_DIR): + @mkdir -p $@ + +# 生成中间目标文件 +$(OBJ_DIR)/%.o:$(SRC_DIR)/%.cpp $(DEP_DIR)/%.d | $(OBJ_DIR) $(DEP_DIR) + @echo -e "\e[33m""Building object $@""\e[0m" + @$(CXX) -c $(DEPFLAGS) $(CXXFLAGS) $(LDFLAGS) $(lib_dir) $(lib) $(MACROS) -o $@ $< + +# 若没有obj目录则自动生成 +$(OBJ_DIR): + @mkdir -p $@ + +# 若没有.dep目录则自动生成 +$(DEP_DIR): + @mkdir -p $@ + +# 依赖文件会在生成中间文件的时候自动生成,这里只是为了防止报错 +$(DEPS): + +# 引入中间目标文件头文件依赖关系 +include $(wildcard $(DEPS)) + +# 直接删除组件build目录 +.PHONY:clean +clean: + @rm -rf $(BUILD_DIR)/$(MODULE) diff --git a/src/dvpp/VpcPicConverter.cpp b/src/dvpp/VpcPicConverter.cpp new file mode 100644 index 0000000..c6d0a51 --- /dev/null +++ b/src/dvpp/VpcPicConverter.cpp @@ -0,0 +1,79 @@ +#include "VpcPicConverter.h" +#include "depend_headers.h" + +#define ALIGN_UP(val, align) (((val) % (align) == 0) ? (val) : (((val) / (align) + 1) * (align))) + +VpcPicConverter::VpcPicConverter(){ + +} + +VpcPicConverter::~VpcPicConverter(){ + if(nullptr == stream_){ + aclrtDestroyStream(stream_); + } +} + +int VpcPicConverter::init(aclrtContext context, string dec_name){ + + m_dec_name = dec_name; + + CHECK_AND_RETURN(aclrtSetCurrentContext(context), "aclrtSetCurrentContext failed"); + CHECK_AND_RETURN(aclrtCreateStream(&stream_), "aclrtCreateStream failed! "); + + dvppChannelDesc_ = acldvppCreateChannelDesc(); + + int ret = ACL_ERROR_NONE; + do + { + ret = acldvppCreateChannel(dvppChannelDesc_); + CHECK_AND_BREAK(ret, "acldvppCreateChannel failed !"); + + ret = acldvppSetChannelDescMode(dvppChannelDesc_, DVPP_CHNMODE_VPC); + CHECK_AND_BREAK(ret, "acldvppSetChannelDescMode failed !"); + } while (0); + + return ret; +} + +DvppRgbMemory* VpcPicConverter::convert2bgr(acldvppPicDesc *inputDesc_, int out_width, int out_height, bool key_frame){ + + int out_buf_width = ALIGN_UP(out_width, 16) * 3; + int out_buf_height = ALIGN_UP(out_height, 2); + int out_buf_size = out_buf_width * out_buf_height; + + DvppRgbMemory* rgbMem = new DvppRgbMemory(3, out_buf_width, out_buf_height, out_buf_size, "", to_string(m_devId), key_frame); + void *outBufferDev_ = (void*)rgbMem->getMem(); + + acldvppPicDesc *outputDesc_= acldvppCreatePicDesc(); + acldvppSetPicDescData(outputDesc_, outBufferDev_); + acldvppSetPicDescFormat(outputDesc_, PIXEL_FORMAT_BGR_888); + acldvppSetPicDescWidth(outputDesc_, out_width); + acldvppSetPicDescHeight(outputDesc_, out_height); + acldvppSetPicDescWidthStride(outputDesc_, out_buf_width); + acldvppSetPicDescHeightStride(outputDesc_, out_buf_height); + acldvppSetPicDescSize(outputDesc_, out_buf_size); + + aclError ret = ACL_ERROR_NONE; + do{ + // 9. 执行异步色域转换,再调用aclrtSynchronizeStream接口阻塞程序运行,直到指定Stream中的所有任务都完成 + ret = acldvppVpcConvertColorAsync(dvppChannelDesc_, inputDesc_, outputDesc_, stream_); + if(ret != ACL_ERROR_NONE){ + LOG_ERROR("acldvppVpcConvertColorAsync failed - out_width:{} out_height:{} out_buf_width:{} out_buf_height:{} out_buf_size:{}", out_width, out_height, out_buf_width, out_buf_height, out_buf_size); + break; + } + ret = aclrtSynchronizeStream(stream_); + if(ret != ACL_ERROR_NONE){ + LOG_ERROR("aclrtSynchronizeStream failed - out_width:{} out_height:{} out_buf_width:{} out_buf_height:{} out_buf_size:{}", out_width, out_height, out_buf_width, out_buf_height, out_buf_size); + break; + } + }while(0); + + acldvppDestroyPicDesc(outputDesc_); + + if(ret != ACL_ERROR_NONE){ + delete rgbMem; + rgbMem = nullptr; + } + + return rgbMem; +} \ No newline at end of file diff --git a/src/dvpp/VpcPicConverter.h b/src/dvpp/VpcPicConverter.h new file mode 100644 index 0000000..18d6921 --- /dev/null +++ b/src/dvpp/VpcPicConverter.h @@ -0,0 +1,20 @@ +#include "dvpp_headers.h" +#include "depend_headers.h" +#include "DvppRgbMemory.hpp" + + +class VpcPicConverter{ +public: + VpcPicConverter(); + ~VpcPicConverter(); + int init(aclrtContext context, string dec_name); + + DvppRgbMemory* convert2bgr(acldvppPicDesc *input, int out_width, int out_height, bool key_frame); + +private: + aclrtContext context_; + aclrtStream stream_; + int m_devId; + acldvppChannelDesc *dvppChannelDesc_ ; + string m_dec_name; +}; \ No newline at end of file diff --git a/src/dvpp/depend_headers.h b/src/dvpp/depend_headers.h new file mode 100644 index 0000000..0e942a2 --- /dev/null +++ b/src/dvpp/depend_headers.h @@ -0,0 +1,38 @@ +#ifndef __DEPEND_HEADERS_H__ +#define __DEPEND_HEADERS_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* +* 依赖模块外部的代码或库 +* 不要在此处添加模块内部的头文件 +*/ + +// ffmpeg 是c库 所以编译的时候要加入从 extern导入的C 来声明否则连接失败 +extern "C" { + #include "libavutil/imgutils.h" + #include "libavutil/samplefmt.h" + #include "libavformat/avformat.h" + #include "libavcodec/avcodec.h" +} + + +#include "../interface/logger.hpp" +#include "../interface/DeviceRgbMemory.hpp" +#include "../interface/interface_headers.h" +#include "../interface/utiltools.hpp" + +#endif \ No newline at end of file diff --git a/src/dvpp/dvpp_headers.h b/src/dvpp/dvpp_headers.h new file mode 100644 index 0000000..3d981af --- /dev/null +++ b/src/dvpp/dvpp_headers.h @@ -0,0 +1,40 @@ +/* +* 模块内部的头文件请在此处添加 +*/ + +#ifndef __DVPP_HEADERS_H__ +#define __DVPP_HEADERS_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "acl/acl_mdl.h" +#include "acl/acl_base.h" +#include "acl/acl_rt.h" +#include "acl/acl.h" +#include "acl/ops/acl_dvpp.h" + + +#define CHECK_AND_RETURN(ret, message) \ + if(ret != 0) {LOG_ERROR("[{}]- {}", m_dec_name, message); return ret;} +#define CHECK_NOT_RETURN(ret, message) \ + if(ret != 0) {LOG_ERROR("[{}]- {}", m_dec_name, message);} +#define CHECK_AND_RETURN_NOVALUE(ret, message) \ + if(ret != 0) {LOG_ERROR("[{}]- {}", m_dec_name, message); return;} +#define CHECK_AND_BREAK(ret, message) \ + if(ret != 0) {LOG_ERROR("[{}]- {}", m_dec_name, message); break;} + +#endif + diff --git a/src/dvpp/threadsafe_queue.h b/src/dvpp/threadsafe_queue.h new file mode 100644 index 0000000..5a5b0f9 --- /dev/null +++ b/src/dvpp/threadsafe_queue.h @@ -0,0 +1,128 @@ + +#ifndef __THREADSAFE_QUEUE_H__ +#define __THREADSAFE_QUEUE_H__ + +#include +#include +#include +#include + +#include +using std::queue; +using namespace std; + +template +class ThreadedQueue : public queue { +public: + ThreadedQueue(); + ~ThreadedQueue(); + bool empty() const; + size_t size() const; + void push(const T& val); + void push(T& val); + bool pop(); + T& front(); + const T& front() const; + T& back(); + const T& back() const; + + void Put(T &data); + + T Take(); + void Get(T &data); + bool GetEmpty(); + + condition_variable *condition; + mutex *lock; +}; + +template +ThreadedQueue::ThreadedQueue() { + lock = new mutex; + condition = new condition_variable; +} + +template +ThreadedQueue::~ThreadedQueue() { + if(condition != nullptr){ + delete condition; + condition = nullptr; + } + if(lock != nullptr){ + delete lock; + lock = nullptr; + } +} + +template +T ThreadedQueue:: Take() +{ + std::unique_lock lk(this->lock); + this->condition->wait(lk, [this]{return !this->empty();}); + T val = this->front(); + this->pop(); + return val; +} + +template +void ThreadedQueue:: Put(T &data) +{ + std::unique_lock lk(*lock); + this->push(data); + this->condition->notify_one(); + return; +} + +template +void ThreadedQueue:: Get(T &data) +{ + std::unique_lock lk(*lock); + this->condition->wait(lk, [this]{return !this->empty();}); + data = this->front(); + this->pop(); +} + +template +bool ThreadedQueue::GetEmpty() +{ + std::unique_lock lk(*lock); + this->condition->wait(lk, [this]{return !this->empty();}); + return true; +} + + +template +bool ThreadedQueue::empty() const { + bool result = queue::empty(); + return result; +} + +template +size_t ThreadedQueue::size() const { + size_t result = queue::size(); + return result; +} + +template +void ThreadedQueue::push(T& val) { + queue::push(val); +} + + +template +T& ThreadedQueue::front() { + T& result = queue::front(); + return result; +} + +template +bool ThreadedQueue::pop() { + bool result = false; + if(!queue::empty()) { + queue::pop(); + result = true; + } + return result; +} + +#endif diff --git a/src/dvpp/user_mem.h b/src/dvpp/user_mem.h new file mode 100644 index 0000000..e6a7d11 --- /dev/null +++ b/src/dvpp/user_mem.h @@ -0,0 +1,33 @@ +#ifndef __USER_MEM_H__ +#define __USER_MEM_H__ + +#include +#include +#include +#include +#include "threadsafe_queue.h" + +#define ALIGN_MEM(val, align) (((val) % (align) == 0) ? (val) : (((val) / (align) + 1) * (align))) + +using namespace std; + +typedef enum { + RTSP_MEM, + VDEC_MEM, +} MemType; + +class MemNode{ +public: + uint8_t *bufAddr; + MemType memType; + + MemNode(){ + std::cout << "构造" << endl; + } + + ~MemNode(){ + std::cout << "析构" << std::endl; + } +} ; + +#endif \ No newline at end of file diff --git a/src/gb28181/FFGB28181Decoder.cpp b/src/gb28181/FFGB28181Decoder.cpp index 4cea111..535274a 100644 --- a/src/gb28181/FFGB28181Decoder.cpp +++ b/src/gb28181/FFGB28181Decoder.cpp @@ -2,7 +2,7 @@ #include #include "FFGB28181Decoder.h" -#include "../FFCuContextManager.h" + extern "C" { #include "libavutil/avstring.h" @@ -17,6 +17,10 @@ extern "C" { #include "common_header.h" +#include "../nvdec/FFCuContextManager.h" +#include "../nvdec/GpuRgbMemory.hpp" +#include "../nvdec/cuda_kernels.h" + #define ECLOSED 0 #define ECLOSING 1 #define ERUNNING 2 @@ -300,7 +304,7 @@ void FFGB28181Decoder::post_decode_thread(){ m_queue_mutex.unlock(); // 跳帧 if (m_frameSkip == 1 || index % m_frameSkip == 0){ - post_decoded_cbk(m_postDecArg, gpuFrame); + post_decoded_cbk(m_postDecArg, convert2bgr(gpuFrame)); } av_frame_free(&gpuFrame); @@ -325,6 +329,14 @@ void FFGB28181Decoder::stream_end_callback() return; } +void FFGB28181Decoder::setPostDecArg(const void* postDecArg){ + m_postDecArg = postDecArg; +} + +void FFGB28181Decoder::setFinishedDecArg(const void* finishedDecArg){ + m_finishedDecArg = finishedDecArg; +} + void FFGB28181Decoder::pause() { m_status = EPAUSE; LOG_INFO("pause --{}", m_dec_name); @@ -373,4 +385,120 @@ bool FFGB28181Decoder::isSurport(FFDecConfig& cfg){ int FFGB28181Decoder::getCachedQueueLength(){ return m_rtpPtr->GetPsFrameListSize(); +} + +DeviceRgbMemory* FFGB28181Decoder::convert2bgr(AVFrame * gpuFrame){ + if (gpuFrame != nullptr && gpuFrame->format == AV_PIX_FMT_CUDA ){ + LOG_DEBUG("decode task: gpuid: {} width: {} height: {}", m_cfg.gpuid, gpuFrame->width, gpuFrame->height); + GpuRgbMemory* gpuMem = new GpuRgbMemory(3, gpuFrame->width, gpuFrame->height, getName(), m_cfg.gpuid, false, true); + + do{ + if (gpuMem->getMem() == nullptr){ + LOG_ERROR("new GpuRgbMemory failed !!!"); + break; + } + + cudaSetDevice(atoi(m_cfg.gpuid.c_str())); + cuda_common::setColorSpace( ITU_709, 0 ); + cudaError_t cudaStatus = cuda_common::CUDAToBGR((CUdeviceptr)gpuFrame->data[0],(CUdeviceptr)gpuFrame->data[1], gpuFrame->linesize[0], gpuFrame->linesize[1], gpuMem->getMem(), gpuFrame->width, gpuFrame->height); + cudaDeviceSynchronize(); + if (cudaStatus != cudaSuccess) { + LOG_ERROR("CUDAToBGR failed failed !!!"); + break; + } + + return gpuMem; + }while(0); + + delete gpuMem; + gpuMem = nullptr; + } + + return nullptr; +} + +FFImgInfo* FFGB28181Decoder::snapshot(){ + + // 锁住停止队列消耗 + std::lock_guard l(m_snapshot_mutex); + + AVFrame * gpuFrame = nullptr; + + bool bFirst = true; + while(true){ + m_queue_mutex.lock(); + if(mFrameQueue.size() <= 0){ + m_queue_mutex.unlock(); + if(bFirst){ + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + bFirst = false; + continue; + }else{ + // 再进来说明前面已经等了 100 ms + // 100 ms都没有等到解码数据,则退出 + return nullptr; + } + } + + // 队列中数据大于1 + gpuFrame = mFrameQueue.front(); + m_queue_mutex.unlock(); + break; + } + + if (gpuFrame != nullptr && gpuFrame->format == AV_PIX_FMT_CUDA ){ + LOG_DEBUG("decode task: gpuid: {} width: {} height: {}", m_cfg.gpuid, gpuFrame->width, gpuFrame->height); + GpuRgbMemory* gpuMem = new GpuRgbMemory(3, gpuFrame->width, gpuFrame->height, getName(), m_cfg.gpuid , false, true); + + if (gpuMem->getMem() == nullptr){ + LOG_ERROR("new GpuRgbMemory failed !!!"); + return nullptr; + } + + cudaSetDevice(atoi(m_cfg.gpuid.c_str())); + cuda_common::setColorSpace( ITU_709, 0 ); + cudaError_t cudaStatus = cuda_common::CUDAToBGR((CUdeviceptr)gpuFrame->data[0],(CUdeviceptr)gpuFrame->data[1], gpuFrame->linesize[0], gpuFrame->linesize[1], gpuMem->getMem(), gpuFrame->width, gpuFrame->height); + cudaDeviceSynchronize(); + if (cudaStatus != cudaSuccess) { + LOG_ERROR("CUDAToBGR failed failed !!!"); + return nullptr; + } + + unsigned char * pHwRgb = gpuMem->getMem(); + int channel = gpuMem->getChannel(); + int width = gpuMem->getWidth(); + int height = gpuMem->getHeight(); + + if (pHwRgb != nullptr && channel > 0 && width > 0 && height > 0){ + int nSize = channel * height * width; + + LOG_INFO("channel:{} height:{} width:{}", channel, height, width); + // unsigned char* cpu_data = new unsigned char[nSize]; + + unsigned char* cpu_data = (unsigned char *)av_malloc(nSize * sizeof(unsigned char)); + + cudaMemcpy(cpu_data, pHwRgb, nSize * sizeof(unsigned char), cudaMemcpyDeviceToHost); + cudaDeviceSynchronize(); + + delete gpuMem; + gpuMem = nullptr; + + FFImgInfo* imgInfo = new FFImgInfo(); + imgInfo->dec_name = m_dec_name; + imgInfo->pData = cpu_data; + imgInfo->height = height; + imgInfo->width = width; + imgInfo->timestamp = UtilTools::get_cur_time_ms(); + imgInfo->index = m_index; + + m_index++; + + return imgInfo; + } + + delete gpuMem; + gpuMem = nullptr; + } + + return nullptr; } \ No newline at end of file diff --git a/src/gb28181/FFGB28181Decoder.h b/src/gb28181/FFGB28181Decoder.h index 1f31a5b..abae9e5 100644 --- a/src/gb28181/FFGB28181Decoder.h +++ b/src/gb28181/FFGB28181Decoder.h @@ -3,7 +3,8 @@ #include "RTPReceiver.h" -#include "../AbstractDecoder.h" +#include "common_header.h" +#include "../interface/AbstractDecoder.h" #include #include @@ -14,6 +15,7 @@ struct AVCodec; struct AVFrame; struct AVPacket; struct SwsContext; +struct AVDictionary; using namespace std; @@ -44,12 +46,31 @@ public: DECODER_TYPE getDecoderType(){ return DECODER_TYPE_GB28181; } + FFImgInfo* snapshot(); + + void setName(string nm){ + m_dec_name = nm; + } + + string getName(){ + return m_dec_name; + } + + void setPostDecArg(const void* postDecArg); + void setFinishedDecArg(const void* finishedDecArg); + public: void stream_callback(int videoType, char* data, int len, int isKey, uint64_t pts, uint64_t localPts); void stream_end_callback(); void post_decode_thread(); private: + DeviceRgbMemory* convert2bgr(AVFrame * gpuFrame); + +private: + string m_dec_name; + FFDecConfig m_cfg; + AVCodecContext* m_pAVCodecCtx {}; const AVCodec* m_pAVCodec {}; @@ -74,6 +95,17 @@ private: AVDictionary *gpu_options = nullptr; pthread_t m_post_decode_thread; + const void * m_postDecArg; + POST_DECODE_CALLBACK post_decoded_cbk; // 解码数据回调接口 + + const void * m_finishedDecArg; + DECODE_FINISHED_CALLBACK decode_finished_cbk; + + queue mFrameQueue; + mutex m_queue_mutex; + mutex m_snapshot_mutex; + + bool m_dec_keyframe; }; #endif // _GB28181_DECODER_H_ diff --git a/src/gb28181/Makefile b/src/gb28181/Makefile new file mode 100644 index 0000000..f0d2492 --- /dev/null +++ b/src/gb28181/Makefile @@ -0,0 +1,71 @@ +# 各项目录 +LIB_DIR:=$(BUILD_DIR)/$(MODULE)/lib +DEP_DIR:=$(BUILD_DIR)/$(MODULE)/.dep +OBJ_DIR:=$(BUILD_DIR)/$(MODULE)/obj +SRC_DIR:=$(TOP_DIR)/$(MODULE) + +# 源文件以及中间目标文件和依赖文件 +SRCS:=$(notdir $(wildcard $(SRC_DIR)/*.cpp)) +OBJS:=$(addprefix $(OBJ_DIR)/, $(patsubst %.cpp, %.o, $(SRCS))) +DEPS:=$(addprefix $(DEP_DIR)/, $(patsubst %.cpp, %.d,a $(SRCS))) + +# 自动生成头文件依赖选项 +DEPFLAGS=-MT $@ -MMD -MP -MF $(DEP_DIR)/$*.d + +JRTP_ROOT = $(THIRDPARTY_ROOT)/jrtp_export + +INCLUDE= -I $(TOP_DIR)/common/inc \ + -I $(TOP_DIR)/common/UtilNPP \ + -I $(TOP_DIR)/ \ + -I $(CUDA_ROOT)/include \ + -I $(JRTP_ROOT)/jrtplib/include/jrtplib3 \ + -I $(JRTP_ROOT)/jthread/include/jthread + +LIBSPATH= -L $(JRTP_ROOT)/jthread/lib -l:libjthread.a \ + -L $(JRTP_ROOT)/jrtplib/lib -l:libjrtp.a \ + -L $(CUDA_ROOT)/lib64 -lcuda -lcudart -lnvcuvid -lcurand -lcublas -lnvjpeg \ + + +CXXFLAGS= -g -O0 -fPIC $(INCLUDE) $(INCS) $(LIBS) $(LIBSPATH) $(MACROS) $(DEFS) -lpthread -lrt -lz -fexceptions -std=c++11 -fvisibility=hidden -Wl,-Bsymbolic -ldl -Wwrite-strings + +# 最终目标文件 +TARGET:=$(LIB_DIR)/$(MODULE).a + +# 默认最终目标 +.PHONY:all +all:$(TARGET) + +# 生成最终目标 +$(TARGET):$(OBJS) | $(LIB_DIR) + @echo -e "\e[32m""Linking static library $(TARGET)""\e[0m" + @echo -e "ar -rc $@ $^" + @ar -rc $@ $^ + +# 若没有lib目录则自动生成 +$(LIB_DIR): + @mkdir -p $@ + +# 生成中间目标文件 +$(OBJ_DIR)/%.o:$(SRC_DIR)/%.cpp $(DEP_DIR)/%.d | $(OBJ_DIR) $(DEP_DIR) + @echo -e "\e[33m""Building object $@""\e[0m" + @echo -e "$(CXX) -c $(DEPFLAGS) $(CXXFLAGS) -o $@ $<" + @$(CXX) -c $(DEPFLAGS) $(CXXFLAGS) -o $@ $< + +# 若没有obj目录则自动生成 +$(OBJ_DIR): + @mkdir -p $@ + +# 若没有.dep目录则自动生成 +$(DEP_DIR): + @mkdir -p $@ + +# 依赖文件会在生成中间文件的时候自动生成,这里只是为了防止报错 +$(DEPS): + +# 引入中间目标文件头文件依赖关系 +include $(wildcard $(DEPS)) + +# 直接删除组件build目录 +.PHONY:clean +clean: + @rm -rf $(BUILD_DIR)/$(MODULE) diff --git a/src/gb28181/common_header.h b/src/gb28181/common_header.h index 2f0c324..d5feed8 100644 --- a/src/gb28181/common_header.h +++ b/src/gb28181/common_header.h @@ -2,7 +2,7 @@ #define _COMMON_HEADER_H_ -#include "../logger.hpp" -#include "../utiltools.hpp" +#include "../interface/logger.hpp" +#include "../interface/utiltools.hpp" #endif \ No newline at end of file diff --git a/src/interface/AbstractDecoder.cpp b/src/interface/AbstractDecoder.cpp new file mode 100644 index 0000000..244dd45 --- /dev/null +++ b/src/interface/AbstractDecoder.cpp @@ -0,0 +1,25 @@ +#include "AbstractDecoder.h" + +#include "logger.hpp" +#include "utiltools.hpp" + + +bool AbstractDecoder::isSnapTime(){ + if(m_snap_time_interval <= 0){ + return false; + } + long cur_time = UtilTools::get_cur_time_ms(); + if(cur_time - m_last_snap_time > m_snap_time_interval){ + return true; + } + return false; +} + +void AbstractDecoder::updateLastSnapTime(){ + m_last_snap_time = UtilTools::get_cur_time_ms(); +} + +void AbstractDecoder::setSnapTimeInterval(long interval){ + m_snap_time_interval = interval; + m_last_snap_time = UtilTools::get_cur_time_ms(); +} \ No newline at end of file diff --git a/src/interface/AbstractDecoder.h b/src/interface/AbstractDecoder.h new file mode 100644 index 0000000..9f4cb3f --- /dev/null +++ b/src/interface/AbstractDecoder.h @@ -0,0 +1,54 @@ +#ifndef _ABSTRACT_DECODER_H_ +#define _ABSTRACT_DECODER_H_ + +#include "interface_headers.h" + +using namespace std; + +class AbstractDecoder{ +public: + virtual ~AbstractDecoder(){}; + virtual bool init(FFDecConfig& cfg) = 0; + virtual void close() = 0; + virtual bool start() = 0; + virtual void pause() = 0; + virtual void resume() = 0; + + virtual void setDecKeyframe(bool bKeyframe) = 0; + + virtual bool isRunning() = 0; + virtual bool isFinished() = 0; + virtual bool isPausing() = 0; + virtual bool getResolution( int &width, int &height ) = 0; + + virtual bool isSurport(FFDecConfig& cfg) = 0; + + virtual int getCachedQueueLength() = 0; + + virtual float fps() = 0; + + virtual DECODER_TYPE getDecoderType() = 0; + + virtual FFImgInfo* snapshot() = 0; + + virtual void setName(string nm) = 0; + + virtual string getName() = 0; + + virtual void setPostDecArg(const void* postDecArg) = 0; + virtual void setFinishedDecArg(const void* finishedDecArg) = 0; + +public: + bool isSnapTime(); + + void updateLastSnapTime(); + + void setSnapTimeInterval(long interval); + +public: + long m_snap_time_interval{-1}; + long m_last_snap_time; + long m_index{0}; +}; + +#endif // _ABSTRACT_DECODER_H_ \ No newline at end of file diff --git a/src/GpuRgbMemory.hpp b/src/interface/DeviceRgbMemory.hpp index 8e3d15b..b5a3125 100644 --- a/src/GpuRgbMemory.hpp +++ b/src/interface/DeviceRgbMemory.hpp @@ -1,38 +1,31 @@ +#ifndef __DEVICE_RGB_MEMORY_H__ +#define __DEVICE_RGB_MEMORY_H__ + #include -#include "cuda_kernels.h" -#include "define.hpp" #include "utiltools.hpp" using namespace std; -class GpuRgbMemory{ +class DeviceRgbMemory{ public: - GpuRgbMemory(int _channel, int _width, int _height, string _id, string _gpuid, bool _isused){ + DeviceRgbMemory(int _channel, int _width, int _height, string _id, string _dev_id, bool _key_frame, bool _isused){ channel = _channel; width = _width; height = _height; - size = channel * width * height; + data_size = channel * width * height; isused = _isused; id = _id; - gpuid = _gpuid; + device_id = _dev_id; + key_frame = _key_frame; timestamp = UtilTools::get_cur_time_ms(); - - cudaSetDevice(atoi(gpuid.c_str())); - CHECK_CUDA(cudaMalloc((void **)&pHwRgb, size * sizeof(unsigned char))); } - ~GpuRgbMemory(){ - if (pHwRgb) { - cudaSetDevice(atoi(gpuid.c_str())); - CHECK_CUDA(cudaFree(pHwRgb)); - pHwRgb = nullptr; - } - } + virtual ~DeviceRgbMemory(){} int getSize() { - return size; + return data_size; } bool isIsused() { @@ -49,8 +42,8 @@ public: return id; } - string getGpuId() { - return gpuid; + string getDeviceId() { + return device_id; } unsigned char* getMem(){ @@ -73,14 +66,21 @@ public: return channel; } -private: - int size; + bool isKeyFrame(){ + return key_frame; + } + +public: + int data_size; bool isused; string id; - string gpuid; + string device_id; unsigned char * pHwRgb{nullptr}; long long timestamp; int width{0}; int height{0}; int channel{3}; -}; \ No newline at end of file + bool key_frame; +}; + +#endif \ No newline at end of file diff --git a/src/FFNvDecoderManager.cpp b/src/interface/FFNvDecoderManager.cpp index 69a1b9b..bd05873 100644 --- a/src/FFNvDecoderManager.cpp +++ b/src/interface/FFNvDecoderManager.cpp @@ -1,7 +1,13 @@ #include "FFNvDecoderManager.h" -#include "FFNvDecoder.h" -#include "./gb28181/FFGB28181Decoder.h" +#ifdef USE_NVDEC +#include "../nvdec/FFNvDecoder.h" +#include "../gb28181/FFGB28181Decoder.h" +#endif + +#ifdef USE_DVPP +#include "./dvpp/DvppDecoderApi.h" +#endif #include "logger.hpp" @@ -25,22 +31,31 @@ AbstractDecoder* FFNvDecoderManager::createDecoder(MgrDecConfig config){ } AbstractDecoder* dec = nullptr; +#ifdef USE_NVDEC if(DECODER_TYPE_FFMPEG == config.dec_type){ dec = new FFNvDecoder(); - }else if(DECODER_TYPE_GB28181 == config.dec_type){ + } + + if(DECODER_TYPE_GB28181 == config.dec_type){ dec = new FFGB28181Decoder(); } +#endif + +#ifdef USE_DVPP + if(DECODER_TYPE_DVPP == config.dec_type){ + dec = new DvppDecoderApi(); + } +#endif if (dec == nullptr){ LOG_ERROR("没有指定解码器类型"); return nullptr; } + config.cfg.dec_name = config.name; bool bRet= dec->init(config.cfg); if (bRet) { - dec->setName(config.name) ; - dec->setSnapTimeInterval(config.snap_time_interval); decoderMap[config.name] = dec; LOG_INFO("[{}][{}]- 解码器初始化成功",config.name, config.cfg.uri); @@ -68,7 +83,7 @@ bool FFNvDecoderManager::setPostDecArg(const string name, const void * userPtr) auto dec = decoderMap.find(name); if (dec != decoderMap.end()) { - dec->second->m_postDecArg = userPtr; + dec->second->setPostDecArg(userPtr); return true; } @@ -89,7 +104,7 @@ bool FFNvDecoderManager::setFinishedDecArg(const string name, const void * userP auto dec = decoderMap.find(name); if (dec != decoderMap.end()) { - dec->second->m_finishedDecArg = userPtr; + dec->second->setFinishedDecArg(userPtr); return true; } @@ -273,11 +288,21 @@ bool FFNvDecoderManager::isSurport(MgrDecConfig& config) } AbstractDecoder* dec = nullptr; - if(config.dec_type = DECODER_TYPE_FFMPEG){ +#ifdef USE_NVDEC + if(DECODER_TYPE_FFMPEG == config.dec_type){ dec = new FFNvDecoder(); - }else if(config.dec_type = DECODER_TYPE_GB28181){ + } + + if(DECODER_TYPE_GB28181 == config.dec_type){ dec = new FFGB28181Decoder(); } +#endif + +#ifdef USE_DVPP + if(DECODER_TYPE_DVPP == config.dec_type){ + dec = new DvppDecoderApi(); + } +#endif if (dec == nullptr){ LOG_ERROR("没有指定解码器类型"); @@ -420,142 +445,10 @@ int FFNvDecoderManager::getCachedQueueLength(const string name){ return -1; } -FFImgInfo* FFNvDecoderManager::snapshot(const string& uri){ - if (uri.empty()){ - return nullptr; - } - - 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; - int index = 0; - - FFImgInfo* imgInfo = nullptr; - - //av_register_all(); - 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, "stimeout", "30000000", 0 ); // 单位为 百万分之一秒 - - ///打开输入的流 - int ret = avformat_open_input(&ifmt_ctx, uri.c_str(), nullptr, &options); - if (ret != 0){ - printf("Couldn't open input stream.\n"); - goto end_flag ; - } - - //查找流信息 - if (avformat_find_stream_info(ifmt_ctx, nullptr) < 0){ - printf("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){ - fprintf(stderr, "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_BGR24, 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){ - LOG_ERROR("Failed to receive frame: {}",ret); - continue; - } - - index ++ ; - - if (index >= 5){ - // 取解码出来的第三帧,应该可以一定程度优化花屏问题 - 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 FFNvDecoderManager::releaseFFImgInfo(FFImgInfo* info){ if(nullptr != info){ if(info->pData != nullptr){ - av_free(info->pData); + free(info->pData); info->pData = nullptr; } delete info; diff --git a/src/FFNvDecoderManager.h b/src/interface/FFNvDecoderManager.h index 744c83b..36a5381 100644 --- a/src/FFNvDecoderManager.h +++ b/src/interface/FFNvDecoderManager.h @@ -15,6 +15,8 @@ struct MgrDecConfig long snap_time_interval; // 定时抓拍时间间隔 }; +// #define USE_NVDEC +// #define USE_DVPP /** * 解码器管理类,单例类 * 谨防死锁 @@ -236,15 +238,6 @@ public: int getCachedQueueLength(const string name); /************************************************** - * 接口:snapshot - * 功能:获取视频快照 - * 参数:const string& uri 视频地址 - * 返回:FFImgInfo* 快照信息 - * 备注: - **************************************************/ - FFImgInfo* snapshot(const string& uri); - - /************************************************** * 接口:releaseFFImgInfo * 功能:释放视频快照信息 * 参数:FFImgInfo* info 视频快照信息 diff --git a/src/interface/Makefile b/src/interface/Makefile new file mode 100644 index 0000000..a856501 --- /dev/null +++ b/src/interface/Makefile @@ -0,0 +1,76 @@ +# 各项目录 +LIB_DIR:=$(BUILD_DIR)/$(MODULE)/lib +DEP_DIR:=$(BUILD_DIR)/$(MODULE)/.dep +OBJ_DIR:=$(BUILD_DIR)/$(MODULE)/obj +SRC_DIR:=$(TOP_DIR)/$(MODULE) + +# 源文件以及中间目标文件和依赖文件 +SRCS:=$(notdir $(wildcard $(SRC_DIR)/*.cpp)) +OBJS:=$(addprefix $(OBJ_DIR)/, $(patsubst %.cpp, %.o, $(SRCS))) +DEPS:=$(addprefix $(DEP_DIR)/, $(patsubst %.cpp, %.d,a $(SRCS))) + +# 自动生成头文件依赖选项 +DEPFLAGS=-MT $@ -MMD -MP -MF $(DEP_DIR)/$*.d + +JRTP_ROOT = $(THIRDPARTY_ROOT)/jrtp_export + +INCLUDE= -I $(TOP_DIR)/common/inc \ + -I $(TOP_DIR)/common/UtilNPP \ + -I $(TOP_DIR)/ \ + -I $(JRTP_ROOT)/jrtplib/include/jrtplib3 \ + -I $(JRTP_ROOT)/jthread/include/jthread \ + -I $(TOP_DIR)/src/gb28181 \ + -I $(TOP_DIR)/src/nvdec \ + -I $(CUDA_ROOT)/include \ + +LIBSPATH= -L $(JRTP_ROOT)/jthread/lib -l:libjthread.a \ + -L $(JRTP_ROOT)/jrtplib/lib -l:libjrtp.a \ + -L $(CUDA_ROOT)/lib64 -lcuda -lcudart -lnvcuvid -lcurand -lcublas -lnvjpeg \ + + +CXXFLAGS= -g -O0 -fPIC $(INCLUDE) $(LIBSPATH) $(DEFS) -lpthread -lrt -lz -fexceptions -std=c++11 -fvisibility=hidden -Wl,-Bsymbolic -ldl -Wwrite-strings + + +# 最终目标文件 +TARGET:=$(LIB_DIR)/$(MODULE).a + + +# 默认最终目标 +.PHONY:all +all:$(TARGET) + +# 生成最终目标 +$(TARGET):$(OBJS) | $(LIB_DIR) + @echo -e "\e[32m""Linking static library $(TARGET)""\e[0m" + @echo -e "ar -rc $@ $^" + @ar -rc $@ $^ + +# 若没有lib目录则自动生成 +$(LIB_DIR): + @mkdir -p $@ + +# 生成中间目标文件 +$(OBJ_DIR)/%.o:$(SRC_DIR)/%.cpp $(DEP_DIR)/%.d | $(OBJ_DIR) $(DEP_DIR) + @echo -e "\e[33m""Building object $@""\e[0m" + @echo -e "$(CXX) -c $(DEPFLAGS) $(CXXFLAGS) $(INCS) $(LIBS) $(MACROS) -o $@ $<" +# @$(CXX) -c $(DEPFLAGS) $(CXXFLAGS) $(INCS) $(LIBSPATH) $(MACROS) -o $@ $(MODULE_LIBS) $< + @$(CXX) -c $(DEPFLAGS) $(CXXFLAGS) $(INCS) $(LIBS) $(MACROS) -o $@ $< + +# 若没有obj目录则自动生成 +$(OBJ_DIR): + @mkdir -p $@ + +# 若没有.dep目录则自动生成 +$(DEP_DIR): + @mkdir -p $@ + +# 依赖文件会在生成中间文件的时候自动生成,这里只是为了防止报错 +$(DEPS): + +# 引入中间目标文件头文件依赖关系 +include $(wildcard $(DEPS)) + +# 直接删除组件build目录 +.PHONY:clean +clean: + @rm -rf $(BUILD_DIR)/$(MODULE) diff --git a/src/AbstractDecoder.h b/src/interface/interface_headers.h index b5a5665..43edcc9 100644 --- a/src/AbstractDecoder.h +++ b/src/interface/interface_headers.h @@ -1,23 +1,13 @@ -#ifndef _ABSTRACT_DECODER_H_ -#define _ABSTRACT_DECODER_H_ +#ifndef _INTERFACE_HEADERS_H_ +#define _INTERFACE_HEADERS_H_ -#include - -extern "C" -{ - #include - #include - #include - #include - #include - #include - #include - #include -} +#include #include #include +#include "DeviceRgbMemory.hpp" + using namespace std; /************************************************** @@ -31,7 +21,7 @@ using namespace std; * 非实时流时(本地/网络文件),本接口可以进行 * 阻塞/耗时操作 **************************************************/ -typedef void(*POST_DECODE_CALLBACK)(const void * userPtr, AVFrame * gpuFrame); +typedef void(*POST_DECODE_CALLBACK)(const void * userPtr, DeviceRgbMemory* devFrame); typedef void(*DECODE_FINISHED_CALLBACK)(const void* userPtr); @@ -44,6 +34,7 @@ struct FFDecConfig{ string gpuid; // gpu id bool force_tcp{true}; // 是否指定使用tcp连接 int skip_frame{1}; // 跳帧数 + string dec_name; int port; // gb28181接收数据的端口号 DECODE_REQUEST_STREAM_CALLBACK request_stream_cbk; // gb28181请求流 @@ -51,7 +42,8 @@ struct FFDecConfig{ enum DECODER_TYPE{ DECODER_TYPE_GB28181, - DECODER_TYPE_FFMPEG + DECODER_TYPE_FFMPEG, + DECODER_TYPE_DVPP }; struct FFImgInfo{ @@ -59,70 +51,9 @@ struct FFImgInfo{ int width; int height; unsigned char * pData; + int data_type; // 默认0=rgb, 1=nv12 long timestamp; long index; }; -class AbstractDecoder { -public: - virtual ~AbstractDecoder(){}; - virtual bool init(FFDecConfig& cfg) = 0; - virtual void close() = 0; - virtual bool start() = 0; - virtual void pause() = 0; - virtual void resume() = 0; - - virtual void setDecKeyframe(bool bKeyframe) = 0; - - virtual bool isRunning() = 0; - virtual bool isFinished() = 0; - virtual bool isPausing() = 0; - virtual bool getResolution( int &width, int &height ) = 0; - - virtual bool isSurport(FFDecConfig& cfg) = 0; - - virtual int getCachedQueueLength() = 0; - - virtual float fps() = 0; - - virtual DECODER_TYPE getDecoderType() = 0; - - void setName(string nm){ - m_dec_name = nm; - } - - string getName(){ - return m_dec_name; - } - - FFImgInfo* snapshot(); - - bool isSnapTime(); - - void updateLastSnapTime(); - - void setSnapTimeInterval(long interval); - -public: - const void * m_postDecArg; - POST_DECODE_CALLBACK post_decoded_cbk; - const void * m_finishedDecArg; - DECODE_FINISHED_CALLBACK decode_finished_cbk; - -public: - string m_dec_name; - - bool m_dec_keyframe; - - FFDecConfig m_cfg; - - queue mFrameQueue; - mutex m_queue_mutex; - mutex m_snapshot_mutex; - - long m_snap_time_interval{-1}; - long m_last_snap_time; - long m_index{0}; -}; - -#endif // _ABSTRACT_DECODER_H_ \ No newline at end of file +#endif \ No newline at end of file diff --git a/src/logger.hpp b/src/interface/logger.hpp index d249c3c..1d67fea 100644 --- a/src/logger.hpp +++ b/src/interface/logger.hpp @@ -8,7 +8,7 @@ #pragma once -#include "define.hpp" +// #include "define.hpp" #include #include #include @@ -28,6 +28,8 @@ #include #include +#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) + #define LOG_TRACE_WITH_LOGGER(logger, ...) {SPDLOG_LOGGER_TRACE(logger, __VA_ARGS__);} #define LOG_DEBUG_WITH_LOGGER(logger, ...) {SPDLOG_LOGGER_DEBUG(logger, __VA_ARGS__);} #define LOG_WARN_WITH_LOGGER(logger, ...) {SPDLOG_LOGGER_WARN(logger, __VA_ARGS__);} diff --git a/src/utiltools.hpp b/src/interface/utiltools.hpp index 8caff91..a156ab9 100644 --- a/src/utiltools.hpp +++ b/src/interface/utiltools.hpp @@ -1,7 +1,7 @@ #ifndef _UTIL_TOOLS_HPP_ #define _UTIL_TOOLS_HPP_ -#include +#include using namespace std; diff --git a/src/DrawImageOnGPU.cu b/src/nvdec/DrawImageOnGPU.cu index 8770cea..1fa99dc 100644 --- a/src/DrawImageOnGPU.cu +++ b/src/nvdec/DrawImageOnGPU.cu @@ -1,6 +1,6 @@ #include "cuda_kernels.h" -#include "logger.hpp" +#include "../interface/logger.hpp" typedef unsigned char uchar; typedef unsigned int uint32; diff --git a/src/FFCuContextManager.cpp b/src/nvdec/FFCuContextManager.cpp index db097d6..382c4d8 100644 --- a/src/FFCuContextManager.cpp +++ b/src/nvdec/FFCuContextManager.cpp @@ -1,9 +1,21 @@ #include "FFCuContextManager.h" -#include "logger.hpp" +#include "common_header.h" using namespace std; +extern "C" +{ + #include + #include + #include + #include + #include + #include + #include + #include +} + FFCuContextManager::~FFCuContextManager() { for(auto iter = ctxMap.begin(); iter != ctxMap.end(); iter++){ diff --git a/src/FFCuContextManager.h b/src/nvdec/FFCuContextManager.h index 3050641..758167c 100644 --- a/src/FFCuContextManager.h +++ b/src/nvdec/FFCuContextManager.h @@ -2,19 +2,10 @@ #include #include -extern "C" -{ - #include - #include - #include - #include - #include - #include - #include -} - using namespace std; +struct AVBufferRef; + class FFCuContextManager{ public: static FFCuContextManager* getInstance(){ diff --git a/src/FFNvDecoder.cpp b/src/nvdec/FFNvDecoder.cpp index 9aff5fd..e64e2a5 100644 --- a/src/FFNvDecoder.cpp +++ b/src/nvdec/FFNvDecoder.cpp @@ -8,9 +8,10 @@ #include "FFCuContextManager.h" -#include "logger.hpp" +#include "common_header.h" -#include "utiltools.hpp" +#include "GpuRgbMemory.hpp" +#include "cuda_kernels.h" using namespace std; @@ -62,6 +63,7 @@ FFNvDecoder::~FFNvDecoder() bool FFNvDecoder::init(FFDecConfig& cfg) { m_cfg = cfg; + m_dec_name = cfg.dec_name; fstream infile(cfg.uri); if (infile.is_open()){ @@ -217,16 +219,6 @@ void FFNvDecoder::decode_thread() continue; } - if (m_bReal) - { - if (m_bPause) - { - av_packet_unref(pkt); - std::this_thread::sleep_for(std::chrono::milliseconds(3)); - continue; - } - } - if (stream_index == pkt->stream_index){ result = avcodec_send_packet(avctx, pkt); if (result < 0){ @@ -245,6 +237,14 @@ void FFNvDecoder::decode_thread() } av_packet_unref(pkt); + if (m_bReal){ + if (m_bPause){ + av_frame_free(&gpuFrame); + std::this_thread::sleep_for(std::chrono::milliseconds(3)); + continue; + } + } + if(gpuFrame != nullptr){ m_queue_mutex.lock(); if(mFrameQueue.size() <= 10){ @@ -259,6 +259,7 @@ void FFNvDecoder::decode_thread() } m_bRunning = false; + av_packet_free(&pkt); // long end_time = UtilTools::get_cur_time_ms(); // cout << "解码用时:" << end_time - start_time << endl; @@ -315,7 +316,7 @@ void FFNvDecoder::post_decode_thread(){ m_queue_mutex.unlock(); // 跳帧 if (skip_frame == 1 || index % skip_frame == 0){ - post_decoded_cbk(m_postDecArg, gpuFrame); + post_decoded_cbk(m_postDecArg, convert2bgr(gpuFrame)); index = 0; } @@ -386,3 +387,127 @@ int FFNvDecoder::getCachedQueueLength(){ float FFNvDecoder::fps(){ return m_fps; } + +void FFNvDecoder::setPostDecArg(const void* postDecArg){ + m_postDecArg = postDecArg; +} + +void FFNvDecoder::setFinishedDecArg(const void* finishedDecArg){ + m_finishedDecArg = finishedDecArg; +} + +DeviceRgbMemory* FFNvDecoder::convert2bgr(AVFrame * gpuFrame){ + if (gpuFrame != nullptr && gpuFrame->format == AV_PIX_FMT_CUDA ){ + LOG_DEBUG("decode task: gpuid: {} width: {} height: {}", m_cfg.gpuid, gpuFrame->width, gpuFrame->height); + GpuRgbMemory* gpuMem = new GpuRgbMemory(3, gpuFrame->width, gpuFrame->height, getName(), m_cfg.gpuid, false, true); + + do{ + if (gpuMem->getMem() == nullptr){ + LOG_ERROR("new GpuRgbMemory failed !!!"); + break; + } + + cudaSetDevice(atoi(m_cfg.gpuid.c_str())); + cuda_common::setColorSpace( ITU_709, 0 ); + cudaError_t cudaStatus = cuda_common::CUDAToBGR((CUdeviceptr)gpuFrame->data[0],(CUdeviceptr)gpuFrame->data[1], gpuFrame->linesize[0], gpuFrame->linesize[1], gpuMem->getMem(), gpuFrame->width, gpuFrame->height); + cudaDeviceSynchronize(); + if (cudaStatus != cudaSuccess) { + LOG_ERROR("CUDAToBGR failed failed !!!"); + break; + } + + return gpuMem; + }while(0); + + delete gpuMem; + gpuMem = nullptr; + } + + return nullptr; +} + +FFImgInfo* FFNvDecoder::snapshot(){ + + // 锁住停止队列消耗 + std::lock_guard l(m_snapshot_mutex); + + AVFrame * gpuFrame = nullptr; + + bool bFirst = true; + while(true){ + m_queue_mutex.lock(); + if(mFrameQueue.size() <= 0){ + m_queue_mutex.unlock(); + if(bFirst){ + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + bFirst = false; + continue; + }else{ + // 再进来说明前面已经等了 100 ms + // 100 ms都没有等到解码数据,则退出 + return nullptr; + } + } + + // 队列中数据大于1 + gpuFrame = mFrameQueue.front(); + m_queue_mutex.unlock(); + break; + } + + if (gpuFrame != nullptr && gpuFrame->format == AV_PIX_FMT_CUDA ){ + LOG_DEBUG("decode task: gpuid: {} width: {} height: {}", m_cfg.gpuid, gpuFrame->width, gpuFrame->height); + GpuRgbMemory* gpuMem = new GpuRgbMemory(3, gpuFrame->width, gpuFrame->height, getName(), m_cfg.gpuid, false, true); + + if (gpuMem->getMem() == nullptr){ + LOG_ERROR("new GpuRgbMemory failed !!!"); + return nullptr; + } + + cudaSetDevice(atoi(m_cfg.gpuid.c_str())); + cuda_common::setColorSpace( ITU_709, 0 ); + cudaError_t cudaStatus = cuda_common::CUDAToBGR((CUdeviceptr)gpuFrame->data[0],(CUdeviceptr)gpuFrame->data[1], gpuFrame->linesize[0], gpuFrame->linesize[1], gpuMem->getMem(), gpuFrame->width, gpuFrame->height); + cudaDeviceSynchronize(); + if (cudaStatus != cudaSuccess) { + LOG_ERROR("CUDAToBGR failed failed !!!"); + return nullptr; + } + + unsigned char * pHwRgb = gpuMem->getMem(); + int channel = gpuMem->getChannel(); + int width = gpuMem->getWidth(); + int height = gpuMem->getHeight(); + + if (pHwRgb != nullptr && channel > 0 && width > 0 && height > 0){ + int nSize = channel * height * width; + + LOG_INFO("channel:{} height:{} width:{}", channel, height, width); + // unsigned char* cpu_data = new unsigned char[nSize]; + + unsigned char* cpu_data = (unsigned char *)av_malloc(nSize * sizeof(unsigned char)); + + cudaMemcpy(cpu_data, pHwRgb, nSize * sizeof(unsigned char), cudaMemcpyDeviceToHost); + cudaDeviceSynchronize(); + + delete gpuMem; + gpuMem = nullptr; + + FFImgInfo* imgInfo = new FFImgInfo(); + imgInfo->dec_name = m_dec_name; + imgInfo->pData = cpu_data; + imgInfo->height = height; + imgInfo->width = width; + imgInfo->timestamp = UtilTools::get_cur_time_ms(); + imgInfo->index = m_index; + + m_index++; + + return imgInfo; + } + + delete gpuMem; + gpuMem = nullptr; + } + + return nullptr; +} \ No newline at end of file diff --git a/src/FFNvDecoder.h b/src/nvdec/FFNvDecoder.h index 68d2a2f..4784ab6 100644 --- a/src/FFNvDecoder.h +++ b/src/nvdec/FFNvDecoder.h @@ -1,13 +1,27 @@ #include #include -#include "AbstractDecoder.h" - #include +extern "C" +{ + #include + #include + #include + #include + #include + #include + #include + #include +} + +#include "common_header.h" + +#include "../interface/AbstractDecoder.h" + using namespace std; -class FFNvDecoder : public AbstractDecoder{ +class FFNvDecoder : public AbstractDecoder { public: FFNvDecoder(); ~FFNvDecoder(); @@ -32,6 +46,19 @@ public: DECODER_TYPE getDecoderType(){ return DECODER_TYPE_FFMPEG; } + FFImgInfo* snapshot(); + + void setName(string nm){ + m_dec_name = nm; + } + + string getName(){ + return m_dec_name; + } + + void setPostDecArg(const void* postDecArg); + void setFinishedDecArg(const void* finishedDecArg); + public: AVPixelFormat getHwPixFmt(); @@ -41,7 +68,12 @@ private: bool init(const char* uri, const char* gpuid, bool force_tcp); void decode_finished(); + DeviceRgbMemory* convert2bgr(AVFrame * gpuFrame); + private: + string m_dec_name; + FFDecConfig m_cfg; + AVStream* stream; AVCodecContext *avctx; int stream_index; @@ -59,4 +91,17 @@ private: bool m_bReal; // 是否实时流 float m_fps; + + queue mFrameQueue; + mutex m_queue_mutex; + mutex m_snapshot_mutex; + long m_index{0}; + + bool m_dec_keyframe; + + const void * m_postDecArg; + POST_DECODE_CALLBACK post_decoded_cbk; // 解码数据回调接口 + + const void * m_finishedDecArg; + DECODE_FINISHED_CALLBACK decode_finished_cbk; }; \ No newline at end of file diff --git a/src/nvdec/GpuRgbMemory.hpp b/src/nvdec/GpuRgbMemory.hpp new file mode 100644 index 0000000..35eac65 --- /dev/null +++ b/src/nvdec/GpuRgbMemory.hpp @@ -0,0 +1,34 @@ +#include + +#include "../interface/DeviceRgbMemory.hpp" +#include "cuda_kernels.h" +#include "define.hpp" +#include "common_header.h" + +using namespace std; + +class GpuRgbMemory : public DeviceRgbMemory{ + +public: + GpuRgbMemory(int _channel, int _width, int _height, string _id, string _gpuid, bool _key_frame, bool _isused) + :DeviceRgbMemory(_channel, _width, _height, _id, _gpuid, _key_frame, _isused){ + gpuid = _gpuid; + cudaSetDevice(atoi(gpuid.c_str())); + CHECK_CUDA(cudaMalloc((void **)&pHwRgb, data_size * sizeof(unsigned char))); + } + + ~GpuRgbMemory(){ + if (pHwRgb) { + cudaSetDevice(atoi(gpuid.c_str())); + CHECK_CUDA(cudaFree(pHwRgb)); + pHwRgb = nullptr; + } + } + + string getGpuId() { + return gpuid; + } + +private: + string gpuid; +}; \ No newline at end of file diff --git a/src/ImageSaveGPU.cpp b/src/nvdec/ImageSaveGPU.cpp index 9382a27..dde9b64 100644 --- a/src/ImageSaveGPU.cpp +++ b/src/nvdec/ImageSaveGPU.cpp @@ -1,6 +1,6 @@ #include "cuda_kernels.h" -#include "logger.hpp" +#include "common_header.h" //int saveJPEG(const char *szOutputFile, float* d_srcRGB, int img_width, int img_height) diff --git a/src/ImageSaveGPU.h b/src/nvdec/ImageSaveGPU.h index 272a6d2..272a6d2 100644 --- a/src/ImageSaveGPU.h +++ b/src/nvdec/ImageSaveGPU.h diff --git a/src/nvdec/Makefile b/src/nvdec/Makefile new file mode 100644 index 0000000..2a6afb2 --- /dev/null +++ b/src/nvdec/Makefile @@ -0,0 +1,90 @@ +# 各项目录 +LIB_DIR:=$(BUILD_DIR)/$(MODULE)/lib +DEP_DIR:=$(BUILD_DIR)/$(MODULE)/.dep +OBJ_DIR:=$(BUILD_DIR)/$(MODULE)/obj +SRC_DIR:=$(TOP_DIR)/$(MODULE) + +# 源文件以及中间目标文件和依赖文件 +SRCS:=$(notdir $(wildcard $(SRC_DIR)/*.cpp)) +OBJS:=$(addprefix $(OBJ_DIR)/, $(patsubst %.cpp, %.o, $(SRCS))) +DEPS:=$(addprefix $(DEP_DIR)/, $(patsubst %.cpp, %.d,a $(SRCS))) + + +NVCC = $(CUDA_ROOT)/bin/nvcc + +# 自动生成头文件依赖选项 +DEPFLAGS=-MT $@ -MMD -MP -MF $(DEP_DIR)/$*.d + +DEFS = + +# 最终目标文件 +TARGET:=$(LIB_DIR)/$(MODULE).a + + +JRTP_ROOT = $(THIRDPARTY_ROOT)/jrtp_export + +INCLUDE= -I $(TOP_DIR)/common/inc \ + -I $(TOP_DIR)/common/UtilNPP \ + -I $(TOP_DIR) \ + -I $(CUDA_ROOT)/include \ + -I $(JRTP_ROOT)/jrtplib/include/jrtplib3 \ + -I $(JRTP_ROOT)/jthread/include/jthread + +LIBSPATH= -L $(JRTP_ROOT)/jthread/lib -l:libjthread.a \ + -L $(JRTP_ROOT)/jrtplib/lib -l:libjrtp.a \ + -L $(CUDA_ROOT)/lib64 -lcuda -lcudart -lnvcuvid -lcurand -lcublas -lnvjpeg \ + +CXXFLAGS= -g -O0 -fPIC $(INCLUDE) $(LIBSPATH) $(DEFS) $(INCS) $(LIBS) $(MACROS) -lpthread -lrt -lz -fexceptions -std=c++11 -fvisibility=hidden -Wl,-Bsymbolic -ldl -Wwrite-strings + # -DUNICODE -D_UNICODE + +NFLAGS_LIB=-g -c -shared -Xcompiler -fPIC +NFLAGS = $(NFLAGS_LIB) $(INCLUDE) $(LIBSPATH) -std=c++11 + +CU_SOURCES:=$(notdir $(wildcard $(SRC_DIR)/*.cu)) +CU_OBJS:=$(addprefix $(OBJ_DIR)/, $(patsubst %.cu, %.o, $(CU_SOURCES))) + + +# 默认最终目标 +.PHONY:all +all:$(TARGET) + +# 生成最终目标 +$(TARGET):$(OBJS) $(CU_OBJS) | $(LIB_DIR) + @echo -e "\e[32m""Linking static library $(TARGET)""\e[0m" + @echo -e "ar -rc $@ $^" + @ar -rc $@ $^ + +# 若没有lib目录则自动生成 +$(LIB_DIR): + @mkdir -p $@ + +# 生成中间目标文件 +$(OBJ_DIR)/%.o:$(SRC_DIR)/%.cpp $(DEP_DIR)/%.d | $(OBJ_DIR) $(DEP_DIR) + @echo -e "\e[33m""Building object $@""\e[0m" + @echo "$(CXX) -c $(DEPFLAGS) $(CXXFLAGS) -o $@ $<" + @$(CXX) -c $(DEPFLAGS) $(CXXFLAGS) -o $@ $< + +$(OBJ_DIR)%.o:$(SRC_DIR)/%.cu + @echo -e "\e[33m""Building object $@""\e[0m" + @echo "$(NVCC) $(NFLAGS) $(INCS) $(LIBS) -o $@ $<" + $(NVCC) $(NFLAGS) $(INCS) $(LIBS) -o $@ $< + + +# 若没有obj目录则自动生成 +$(OBJ_DIR): + @mkdir -p $@ + +# 若没有.dep目录则自动生成 +$(DEP_DIR): + @mkdir -p $@ + +# 依赖文件会在生成中间文件的时候自动生成,这里只是为了防止报错 +$(DEPS): + +# 引入中间目标文件头文件依赖关系 +include $(wildcard $(DEPS)) + +# 直接删除组件build目录 +.PHONY:clean +clean: + @rm -rf $(BUILD_DIR)/$(MODULE) diff --git a/src/NV12ToRGB.cu b/src/nvdec/NV12ToRGB.cu index 58e1dff..68e54ac 100644 --- a/src/NV12ToRGB.cu +++ b/src/nvdec/NV12ToRGB.cu @@ -2,7 +2,7 @@ #include "cuda_kernels.h" #include -#include "common/inc/helper_cuda_drvapi.h" +#include "helper_cuda_drvapi.h" typedef unsigned char uint8; typedef unsigned int uint32; diff --git a/src/nvdec/NvDecoderApi.cpp b/src/nvdec/NvDecoderApi.cpp new file mode 100644 index 0000000..efb63cd --- /dev/null +++ b/src/nvdec/NvDecoderApi.cpp @@ -0,0 +1,133 @@ +#include "NvDecoderApi.h" +#include "FFNvDecoder.h" + +NvDecoderApi::NvDecoderApi(){ + m_pDecoder = nullptr; +} + +NvDecoderApi::~NvDecoderApi(){ + if(m_pDecoder != nullptr){ + delete m_pDecoder; + m_pDecoder = nullptr; + } +} + +bool NvDecoderApi::init(FFDecConfig& cfg){ + m_pDecoder = new FFNvDecoder(); + if(m_pDecoder != nullptr){ + return m_pDecoder->init(cfg); + } + return false; +} + +void NvDecoderApi::close(){ + if(m_pDecoder != nullptr){ + return m_pDecoder->close(); + } +} + +bool NvDecoderApi::start(){ + if(m_pDecoder != nullptr){ + return m_pDecoder->start(); + } + return false; +} + +void NvDecoderApi::pause(){ + if(m_pDecoder != nullptr){ + return m_pDecoder->pause(); + } +} + +void NvDecoderApi::resume(){ + if(m_pDecoder != nullptr){ + return m_pDecoder->resume(); + } +} + +void NvDecoderApi::setDecKeyframe(bool bKeyframe){ + if(m_pDecoder != nullptr){ + return m_pDecoder->setDecKeyframe(bKeyframe); + } +} + +bool NvDecoderApi::isRunning(){ + if(m_pDecoder != nullptr){ + return m_pDecoder->isRunning(); + } + return false; +} + +bool NvDecoderApi::isFinished(){ + if(m_pDecoder != nullptr){ + return m_pDecoder->isFinished(); + } + return false; +} + +bool NvDecoderApi::isPausing(){ + if(m_pDecoder != nullptr){ + return m_pDecoder->isPausing(); + } + return false; +} + +bool NvDecoderApi::getResolution(int &width, int &height){ + if(m_pDecoder != nullptr){ + return m_pDecoder->getResolution(width, height); + } + return false; +} + +bool NvDecoderApi::isSurport(FFDecConfig& cfg){ + if(m_pDecoder != nullptr){ + return m_pDecoder->isSurport(cfg); + } + return false; +} + +float NvDecoderApi::fps(){ + if(m_pDecoder != nullptr){ + return m_pDecoder->fps(); + } + return 0.0; +} + +int NvDecoderApi::getCachedQueueLength(){ + if(m_pDecoder != nullptr){ + return m_pDecoder->getCachedQueueLength(); + } + return 0; +} + +void NvDecoderApi::setName(string nm){ + if(m_pDecoder != nullptr){ + return m_pDecoder->setName(nm); + } +} + +string NvDecoderApi::getName(){ + if(m_pDecoder != nullptr){ + return m_pDecoder->getName(); + } + return nullptr; +} + +FFImgInfo* NvDecoderApi::snapshot(){ + if(m_pDecoder != nullptr){ + return m_pDecoder->snapshot(); + } + return nullptr; +} + +void NvDecoderApi::setPostDecArg(const void* postDecArg){ + if(m_pDecoder != nullptr){ + return m_pDecoder->setPostDecArg(postDecArg); + } +} + +void NvDecoderApi::setFinishedDecArg(const void* finishedDecArg){ + if(m_pDecoder != nullptr){ + return m_pDecoder->setFinishedDecArg(finishedDecArg); + } +} \ No newline at end of file diff --git a/src/nvdec/NvDecoderApi.h b/src/nvdec/NvDecoderApi.h new file mode 100644 index 0000000..f742dd8 --- /dev/null +++ b/src/nvdec/NvDecoderApi.h @@ -0,0 +1,44 @@ +#include +#include + +#include "common_header.h" +#include "../interface/AbstractDecoder.h" + +using namespace std; + +class FFNvDecoder; + +class NvDecoderApi : public AbstractDecoder{ +public: + NvDecoderApi(); + ~NvDecoderApi(); + bool init(FFDecConfig& cfg); + void close(); + bool start(); + void pause(); + void resume(); + + void setDecKeyframe(bool bKeyframe); + + bool isRunning(); + bool isFinished(); + bool isPausing(); + bool getResolution( int &width, int &height ); + + bool isSurport(FFDecConfig& cfg); + + int getCachedQueueLength(); + + float fps(); + + FFImgInfo* snapshot(); + + DECODER_TYPE getDecoderType(){ return DECODER_TYPE_DVPP; } + void setName(string nm); + string getName(); + + void setPostDecArg(const void* postDecArg); + void setFinishedDecArg(const void* finishedDecArg); +private: + FFNvDecoder* m_pDecoder; +}; \ No newline at end of file diff --git a/src/NvJpegEncoder.cpp b/src/nvdec/NvJpegEncoder.cpp index 7ee0727..7ee0727 100644 --- a/src/NvJpegEncoder.cpp +++ b/src/nvdec/NvJpegEncoder.cpp diff --git a/src/NvJpegEncoder.h b/src/nvdec/NvJpegEncoder.h index 3c27ba8..3c27ba8 100644 --- a/src/NvJpegEncoder.h +++ b/src/nvdec/NvJpegEncoder.h diff --git a/src/PartMemCopy.cu b/src/nvdec/PartMemCopy.cu index 396765b..396765b 100644 --- a/src/PartMemCopy.cu +++ b/src/nvdec/PartMemCopy.cu diff --git a/src/RGB2YUV.cu b/src/nvdec/RGB2YUV.cu index 7202c3a..7202c3a 100644 --- a/src/RGB2YUV.cu +++ b/src/nvdec/RGB2YUV.cu diff --git a/src/ResizeImage.cu b/src/nvdec/ResizeImage.cu index fdc6961..fdc6961 100644 --- a/src/ResizeImage.cu +++ b/src/nvdec/ResizeImage.cu diff --git a/src/nvdec/common_header.h b/src/nvdec/common_header.h new file mode 100644 index 0000000..cf45c91 --- /dev/null +++ b/src/nvdec/common_header.h @@ -0,0 +1,9 @@ +#ifndef _COMMON_HEADER_H_ +#define _COMMON_HEADER_H_ + + +#include "../interface/logger.hpp" +#include "../interface/utiltools.hpp" +#include "../interface/interface_headers.h" + +#endif \ No newline at end of file diff --git a/src/cuda_kernels.h b/src/nvdec/cuda_kernels.h index cd1eb00..cd1eb00 100644 --- a/src/cuda_kernels.h +++ b/src/nvdec/cuda_kernels.h diff --git a/src/define.hpp b/src/nvdec/define.hpp index 26fcc61..ed20540 100644 --- a/src/define.hpp +++ b/src/nvdec/define.hpp @@ -2,12 +2,10 @@ #include -#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) - #define CHECK_CUDA(call) \ {\ const cudaError_t error_code = call;\ if (cudaSuccess != error_code)\ LOG_ERROR("CUDA error, code: {} reason: {}", error_code, cudaGetErrorString(error_code));\ -} \ No newline at end of file +} diff --git a/src/jpegNPP.cpp-1 b/src/nvdec/jpegNPP.cpp-1 index f0bf2e6..f0bf2e6 100644 --- a/src/jpegNPP.cpp-1 +++ b/src/nvdec/jpegNPP.cpp-1