-
mentioned in commit 34cc7f89b1d64f58347defb7fe99928917a8a2f5
-
Status changed to merged
-
2.添加DECODE_FINISHED_CALLBACK 3.添加isPausing接口 4.添加getCachedQueueLength接口 5.添加snapshot和releaseFFImgInfo接口 6.测试代码添加log回调的自定义设置
Showing
16 changed files
.vscode/launch.json
.vscode/settings.json
... | ... | @@ -10,6 +10,57 @@ |
10 | 10 | "iostream": "cpp", |
11 | 11 | "thread": "cpp", |
12 | 12 | "nvdec.h": "c", |
13 | - "chrono": "cpp" | |
13 | + "chrono": "cpp", | |
14 | + "atomic": "cpp", | |
15 | + "bit": "cpp", | |
16 | + "*.tcc": "cpp", | |
17 | + "bitset": "cpp", | |
18 | + "cctype": "cpp", | |
19 | + "clocale": "cpp", | |
20 | + "cmath": "cpp", | |
21 | + "codecvt": "cpp", | |
22 | + "condition_variable": "cpp", | |
23 | + "cstdarg": "cpp", | |
24 | + "cstddef": "cpp", | |
25 | + "cstdint": "cpp", | |
26 | + "cstdio": "cpp", | |
27 | + "cstdlib": "cpp", | |
28 | + "cstring": "cpp", | |
29 | + "ctime": "cpp", | |
30 | + "cwchar": "cpp", | |
31 | + "cwctype": "cpp", | |
32 | + "deque": "cpp", | |
33 | + "map": "cpp", | |
34 | + "set": "cpp", | |
35 | + "unordered_map": "cpp", | |
36 | + "vector": "cpp", | |
37 | + "exception": "cpp", | |
38 | + "algorithm": "cpp", | |
39 | + "functional": "cpp", | |
40 | + "iterator": "cpp", | |
41 | + "memory": "cpp", | |
42 | + "memory_resource": "cpp", | |
43 | + "numeric": "cpp", | |
44 | + "optional": "cpp", | |
45 | + "random": "cpp", | |
46 | + "ratio": "cpp", | |
47 | + "system_error": "cpp", | |
48 | + "tuple": "cpp", | |
49 | + "type_traits": "cpp", | |
50 | + "utility": "cpp", | |
51 | + "fstream": "cpp", | |
52 | + "initializer_list": "cpp", | |
53 | + "iomanip": "cpp", | |
54 | + "istream": "cpp", | |
55 | + "limits": "cpp", | |
56 | + "mutex": "cpp", | |
57 | + "new": "cpp", | |
58 | + "ostream": "cpp", | |
59 | + "sstream": "cpp", | |
60 | + "stdexcept": "cpp", | |
61 | + "streambuf": "cpp", | |
62 | + "cfenv": "cpp", | |
63 | + "cinttypes": "cpp", | |
64 | + "__nullptr": "cpp" | |
14 | 65 | } |
15 | 66 | } |
16 | 67 | \ No newline at end of file | ... | ... |
check_tool/FFCuContextManager.cpp
0 → 100644
1 | +#include "FFCuContextManager.h" | |
2 | +#include <iostream> | |
3 | + | |
4 | +using namespace std; | |
5 | + | |
6 | +FFCuContextManager::~FFCuContextManager() | |
7 | +{ | |
8 | + for(auto iter = ctxMap.begin(); iter != ctxMap.end(); iter++){ | |
9 | + av_buffer_unref(&iter->second); | |
10 | + } | |
11 | + ctxMap.clear(); | |
12 | +} | |
13 | + | |
14 | +AVBufferRef *FFCuContextManager::getCuCtx(string gpuid) | |
15 | +{ | |
16 | + AVBufferRef *hw_device_ctx = ctxMap[gpuid]; | |
17 | + if (nullptr == hw_device_ctx) | |
18 | + { | |
19 | + // 初始化硬件解码器 | |
20 | + if (av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_CUDA, gpuid.c_str(), nullptr, 0) < 0) | |
21 | + { | |
22 | + av_log(nullptr, AV_LOG_ERROR, "Failed to create specified HW device ! \n"); | |
23 | + return nullptr; | |
24 | + } | |
25 | + ctxMap[gpuid] = hw_device_ctx; | |
26 | + } | |
27 | + return hw_device_ctx; | |
28 | +} | |
0 | 29 | \ No newline at end of file | ... | ... |
check_tool/FFCuContextManager.h
0 → 100644
1 | + | |
2 | +#include<map> | |
3 | +#include<string> | |
4 | + | |
5 | +extern "C" | |
6 | +{ | |
7 | + #include <libavcodec/avcodec.h> | |
8 | + #include <libavdevice/avdevice.h> | |
9 | + #include <libavformat/avformat.h> | |
10 | + #include <libavfilter/avfilter.h> | |
11 | + #include <libavutil/avutil.h> | |
12 | + #include <libavutil/pixdesc.h> | |
13 | + #include <libswscale/swscale.h> | |
14 | +} | |
15 | + | |
16 | +using namespace std; | |
17 | + | |
18 | +class FFCuContextManager{ | |
19 | +public: | |
20 | + static FFCuContextManager* getInstance(){ | |
21 | + static FFCuContextManager* singleton = nullptr; | |
22 | + if (singleton == nullptr){ | |
23 | + singleton = new FFCuContextManager(); | |
24 | + } | |
25 | + return singleton; | |
26 | + } | |
27 | + | |
28 | + AVBufferRef *getCuCtx(string gpuid); | |
29 | + | |
30 | +private: | |
31 | + FFCuContextManager(){} | |
32 | + ~FFCuContextManager(); | |
33 | + | |
34 | +private: | |
35 | + map<string,AVBufferRef *> ctxMap; | |
36 | + | |
37 | +}; | |
0 | 38 | \ No newline at end of file | ... | ... |
check_tool/Makefile
0 → 100644
1 | + | |
2 | +XX = g++ | |
3 | +NVCC = nvcc | |
4 | + | |
5 | +PROJECT_ROOT= /mnt/e/fiss/FFNvDecoder | |
6 | + | |
7 | +DEPEND_DIR = $(PROJECT_ROOT)/bin | |
8 | +SRC_ROOT = $(PROJECT_ROOT)/check_tool | |
9 | +CUDA_ROOT = /usr/local/cuda | |
10 | + | |
11 | +TARGET= $(DEPEND_DIR)/lib/check_tool | |
12 | + | |
13 | + | |
14 | +INCLUDE= -I $(DEPEND_DIR)/include \ | |
15 | + -I $(CUDA_ROOT)/include \ | |
16 | + -I $(SRC_ROOT)\ | |
17 | + | |
18 | +LIBSPATH= -L $(DEPEND_DIR)/lib -lavformat -lavcodec -lswscale -lavutil -lavfilter -lswresample -lavdevice \ | |
19 | + -L $(CUDA_ROOT)/lib64 -lcudart -lcurand -lcublas -lnvjpeg \ | |
20 | + -L /usr/lib/wsl/lib -lcuda -lnvcuvid\ | |
21 | + | |
22 | +CFLAGS= -g -fPIC -O0 $(INCLUDE) -pthread -lrt -lz -std=c++11 -fvisibility=hidden -Wl,-Bsymbolic -ldl | |
23 | + # -DUNICODE -D_UNICODE | |
24 | + | |
25 | +NFLAGS_LIB=-g -c -shared -Xcompiler -fPIC -Xcompiler -fvisibility=hidden | |
26 | +NFLAGS = $(NFLAGS_LIB) $(INCLUDE) -std=c++11 | |
27 | + | |
28 | +SRCS:=$(wildcard $(SRC_ROOT)/*.cpp) | |
29 | +OBJS = $(patsubst %.cpp, %.o, $(notdir $(SRCS))) | |
30 | + | |
31 | +CU_SOURCES = $(wildcard ${SRC_ROOT}/*.cu) | |
32 | +CU_OBJS = $(patsubst %.cu, %.o, $(notdir $(CU_SOURCES))) | |
33 | + | |
34 | + | |
35 | +$(TARGET):$(OBJS) $(CU_OBJS) | |
36 | + rm -f $(TARGET) | |
37 | + $(XX) -o $@ $^ $(CFLAGS) $(LIBSPATH) $(LIBS) -Wwrite-strings | |
38 | + rm -f *.o | |
39 | + | |
40 | +%.o:$(SRC_ROOT)/%.cpp | |
41 | + $(XX) $(CFLAGS) -c $< | |
42 | + | |
43 | +%.o:$(SRC_ROOT)/%.cu | |
44 | + @echo "#######################CU_OBJS:$@###############" | |
45 | + $(NVCC) $(NFLAGS) -o $@ $< | |
46 | + | |
47 | +clean: | |
48 | + rm -f *.o $(TARGET) | |
49 | + | |
50 | + | ... | ... |
check_tool/check_tool.cpp
0 → 100644
1 | +#include"check_tool.h" | |
2 | + | |
3 | +#include "FFCuContextManager.h" | |
4 | + | |
5 | +extern "C" | |
6 | +{ | |
7 | + #include <libavcodec/avcodec.h> | |
8 | + #include <libavdevice/avdevice.h> | |
9 | + #include <libavformat/avformat.h> | |
10 | + #include <libavfilter/avfilter.h> | |
11 | + #include <libavutil/avutil.h> | |
12 | + #include <libavutil/pixdesc.h> | |
13 | + #include <libswscale/swscale.h> | |
14 | + #include <libavutil/imgutils.h> | |
15 | +} | |
16 | + | |
17 | +#include <chrono> | |
18 | + | |
19 | +static AVPixelFormat get_hw_format(AVCodecContext *avctx, const AVPixelFormat *pix_fmts){ | |
20 | + | |
21 | + const AVPixelFormat *p; | |
22 | + | |
23 | + for (p = pix_fmts; *p != -1; p++) { | |
24 | + if (*p == AV_PIX_FMT_CUDA) | |
25 | + return *p; | |
26 | + } | |
27 | + | |
28 | + av_log(nullptr, AV_LOG_ERROR, "Failed to get HW surface format. \n"); | |
29 | + return AV_PIX_FMT_NONE; | |
30 | +} | |
31 | + | |
32 | +static long long get_cur_time(){ | |
33 | + // 获取操作系统当前时间点(精确到微秒) | |
34 | + chrono::time_point<chrono::system_clock, chrono::milliseconds> tpMicro | |
35 | + = chrono::time_point_cast<chrono::milliseconds>(chrono::system_clock::now()); | |
36 | + // (微秒精度的)时间点 => (微秒精度的)时间戳 | |
37 | + time_t currentTime = tpMicro.time_since_epoch().count(); | |
38 | + | |
39 | + return (long long )currentTime; | |
40 | +} | |
41 | + | |
42 | +void evalQuality(const string& uri, const char* gpuid){ | |
43 | + AVFormatContext* ifmt_ctx = nullptr; | |
44 | + AVCodecContext* codec_ctx = nullptr; | |
45 | + AVCodec *decoder = nullptr; | |
46 | + AVCodec* codec = nullptr; | |
47 | + AVPacket* pkt = nullptr; | |
48 | + int video_index = -1; | |
49 | + AVStream* st = nullptr; | |
50 | + SwsContext *img_convert_ctx = nullptr; | |
51 | + uint8_t *buffer = nullptr; | |
52 | + int numBytes = 0; | |
53 | + | |
54 | + long start_time = 0; | |
55 | + long end_time = 0; | |
56 | + long s_time = 0; | |
57 | + long e_time = 0; | |
58 | + long long sum = 0; | |
59 | + double avg_time = 0.0; | |
60 | + | |
61 | + int sep = 0; | |
62 | + | |
63 | + string cuvid_dec_name = "" ; | |
64 | + FFCuContextManager* pCtxMgr = FFCuContextManager::getInstance(); | |
65 | + AVDictionary *op = nullptr; | |
66 | + AVBufferRef *hw_device_ctx = nullptr; | |
67 | + | |
68 | + | |
69 | + avformat_network_init(); | |
70 | + | |
71 | + // 打开输入视频文件 | |
72 | + AVDictionary *options = nullptr; | |
73 | + av_dict_set( &options, "bufsize", "655360", 0 ); | |
74 | + av_dict_set( &options, "rtsp_transport", "tcp", 0 ); | |
75 | + // av_dict_set( &options, "listen_timeout", "30", 0 ); // 单位为s | |
76 | + av_dict_set( &options, "stimeout", "30000000", 0 ); // 单位为 百万分之一秒 | |
77 | + | |
78 | + ///打开输入的流 | |
79 | + ifmt_ctx = avformat_alloc_context(); | |
80 | + int ret = avformat_open_input(&ifmt_ctx, uri.c_str(), nullptr, &options); | |
81 | + if (ret != 0){ | |
82 | + av_log(nullptr, AV_LOG_ERROR, "Couldn't open input stream ! \n"); | |
83 | + goto end_flag ; | |
84 | + } | |
85 | + | |
86 | + //查找流信息 | |
87 | + if (avformat_find_stream_info(ifmt_ctx, nullptr) < 0){ | |
88 | + av_log(nullptr, AV_LOG_ERROR, "Couldn't find stream information ! \n"); | |
89 | + goto end_flag ; | |
90 | + } | |
91 | + | |
92 | + // 查找视频流信息 | |
93 | + video_index = av_find_best_stream(ifmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &decoder, 0); | |
94 | + if (video_index < 0) { | |
95 | + av_log(nullptr, AV_LOG_ERROR, "Cannot find a video stream in the input file ! \n"); | |
96 | + goto end_flag ; | |
97 | + } | |
98 | + | |
99 | + cuvid_dec_name = string(decoder->name) + "_cuvid"; | |
100 | + codec = avcodec_find_decoder_by_name(cuvid_dec_name.c_str()); | |
101 | + if (!codec){ | |
102 | + av_log(nullptr, AV_LOG_ERROR, "Codec not found ! \n"); | |
103 | + goto end_flag ; | |
104 | + } | |
105 | + | |
106 | + //申请AVCodecContext | |
107 | + codec_ctx = avcodec_alloc_context3(codec); | |
108 | + if (!codec_ctx){ | |
109 | + goto end_flag ; | |
110 | + } | |
111 | + | |
112 | + st = ifmt_ctx->streams[video_index]; | |
113 | + if(avcodec_parameters_to_context(codec_ctx, st->codecpar) < 0){ | |
114 | + goto end_flag ; | |
115 | + } | |
116 | + | |
117 | + { | |
118 | + av_log(nullptr, AV_LOG_INFO, "path: %s \n", ifmt_ctx->url); | |
119 | + av_log(nullptr, AV_LOG_INFO, "format: %s \n", ifmt_ctx->iformat->name); | |
120 | + const char* profile = avcodec_profile_name(codec_ctx->codec_id, codec_ctx->profile); | |
121 | + av_log(nullptr, AV_LOG_INFO, "codec: %s(%s) \n", decoder->name, profile); | |
122 | + const char* pix_fmt_name = av_get_pix_fmt_name(codec_ctx->pix_fmt); | |
123 | + av_log(nullptr, AV_LOG_INFO, "pix_fmt_name: %s \n", pix_fmt_name); | |
124 | + av_log(nullptr, AV_LOG_INFO, "width x height: %dX%d \n", st->codecpar->width, st->codecpar->height); | |
125 | + | |
126 | + av_log(NULL, AV_LOG_INFO, "frame_rate: %1.0f ", av_q2d(st->r_frame_rate)); | |
127 | + av_log(NULL, AV_LOG_INFO, " --> reference PPS: %f ms\n", 1/av_q2d(st->r_frame_rate) * 1000); | |
128 | + | |
129 | + } | |
130 | + | |
131 | + // 设置解码器管理器的像素格式回调函数 | |
132 | + codec_ctx->get_format = get_hw_format; | |
133 | + | |
134 | + hw_device_ctx = pCtxMgr->getCuCtx(gpuid); | |
135 | + if(nullptr == hw_device_ctx){ | |
136 | + av_log(nullptr, AV_LOG_ERROR, "create CUDA context failed ! \n"); | |
137 | + goto end_flag ; | |
138 | + } | |
139 | + codec_ctx->hw_device_ctx = av_buffer_ref(hw_device_ctx); | |
140 | + if (nullptr == codec_ctx->hw_device_ctx){ | |
141 | + goto end_flag ; | |
142 | + } | |
143 | + | |
144 | + // 打开解码器流 | |
145 | + av_dict_set( &op, "gpu", gpuid, 0 ); | |
146 | + if (avcodec_open2(codec_ctx, codec, &op) < 0) { | |
147 | + av_log(nullptr, AV_LOG_ERROR, "Failed to open codec for stream ! \n"); | |
148 | + goto end_flag ; | |
149 | + } | |
150 | + | |
151 | + s_time = get_cur_time(); | |
152 | + start_time = get_cur_time(); | |
153 | + pkt = av_packet_alloc(); | |
154 | + while (av_read_frame(ifmt_ctx, pkt) >= 0){ | |
155 | + end_time = get_cur_time(); | |
156 | + sum ++ ; | |
157 | + sep ++ ; | |
158 | + if(end_time - start_time > 1000){ | |
159 | + avg_time = double(end_time - start_time) / sep; | |
160 | + start_time = get_cur_time(); | |
161 | + sep = 0; | |
162 | + av_log(nullptr, AV_LOG_INFO, "PPS: %f ms\n", avg_time); | |
163 | + } | |
164 | + av_packet_unref(pkt); | |
165 | + } | |
166 | + | |
167 | + e_time = get_cur_time(); | |
168 | + avg_time = double(e_time - s_time) / sum; | |
169 | + av_log(nullptr, AV_LOG_INFO, "TOOTAL PPS: %f ms\n", avg_time); | |
170 | + | |
171 | +end_flag: | |
172 | + if (codec_ctx != nullptr){ | |
173 | + avcodec_close(codec_ctx); | |
174 | + avcodec_free_context(&codec_ctx); | |
175 | + } | |
176 | + | |
177 | + if (ifmt_ctx != nullptr){ | |
178 | + avformat_close_input(&ifmt_ctx); | |
179 | + } | |
180 | + | |
181 | + if (pkt != nullptr){ | |
182 | + av_packet_free(&pkt); | |
183 | + } | |
184 | +} | |
0 | 185 | \ No newline at end of file | ... | ... |
check_tool/check_tool.h
0 → 100644
check_tool/main.cpp
0 → 100644
1 | +#include"check_tool.h" | |
2 | + | |
3 | +#include <cuda.h> | |
4 | + | |
5 | +#include<iostream> | |
6 | + | |
7 | +using namespace std; | |
8 | + | |
9 | + | |
10 | +#define checkCudaErrors(S) do {CUresult status; \ | |
11 | + status = S; \ | |
12 | + if (status != CUDA_SUCCESS ) {std::cout << __LINE__ <<" checkCudaErrors - status = " << status << std::endl; \ | |
13 | + exit(EXIT_FAILURE);}\ | |
14 | + } while (false) | |
15 | + | |
16 | + | |
17 | + | |
18 | +int CheckCUDAProperty( int devId ) | |
19 | +{ | |
20 | + cuInit(0); | |
21 | + | |
22 | + CUdevice dev = devId; | |
23 | + size_t memSize = 0; | |
24 | + char devName[256] = {0}; | |
25 | + int major = 0, minor = 0; | |
26 | + CUresult rlt = CUDA_SUCCESS; | |
27 | + | |
28 | + checkCudaErrors(cuDeviceGetAttribute(&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, dev)); | |
29 | + checkCudaErrors(cuDeviceGetAttribute(&minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, dev)); | |
30 | + | |
31 | + checkCudaErrors( cuDeviceGetName(devName, sizeof( devName ), dev) ); | |
32 | + | |
33 | + printf( "Using GPU Device %d: %s has SM %d.%d compute capability\n", | |
34 | + dev, devName, major, minor ); | |
35 | + | |
36 | + rlt = cuDeviceTotalMem( &memSize, dev ); | |
37 | + checkCudaErrors( rlt ); | |
38 | + | |
39 | + printf( "Total amount of global memory: %4.4f MB\n", | |
40 | + (float)memSize / ( 1024 * 1024 ) ); | |
41 | + | |
42 | + return 0; | |
43 | +} | |
44 | + | |
45 | + | |
46 | +int main(int argc, char *argv[]) { | |
47 | + printf("start \n"); | |
48 | + if (argc != 3) { | |
49 | + fprintf(stderr, "./xxx uri gpu_id\n"); | |
50 | + return -1; | |
51 | + } | |
52 | + | |
53 | + char* uri = argv[1]; | |
54 | + char* gpuid = argv[2]; | |
55 | + | |
56 | + CheckCUDAProperty(atoi(gpuid)); | |
57 | + | |
58 | + evalQuality(uri,gpuid); | |
59 | + | |
60 | + return 0; | |
61 | +} | |
0 | 62 | \ No newline at end of file | ... | ... |
src/FFCuContextManager.cpp
... | ... | @@ -19,7 +19,7 @@ AVBufferRef *FFCuContextManager::getCuCtx(string gpuid) |
19 | 19 | // 初始化硬件解码器 |
20 | 20 | if (av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_CUDA, gpuid.c_str(), nullptr, 0) < 0) |
21 | 21 | { |
22 | - cout << "Failed to create specified HW device."; | |
22 | + av_log(nullptr, AV_LOG_ERROR, "Failed to create specified HW device ! \n"); | |
23 | 23 | return nullptr; |
24 | 24 | } |
25 | 25 | ctxMap[gpuid] = hw_device_ctx; | ... | ... |
src/FFNvDecoder.cpp
1 | 1 | #include "FFNvDecoder.h" |
2 | -#include<iostream> | |
3 | 2 | |
4 | 3 | #include <chrono> |
5 | 4 | #include <thread> |
6 | 5 | #include <fstream> |
7 | 6 | |
8 | -#include <chrono> | |
9 | - | |
10 | 7 | #include "FFCuContextManager.h" |
11 | 8 | |
12 | 9 | using namespace std; |
... | ... | @@ -24,7 +21,7 @@ static AVPixelFormat get_hw_format(AVCodecContext *avctx, const AVPixelFormat *p |
24 | 21 | return *p; |
25 | 22 | } |
26 | 23 | |
27 | - //cout << "Failed to get HW surface format"; | |
24 | + av_log(nullptr, AV_LOG_ERROR, "Failed to get HW surface format. \n"); | |
28 | 25 | return AV_PIX_FMT_NONE; |
29 | 26 | } |
30 | 27 | |
... | ... | @@ -86,13 +83,13 @@ bool FFNvDecoder::init(const char* uri, const char* gpuid, bool force_tcp) |
86 | 83 | fmt_ctx = avformat_alloc_context(); |
87 | 84 | const char* input_file = uri; |
88 | 85 | if (avformat_open_input(&fmt_ctx, input_file, nullptr, &options) != 0) { |
89 | - cout << "Cannot open input file: " << input_file; | |
86 | + av_log(nullptr, AV_LOG_ERROR, "Cannot open input file: %s \n", input_file); | |
90 | 87 | return false; |
91 | 88 | } |
92 | 89 | |
93 | 90 | // 查找流信息 |
94 | 91 | if (avformat_find_stream_info(fmt_ctx, nullptr) < 0) { |
95 | - cout << "Cannot find input stream information"; | |
92 | + av_log(nullptr, AV_LOG_ERROR, "Cannot find input stream information ! \n"); | |
96 | 93 | return false; |
97 | 94 | } |
98 | 95 | |
... | ... | @@ -100,7 +97,7 @@ bool FFNvDecoder::init(const char* uri, const char* gpuid, bool force_tcp) |
100 | 97 | AVCodec *decoder = nullptr; |
101 | 98 | stream_index = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &decoder, 0); |
102 | 99 | if (stream_index < 0) { |
103 | - cout << "Cannot find a video stream in the input file"; | |
100 | + av_log(nullptr, AV_LOG_ERROR, "Cannot find a video stream in the input file ! \n"); | |
104 | 101 | return false; |
105 | 102 | } |
106 | 103 | |
... | ... | @@ -121,7 +118,13 @@ bool FFNvDecoder::init(const char* uri, const char* gpuid, bool force_tcp) |
121 | 118 | hw_pix_fmt = AV_PIX_FMT_CUDA; |
122 | 119 | |
123 | 120 | FFCuContextManager* pCtxMgr = FFCuContextManager::getInstance(); |
124 | - avctx->hw_device_ctx = av_buffer_ref(pCtxMgr->getCuCtx(gpuid)); | |
121 | + | |
122 | + AVBufferRef *hw_device_ctx = pCtxMgr->getCuCtx(gpuid); | |
123 | + if(nullptr == hw_device_ctx){ | |
124 | + av_log(nullptr, AV_LOG_ERROR, "create CUDA context failed ! \n"); | |
125 | + return false; | |
126 | + } | |
127 | + avctx->hw_device_ctx = av_buffer_ref(hw_device_ctx); | |
125 | 128 | if (nullptr == avctx->hw_device_ctx) |
126 | 129 | { |
127 | 130 | return false; |
... | ... | @@ -130,9 +133,9 @@ bool FFNvDecoder::init(const char* uri, const char* gpuid, bool force_tcp) |
130 | 133 | // 打开解码器流 |
131 | 134 | AVDictionary *op = nullptr; |
132 | 135 | av_dict_set( &op, "gpu", gpuid, 0 ); |
133 | - av_dict_set( &op, "surfaces", "3", 0 ); | |
136 | + // av_dict_set( &op, "surfaces", "10", 0 ); | |
134 | 137 | if (avcodec_open2(avctx, vcodec, &op) < 0) { |
135 | - cout << "Failed to open codec for stream" << stream_index; | |
138 | + av_log(nullptr, AV_LOG_ERROR, "Failed to open codec for stream ! \n"); | |
136 | 139 | return false; |
137 | 140 | } |
138 | 141 | |
... | ... | @@ -162,14 +165,12 @@ void FFNvDecoder::start(){ |
162 | 165 | |
163 | 166 | static long long get_cur_time(){ |
164 | 167 | // 获取操作系统当前时间点(精确到微秒) |
165 | - chrono::time_point<chrono::system_clock, chrono::microseconds> tpMicro | |
166 | - = chrono::time_point_cast<chrono::microseconds>(chrono::system_clock::now()); | |
168 | + chrono::time_point<chrono::system_clock, chrono::milliseconds> tpMicro | |
169 | + = chrono::time_point_cast<chrono::milliseconds>(chrono::system_clock::now()); | |
167 | 170 | // (微秒精度的)时间点 => (微秒精度的)时间戳 |
168 | - time_t totalMicroSeconds = tpMicro.time_since_epoch().count(); | |
169 | - | |
170 | - long long currentTime = ((long long)totalMicroSeconds)/1000; | |
171 | + time_t currentTime = tpMicro.time_since_epoch().count(); | |
171 | 172 | |
172 | - return currentTime; | |
173 | + return (long long )currentTime; | |
173 | 174 | } |
174 | 175 | |
175 | 176 | void FFNvDecoder::decode_thread() |
... | ... | @@ -208,14 +209,9 @@ void FFNvDecoder::decode_thread() |
208 | 209 | } |
209 | 210 | |
210 | 211 | int result = av_read_frame(fmt_ctx, pkt); |
211 | - if (result == AVERROR_EOF) | |
212 | + if (result == AVERROR_EOF || result < 0) | |
212 | 213 | { |
213 | - cout << "Failed to read frame!" << endl; | |
214 | - break; | |
215 | - } | |
216 | - if (result < 0) | |
217 | - { | |
218 | - cout << "Failed to read frame!" << endl; | |
214 | + av_log(nullptr, AV_LOG_ERROR, "Failed to read frame! \n"); | |
219 | 215 | break; |
220 | 216 | } |
221 | 217 | |
... | ... | @@ -234,19 +230,16 @@ void FFNvDecoder::decode_thread() |
234 | 230 | } |
235 | 231 | } |
236 | 232 | |
237 | - if (stream_index == pkt->stream_index) | |
238 | - { | |
233 | + if (stream_index == pkt->stream_index){ | |
239 | 234 | result = avcodec_send_packet(avctx, pkt); |
240 | - if (result < 0) | |
241 | - { | |
242 | - cout << "Failed to send pkt:" << result << endl; | |
235 | + if (result < 0){ | |
236 | + av_log(nullptr, AV_LOG_ERROR, "%s - Failed to send pkt: %d \n",name,result); | |
243 | 237 | continue; |
244 | 238 | } |
245 | 239 | |
246 | 240 | result = avcodec_receive_frame(avctx, gpuFrame); |
247 | - if (result == AVERROR(EAGAIN) || result == AVERROR_EOF || result < 0) | |
248 | - { | |
249 | - cout << "Failed to receive frame"<< endl; | |
241 | + if ((result == AVERROR(EAGAIN) || result == AVERROR_EOF) || result < 0){ | |
242 | + av_log(nullptr, AV_LOG_ERROR, "%s - Failed to receive frame: %d \n",name,result); | |
250 | 243 | continue; |
251 | 244 | } |
252 | 245 | |
... | ... | @@ -255,6 +248,14 @@ void FFNvDecoder::decode_thread() |
255 | 248 | av_packet_unref(pkt); |
256 | 249 | } |
257 | 250 | |
251 | + // 队列中没有数据了再结束 | |
252 | + while (mFrameQueue.length() > 0){ | |
253 | + if(!m_bRunning){ | |
254 | + break; | |
255 | + } | |
256 | + std::this_thread::sleep_for(std::chrono::milliseconds(10)); | |
257 | + } | |
258 | + | |
258 | 259 | m_bRunning = false; |
259 | 260 | |
260 | 261 | // long end_time = get_cur_time(); |
... | ... | @@ -266,9 +267,11 @@ void FFNvDecoder::decode_thread() |
266 | 267 | pthread_join(m_post_decode_thread,0); |
267 | 268 | } |
268 | 269 | |
270 | + decode_finished_cbk(m_userPtr); | |
271 | + | |
269 | 272 | decode_finished(); |
270 | 273 | |
271 | - cout << "decode thread exited." << endl; | |
274 | + av_log(nullptr, AV_LOG_INFO, "%s - decode thread exited. \n",name); | |
272 | 275 | } |
273 | 276 | |
274 | 277 | void FFNvDecoder::decode_finished() |
... | ... | @@ -289,7 +292,7 @@ void FFNvDecoder::decode_finished() |
289 | 292 | |
290 | 293 | void FFNvDecoder::post_decode_thread() |
291 | 294 | { |
292 | - while (m_bRunning) | |
295 | + while (m_bRunning || mFrameQueue.length() > 0) | |
293 | 296 | { |
294 | 297 | AVFrame * gpuFrame = mFrameQueue.getHead(); |
295 | 298 | if (gpuFrame == nullptr) |
... | ... | @@ -302,8 +305,8 @@ void FFNvDecoder::post_decode_thread() |
302 | 305 | |
303 | 306 | mFrameQueue.addHead(); |
304 | 307 | } |
305 | - | |
306 | - cout << "post decode thread exited." << endl; | |
308 | + | |
309 | + av_log(nullptr, AV_LOG_INFO, "post decode thread exited. \n"); | |
307 | 310 | } |
308 | 311 | |
309 | 312 | void FFNvDecoder::close() |
... | ... | @@ -338,12 +341,16 @@ bool FFNvDecoder::isFinished() |
338 | 341 | return m_bFinished; |
339 | 342 | } |
340 | 343 | |
344 | +bool FFNvDecoder::isPausing(){ | |
345 | + return m_bPause; | |
346 | +} | |
347 | + | |
341 | 348 | bool FFNvDecoder::getResolution( int &width, int &height ) |
342 | 349 | { |
343 | - if (avctx != nullptr) | |
350 | + if (stream != nullptr && stream->codecpar != nullptr) | |
344 | 351 | { |
345 | - width = avctx->width; | |
346 | - height = avctx->height; | |
352 | + width = stream->codecpar->width; | |
353 | + height = stream->codecpar->height; | |
347 | 354 | return true; |
348 | 355 | } |
349 | 356 | |
... | ... | @@ -363,4 +370,145 @@ void FFNvDecoder::resume() |
363 | 370 | void FFNvDecoder::setDecKeyframe(bool bKeyframe) |
364 | 371 | { |
365 | 372 | m_dec_keyframe = bKeyframe; |
366 | -} | |
367 | 373 | \ No newline at end of file |
374 | +} | |
375 | + | |
376 | +int FFNvDecoder::getCachedQueueLength(){ | |
377 | + return mFrameQueue.length(); | |
378 | +} | |
379 | + | |
380 | +FFImgInfo* FFNvDecoder::snapshot(const string& uri){ | |
381 | + | |
382 | + AVFormatContext* ifmt_ctx = nullptr; | |
383 | + AVCodecContext* codec_ctx = nullptr; | |
384 | + AVCodec* codec = nullptr; | |
385 | + AVPacket* pkt = nullptr; | |
386 | + AVFrame *frame = nullptr; | |
387 | + AVFrame *pFrameRGB = nullptr; | |
388 | + int video_index = -1; | |
389 | + AVStream* st = nullptr; | |
390 | + SwsContext *img_convert_ctx = nullptr; | |
391 | + uint8_t *buffer = nullptr; | |
392 | + int numBytes = 0; | |
393 | + | |
394 | + FFImgInfo* imgInfo = nullptr; | |
395 | + | |
396 | + | |
397 | + avformat_network_init(); | |
398 | + | |
399 | + // 打开输入视频文件 | |
400 | + AVDictionary *options = nullptr; | |
401 | + av_dict_set( &options, "bufsize", "655360", 0 ); | |
402 | + av_dict_set( &options, "rtsp_transport", "tcp", 0 ); | |
403 | + // av_dict_set( &options, "listen_timeout", "30", 0 ); // 单位为s | |
404 | + av_dict_set( &options, "stimeout", "30000000", 0 ); // 单位为 百万分之一秒 | |
405 | + | |
406 | + ///打开输入的流 | |
407 | + ifmt_ctx = avformat_alloc_context(); | |
408 | + int ret = avformat_open_input(&ifmt_ctx, uri.c_str(), nullptr, &options); | |
409 | + if (ret != 0){ | |
410 | + av_log(nullptr, AV_LOG_ERROR, "Couldn't open input stream ! \n"); | |
411 | + goto end_flag ; | |
412 | + } | |
413 | + | |
414 | + //查找流信息 | |
415 | + if (avformat_find_stream_info(ifmt_ctx, nullptr) < 0){ | |
416 | + av_log(nullptr, AV_LOG_ERROR, "Couldn't find stream information ! \n"); | |
417 | + goto end_flag ; | |
418 | + } | |
419 | + | |
420 | + //找到视频流索引 | |
421 | + video_index = av_find_best_stream(ifmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, nullptr, 0); | |
422 | + | |
423 | + st = ifmt_ctx->streams[video_index]; | |
424 | + | |
425 | + //找到解码器 | |
426 | + codec = avcodec_find_decoder(st->codecpar->codec_id); | |
427 | + if (!codec){ | |
428 | + av_log(nullptr, AV_LOG_ERROR, "Codec not found ! \n"); | |
429 | + goto end_flag ; | |
430 | + } | |
431 | + | |
432 | + //申请AVCodecContext | |
433 | + codec_ctx = avcodec_alloc_context3(codec); | |
434 | + if (!codec_ctx){ | |
435 | + goto end_flag ; | |
436 | + } | |
437 | + | |
438 | + avcodec_parameters_to_context(codec_ctx, ifmt_ctx->streams[video_index]->codecpar); | |
439 | + | |
440 | + //打开解码器 | |
441 | + if ((ret = avcodec_open2(codec_ctx, codec, nullptr) < 0)){ | |
442 | + goto end_flag ; | |
443 | + } | |
444 | + | |
445 | + // 计算解码后原始数据所需缓冲区大小,并分配内存空间 Determine required buffer size and allocate buffer | |
446 | + numBytes = av_image_get_buffer_size(AV_PIX_FMT_RGB24, codec_ctx->width, codec_ctx->height, 1); | |
447 | + buffer = (uint8_t *)av_malloc(numBytes * sizeof(uint8_t)); | |
448 | + | |
449 | + pFrameRGB = av_frame_alloc(); | |
450 | + av_image_fill_arrays(pFrameRGB->data, pFrameRGB->linesize, buffer, AV_PIX_FMT_BGR24, codec_ctx->width, codec_ctx->height, 1); | |
451 | + | |
452 | + 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, | |
453 | + SWS_BICUBIC, nullptr, nullptr, nullptr); | |
454 | + | |
455 | + pkt = av_packet_alloc(); | |
456 | + frame = av_frame_alloc(); | |
457 | + while (av_read_frame(ifmt_ctx, pkt) >= 0){ | |
458 | + if (pkt->stream_index == video_index){ | |
459 | + int ret = avcodec_send_packet(codec_ctx, pkt); | |
460 | + if (ret >= 0){ | |
461 | + ret = avcodec_receive_frame(codec_ctx, frame); | |
462 | + if ((ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) || ret < 0){ | |
463 | + av_log(nullptr, AV_LOG_ERROR, "Failed to receive frame: %d \n", ret); | |
464 | + av_packet_unref(pkt); | |
465 | + continue; | |
466 | + } | |
467 | + | |
468 | + sws_scale(img_convert_ctx, (const unsigned char* const*)frame->data, frame->linesize, 0, codec_ctx->height, pFrameRGB->data, pFrameRGB->linesize); | |
469 | + | |
470 | + imgInfo = new FFImgInfo(); | |
471 | + imgInfo->pData = buffer; | |
472 | + imgInfo->height = codec_ctx->height; | |
473 | + imgInfo->width = codec_ctx->width; | |
474 | + break; | |
475 | + } | |
476 | + } | |
477 | + | |
478 | + av_packet_unref(pkt); | |
479 | + } | |
480 | + | |
481 | +end_flag: | |
482 | + if (codec_ctx != nullptr){ | |
483 | + avcodec_close(codec_ctx); | |
484 | + avcodec_free_context(&codec_ctx); | |
485 | + } | |
486 | + | |
487 | + if (ifmt_ctx != nullptr){ | |
488 | + avformat_close_input(&ifmt_ctx); | |
489 | + } | |
490 | + | |
491 | + if (frame != nullptr){ | |
492 | + av_frame_free(&frame); | |
493 | + } | |
494 | + | |
495 | + if (pFrameRGB != nullptr){ | |
496 | + av_frame_free(&pFrameRGB); | |
497 | + } | |
498 | + | |
499 | + if (pkt != nullptr){ | |
500 | + av_packet_free(&pkt); | |
501 | + } | |
502 | + | |
503 | + return imgInfo; | |
504 | +} | |
505 | + | |
506 | +void FFNvDecoder::releaseFFImgInfo(FFImgInfo* info){ | |
507 | + if(nullptr != info){ | |
508 | + if(info->pData != nullptr){ | |
509 | + av_free(info->pData); | |
510 | + info->pData = nullptr; | |
511 | + } | |
512 | + delete info; | |
513 | + info = nullptr; | |
514 | + } | |
515 | +} | ... | ... |
src/FFNvDecoder.h
... | ... | @@ -12,6 +12,7 @@ extern "C" |
12 | 12 | #include <libavutil/avutil.h> |
13 | 13 | #include <libavutil/pixdesc.h> |
14 | 14 | #include <libswscale/swscale.h> |
15 | + #include <libavutil/imgutils.h> | |
15 | 16 | } |
16 | 17 | |
17 | 18 | using namespace std; |
... | ... | @@ -29,14 +30,22 @@ using namespace std; |
29 | 30 | **************************************************/ |
30 | 31 | typedef void(*POST_DECODE_CALLBACK)(const void * userPtr, AVFrame * gpuFrame); |
31 | 32 | |
32 | -struct FFDecConfig | |
33 | -{ | |
33 | +typedef void(*DECODE_FINISHED_CALLBACK)(const void* userPtr); | |
34 | + | |
35 | +struct FFDecConfig{ | |
34 | 36 | string uri; // 视频地址 |
35 | 37 | POST_DECODE_CALLBACK post_decoded_cbk; // 解码数据回调接口 |
38 | + DECODE_FINISHED_CALLBACK decode_finished_cbk; // 解码线程结束后的回调接口 | |
36 | 39 | string gpuid; // gpu id |
37 | 40 | bool force_tcp{true}; // 是否指定使用tcp连接 |
38 | 41 | }; |
39 | 42 | |
43 | +struct FFImgInfo{ | |
44 | + int width; | |
45 | + int height; | |
46 | + unsigned char * pData; | |
47 | +}; | |
48 | + | |
40 | 49 | class FFNvDecoder{ |
41 | 50 | public: |
42 | 51 | FFNvDecoder(); |
... | ... | @@ -51,6 +60,7 @@ public: |
51 | 60 | |
52 | 61 | bool isRunning(); |
53 | 62 | bool isFinished(); |
63 | + bool isPausing(); | |
54 | 64 | bool getResolution( int &width, int &height ); |
55 | 65 | |
56 | 66 | void setName(string nm); |
... | ... | @@ -58,6 +68,12 @@ public: |
58 | 68 | |
59 | 69 | bool isSurport(FFDecConfig& cfg); |
60 | 70 | |
71 | + int getCachedQueueLength(); | |
72 | + | |
73 | + static FFImgInfo* snapshot(const string& uri); | |
74 | + | |
75 | + static void releaseFFImgInfo(FFImgInfo*); | |
76 | + | |
61 | 77 | public: |
62 | 78 | AVPixelFormat getHwPixFmt(); |
63 | 79 | |
... | ... | @@ -69,6 +85,7 @@ private: |
69 | 85 | |
70 | 86 | public: |
71 | 87 | POST_DECODE_CALLBACK post_decoded_cbk; |
88 | + DECODE_FINISHED_CALLBACK decode_finished_cbk; | |
72 | 89 | const void * m_userPtr; |
73 | 90 | FFDecConfig m_cfg; |
74 | 91 | ... | ... |
src/FFNvDecoderManager.cpp
1 | 1 | #include "FFNvDecoderManager.h" |
2 | -#include<iostream> | |
3 | 2 | |
4 | 3 | using namespace std; |
5 | 4 | |
6 | 5 | |
7 | -FFNvDecoder* FFNvDecoderManager::createDecoder(MgrDecConfig& config){ | |
6 | +FFNvDecoder* FFNvDecoderManager::createDecoder(MgrDecConfig config){ | |
8 | 7 | |
9 | 8 | closeAllFinishedDecoder(); |
10 | 9 | |
11 | - int num = decoderMap.count(config.name); | |
12 | - if (num > 0) | |
13 | - { | |
14 | - cout << "已存在name所标记的解码器" << endl; | |
10 | + std::lock_guard<std::mutex> l(m_mutex); | |
11 | + | |
12 | + auto it = decoderMap.find(config.name); | |
13 | + if (it != decoderMap.end()){ | |
14 | + av_log(NULL, AV_LOG_ERROR, "已存在name所标记的解码器 \n"); | |
15 | 15 | return nullptr; |
16 | 16 | } |
17 | 17 | |
... | ... | @@ -26,6 +26,7 @@ FFNvDecoder* FFNvDecoderManager::createDecoder(MgrDecConfig& config){ |
26 | 26 | { |
27 | 27 | dec->setName(config.name) ; |
28 | 28 | dec->post_decoded_cbk = config.cfg.post_decoded_cbk; |
29 | + dec->decode_finished_cbk = config.cfg.decode_finished_cbk; | |
29 | 30 | decoderMap[config.name] = dec; |
30 | 31 | return dec; |
31 | 32 | } |
... | ... | @@ -41,10 +42,12 @@ bool FFNvDecoderManager::setUserPtr(const string name, const void * userPtr) |
41 | 42 | { |
42 | 43 | if (name.empty()) |
43 | 44 | { |
44 | - cout << "name 为空!"<< endl; | |
45 | + av_log(NULL, AV_LOG_ERROR, "name 为空! \n"); | |
45 | 46 | return false; |
46 | 47 | } |
47 | 48 | |
49 | + std::lock_guard<std::mutex> l(m_mutex); | |
50 | + | |
48 | 51 | auto dec = decoderMap.find(name); |
49 | 52 | if (dec != decoderMap.end()) |
50 | 53 | { |
... | ... | @@ -52,7 +55,7 @@ bool FFNvDecoderManager::setUserPtr(const string name, const void * userPtr) |
52 | 55 | return true; |
53 | 56 | } |
54 | 57 | |
55 | - cout << "没有找到name为" << name << "的解码器!" << endl; | |
58 | + av_log(NULL, AV_LOG_ERROR, "没有找到name为 %s 的解码器! \n", name.c_str()); | |
56 | 59 | return false; |
57 | 60 | } |
58 | 61 | |
... | ... | @@ -60,17 +63,19 @@ FFNvDecoder* FFNvDecoderManager::getDecoderByName(const string name) |
60 | 63 | { |
61 | 64 | if (name.empty()) |
62 | 65 | { |
63 | - cout << "name 为空!"<< endl; | |
66 | + av_log(NULL, AV_LOG_ERROR, "name 为空! \n"); | |
64 | 67 | return nullptr; |
65 | 68 | } |
66 | 69 | |
70 | + std::lock_guard<std::mutex> l(m_mutex); | |
71 | + | |
67 | 72 | auto dec = decoderMap.find(name); |
68 | 73 | if (dec != decoderMap.end()) |
69 | 74 | { |
70 | 75 | return dec->second; |
71 | 76 | } |
72 | 77 | |
73 | - cout << "没有找到name为" << name << "的解码器!" << endl; | |
78 | + av_log(NULL, AV_LOG_ERROR, "没有找到name为 %s 的解码器! \n", name.c_str()); | |
74 | 79 | return nullptr; |
75 | 80 | } |
76 | 81 | |
... | ... | @@ -84,10 +89,12 @@ void FFNvDecoderManager::startDecode(FFNvDecoder* dec){ |
84 | 89 | bool FFNvDecoderManager::startDecodeByName(const string name){ |
85 | 90 | if (name.empty()) |
86 | 91 | { |
87 | - cout << "name 为空!"<< endl; | |
92 | + av_log(NULL, AV_LOG_ERROR, "name 为空! \n"); | |
88 | 93 | return false; |
89 | 94 | } |
90 | 95 | |
96 | + std::lock_guard<std::mutex> l(m_mutex); | |
97 | + | |
91 | 98 | auto dec = decoderMap.find(name); |
92 | 99 | if (dec != decoderMap.end()) |
93 | 100 | { |
... | ... | @@ -95,11 +102,14 @@ bool FFNvDecoderManager::startDecodeByName(const string name){ |
95 | 102 | return true; |
96 | 103 | } |
97 | 104 | |
98 | - cout << "没有找到name为" << name << "的解码器!" << endl; | |
105 | + av_log(NULL, AV_LOG_ERROR, "没有找到name为 %s 的解码器! \n", name.c_str()); | |
99 | 106 | return false; |
100 | 107 | } |
101 | 108 | |
102 | 109 | void FFNvDecoderManager::startAllDecode(){ |
110 | + | |
111 | + std::lock_guard<std::mutex> l(m_mutex); | |
112 | + | |
103 | 113 | for(auto iter = decoderMap.begin(); iter != decoderMap.end(); iter++){ |
104 | 114 | if (!iter->second->isRunning()) |
105 | 115 | { |
... | ... | @@ -111,11 +121,12 @@ void FFNvDecoderManager::startAllDecode(){ |
111 | 121 | bool FFNvDecoderManager::closeDecoderByName(const string name){ |
112 | 122 | if (name.empty()) |
113 | 123 | { |
114 | - cout << "name 为空!"<< endl; | |
124 | + av_log(NULL, AV_LOG_ERROR, "name 为空! \n"); | |
115 | 125 | return false; |
116 | 126 | } |
117 | 127 | |
118 | - m_mutex_erase.lock(); | |
128 | + std::lock_guard<std::mutex> l(m_mutex); | |
129 | + | |
119 | 130 | auto dec = decoderMap.find(name); |
120 | 131 | if (dec != decoderMap.end()) |
121 | 132 | { |
... | ... | @@ -124,30 +135,29 @@ bool FFNvDecoderManager::closeDecoderByName(const string name){ |
124 | 135 | dec->second = nullptr; |
125 | 136 | decoderMap.erase(dec); |
126 | 137 | |
127 | - m_mutex_erase.unlock(); | |
128 | 138 | return true; |
129 | 139 | } |
130 | 140 | |
131 | - m_mutex_erase.unlock(); | |
132 | - cout << "没有找到name为" << name << "的解码器!" << endl; | |
141 | + av_log(NULL, AV_LOG_ERROR, "没有找到name为 %s 的解码器! \n", name.c_str()); | |
133 | 142 | return false; |
134 | 143 | } |
135 | 144 | |
136 | 145 | void FFNvDecoderManager::closeAllDecoder() |
137 | 146 | { |
138 | - m_mutex_erase.lock(); | |
147 | + std::lock_guard<std::mutex> l(m_mutex); | |
148 | + | |
139 | 149 | for(auto iter = decoderMap.begin(); iter != decoderMap.end(); iter++){ |
140 | 150 | iter->second->close(); |
141 | 151 | delete iter->second; |
142 | 152 | iter->second = nullptr; |
143 | 153 | } |
144 | 154 | decoderMap.clear(); |
145 | - m_mutex_erase.unlock(); | |
146 | 155 | } |
147 | 156 | |
148 | 157 | void FFNvDecoderManager::closeAllFinishedDecoder() |
149 | 158 | { |
150 | - m_mutex_erase.lock(); | |
159 | + std::lock_guard<std::mutex> l(m_mutex); | |
160 | + | |
151 | 161 | for(auto iter = decoderMap.begin(); iter != decoderMap.end(); ){ |
152 | 162 | if (iter->second->isFinished()) |
153 | 163 | { |
... | ... | @@ -160,13 +170,13 @@ void FFNvDecoderManager::closeAllFinishedDecoder() |
160 | 170 | iter++ ; |
161 | 171 | } |
162 | 172 | } |
163 | - m_mutex_erase.unlock(); | |
164 | 173 | } |
165 | 174 | |
166 | 175 | int FFNvDecoderManager::count() |
167 | 176 | { |
168 | 177 | closeAllFinishedDecoder(); |
169 | 178 | |
179 | + std::lock_guard<std::mutex> l(m_mutex); | |
170 | 180 | return decoderMap.size(); |
171 | 181 | } |
172 | 182 | |
... | ... | @@ -174,10 +184,12 @@ bool FFNvDecoderManager::pauseDecoder(const string name) |
174 | 184 | { |
175 | 185 | if (name.empty()) |
176 | 186 | { |
177 | - cout << "name 为空!"<< endl; | |
187 | + av_log(NULL, AV_LOG_ERROR, "name 为空! \n"); | |
178 | 188 | return false; |
179 | 189 | } |
180 | 190 | |
191 | + std::lock_guard<std::mutex> l(m_mutex); | |
192 | + | |
181 | 193 | auto dec = decoderMap.find(name); |
182 | 194 | if (dec != decoderMap.end()) |
183 | 195 | { |
... | ... | @@ -185,7 +197,7 @@ bool FFNvDecoderManager::pauseDecoder(const string name) |
185 | 197 | return true; |
186 | 198 | } |
187 | 199 | |
188 | - cout << "没有找到name为" << name << "的解码器!" << endl; | |
200 | + av_log(NULL, AV_LOG_ERROR, "没有找到name为 %s 的解码器! \n", name.c_str()); | |
189 | 201 | return false; |
190 | 202 | } |
191 | 203 | |
... | ... | @@ -193,10 +205,12 @@ bool FFNvDecoderManager::resumeDecoder(const string name) |
193 | 205 | { |
194 | 206 | if (name.empty()) |
195 | 207 | { |
196 | - cout << "name 为空!"<< endl; | |
208 | + av_log(NULL, AV_LOG_ERROR, "name 为空! \n"); | |
197 | 209 | return false; |
198 | 210 | } |
199 | 211 | |
212 | + std::lock_guard<std::mutex> l(m_mutex); | |
213 | + | |
200 | 214 | auto dec = decoderMap.find(name); |
201 | 215 | if (dec != decoderMap.end()) |
202 | 216 | { |
... | ... | @@ -204,7 +218,7 @@ bool FFNvDecoderManager::resumeDecoder(const string name) |
204 | 218 | return true; |
205 | 219 | } |
206 | 220 | |
207 | - cout << "没有找到name为" << name << "的解码器!" << endl; | |
221 | + av_log(NULL, AV_LOG_ERROR, "没有找到name为 %s 的解码器! \n", name.c_str()); | |
208 | 222 | return false; |
209 | 223 | } |
210 | 224 | |
... | ... | @@ -217,17 +231,57 @@ bool FFNvDecoderManager::isSurport(FFDecConfig& cfg) |
217 | 231 | bool FFNvDecoderManager::isRunning(const string name){ |
218 | 232 | if (name.empty()) |
219 | 233 | { |
220 | - cout << "name 为空!"<< endl; | |
234 | + av_log(NULL, AV_LOG_ERROR, "name 为空! \n"); | |
221 | 235 | return false; |
222 | 236 | } |
223 | 237 | |
238 | + std::lock_guard<std::mutex> l(m_mutex); | |
239 | + | |
224 | 240 | auto dec = decoderMap.find(name); |
225 | 241 | if (dec != decoderMap.end()) |
226 | 242 | { |
227 | 243 | return dec->second->isRunning(); |
228 | 244 | } |
229 | 245 | |
230 | - cout << "没有找到name为" << name << "的解码器!" << endl; | |
246 | + av_log(NULL, AV_LOG_ERROR, "没有找到name为 %s 的解码器! \n", name.c_str()); | |
247 | + return false; | |
248 | +} | |
249 | + | |
250 | +bool FFNvDecoderManager::isFinished(const string name){ | |
251 | + if (name.empty()) | |
252 | + { | |
253 | + av_log(NULL, AV_LOG_ERROR, "name 为空! \n"); | |
254 | + return false; | |
255 | + } | |
256 | + | |
257 | + std::lock_guard<std::mutex> l(m_mutex); | |
258 | + | |
259 | + auto dec = decoderMap.find(name); | |
260 | + if (dec != decoderMap.end()) | |
261 | + { | |
262 | + return dec->second->isFinished(); | |
263 | + } | |
264 | + | |
265 | + av_log(NULL, AV_LOG_ERROR, "没有找到name为 %s 的解码器! \n", name.c_str()); | |
266 | + return false; | |
267 | +} | |
268 | + | |
269 | +bool FFNvDecoderManager::isPausing(const string name){ | |
270 | + if (name.empty()) | |
271 | + { | |
272 | + av_log(NULL, AV_LOG_ERROR, "name 为空! \n"); | |
273 | + return false; | |
274 | + } | |
275 | + | |
276 | + std::lock_guard<std::mutex> l(m_mutex); | |
277 | + | |
278 | + auto dec = decoderMap.find(name); | |
279 | + if (dec != decoderMap.end()) | |
280 | + { | |
281 | + return dec->second->isPausing(); | |
282 | + } | |
283 | + | |
284 | + av_log(NULL, AV_LOG_ERROR, "没有找到name为 %s 的解码器! \n", name.c_str()); | |
231 | 285 | return false; |
232 | 286 | } |
233 | 287 | |
... | ... | @@ -235,10 +289,12 @@ bool FFNvDecoderManager::setDecKeyframe(const string name, bool bKeyframe) |
235 | 289 | { |
236 | 290 | if (name.empty()) |
237 | 291 | { |
238 | - cout << "name 为空!"<< endl; | |
292 | + av_log(NULL, AV_LOG_ERROR, "name 为空! \n"); | |
239 | 293 | return false; |
240 | 294 | } |
241 | 295 | |
296 | + std::lock_guard<std::mutex> l(m_mutex); | |
297 | + | |
242 | 298 | auto dec = decoderMap.find(name); |
243 | 299 | if (dec != decoderMap.end()) |
244 | 300 | { |
... | ... | @@ -246,6 +302,65 @@ bool FFNvDecoderManager::setDecKeyframe(const string name, bool bKeyframe) |
246 | 302 | return true; |
247 | 303 | } |
248 | 304 | |
249 | - cout << "没有找到name为" << name << "的解码器!" << endl; | |
305 | + av_log(NULL, AV_LOG_ERROR, "没有找到name为 %s 的解码器! \n", name.c_str()); | |
306 | + return false; | |
307 | +} | |
308 | + | |
309 | +bool FFNvDecoderManager::getResolution(const string name, int &width, int &height) | |
310 | +{ | |
311 | + if (name.empty()) | |
312 | + { | |
313 | + av_log(NULL, AV_LOG_ERROR, "name 为空! \n"); | |
314 | + return false; | |
315 | + } | |
316 | + | |
317 | + std::lock_guard<std::mutex> l(m_mutex); | |
318 | + | |
319 | + auto dec = decoderMap.find(name); | |
320 | + if (dec != decoderMap.end()) | |
321 | + { | |
322 | + dec->second->getResolution(width, height); | |
323 | + return true; | |
324 | + } | |
325 | + | |
326 | + av_log(NULL, AV_LOG_ERROR, "没有找到name为 %s 的解码器! \n", name.c_str()); | |
250 | 327 | return false; |
328 | +} | |
329 | + | |
330 | +vector<string> FFNvDecoderManager::getAllDecodeName(){ | |
331 | + | |
332 | + closeAllFinishedDecoder(); | |
333 | + | |
334 | + std::lock_guard<std::mutex> l(m_mutex); | |
335 | + | |
336 | + vector<string> decode_names; | |
337 | + for(auto it = decoderMap.begin(); it != decoderMap.end(); ++it){ | |
338 | + decode_names.push_back(it->first); | |
339 | + } | |
340 | + return decode_names; | |
341 | +} | |
342 | + | |
343 | +int FFNvDecoderManager::getCachedQueueLength(const string name){ | |
344 | + if (name.empty()){ | |
345 | + av_log(NULL, AV_LOG_ERROR, "name 为空! \n"); | |
346 | + return -1; | |
347 | + } | |
348 | + | |
349 | + std::lock_guard<std::mutex> l(m_mutex); | |
350 | + | |
351 | + auto dec = decoderMap.find(name); | |
352 | + if (dec != decoderMap.end()){ | |
353 | + return dec->second->getCachedQueueLength(); | |
354 | + } | |
355 | + | |
356 | + av_log(NULL, AV_LOG_ERROR, "没有找到name为 %s 的解码器! \n", name.c_str()); | |
357 | + return -1; | |
358 | +} | |
359 | + | |
360 | +FFImgInfo* FFNvDecoderManager::snapshot(const string& uri){ | |
361 | + return FFNvDecoder::snapshot(uri); | |
362 | +} | |
363 | + | |
364 | +void FFNvDecoderManager::releaseFFImgInfo(FFImgInfo* info){ | |
365 | + FFNvDecoder::releaseFFImgInfo(info); | |
251 | 366 | } |
252 | 367 | \ No newline at end of file | ... | ... |
src/FFNvDecoderManager.h
... | ... | @@ -45,7 +45,7 @@ public: |
45 | 45 | * 返回:成功返回解码器, 失败返回 nullptr |
46 | 46 | * 备注: |
47 | 47 | **************************************************/ |
48 | - FFNvDecoder* createDecoder(MgrDecConfig& config); | |
48 | + FFNvDecoder* createDecoder(MgrDecConfig config); | |
49 | 49 | |
50 | 50 | /************************************************** |
51 | 51 | * 接口:setUserPtr |
... | ... | @@ -111,6 +111,15 @@ public: |
111 | 111 | **************************************************/ |
112 | 112 | void closeAllDecoder(); |
113 | 113 | |
114 | + /************************************************** | |
115 | + * 接口:closeAllDecoderByGpuid | |
116 | + * 功能:关闭某张显卡撒花姑娘的全部解码器 | |
117 | + * 参数:const string gpuid gpu的id | |
118 | + * 返回:void | |
119 | + * 备注: | |
120 | + **************************************************/ | |
121 | + void closeAllDecoderByGpuid(const string gpuid); | |
122 | + | |
114 | 123 | /************************************************** |
115 | 124 | * 接口:pauseDecoder |
116 | 125 | * 功能:暂停指定名称的解码器 |
... | ... | @@ -147,6 +156,24 @@ public: |
147 | 156 | **************************************************/ |
148 | 157 | bool isRunning(const string name); |
149 | 158 | |
159 | + /************************************************** | |
160 | + * 接口:isFinished | |
161 | + * 功能:根据解码器名称判断解码器是否已经结束 | |
162 | + * 参数:const string name 解码器名称 | |
163 | + * 返回:正在运行返回true,否则返回false | |
164 | + * 备注: | |
165 | + **************************************************/ | |
166 | + bool isFinished(const string name); | |
167 | + | |
168 | + /************************************************** | |
169 | + * 接口:isPausing | |
170 | + * 功能:根据解码器名称判断解码器是否暂停 | |
171 | + * 参数:const string name 解码器名称 | |
172 | + * 返回:正在运行返回true,否则返回false | |
173 | + * 备注: | |
174 | + **************************************************/ | |
175 | + bool isPausing(const string name); | |
176 | + | |
150 | 177 | /************************************************** |
151 | 178 | * 接口:count |
152 | 179 | * 功能:获取正在运行的解码器数量 |
... | ... | @@ -161,11 +188,58 @@ public: |
161 | 188 | * 功能:设置是否只解码关键帧。默认全解 |
162 | 189 | * 参数:const string name 解码器名称 |
163 | 190 | * bool bKeyframe 是否只解码关键帧。true,只解码关键帧;false,普通的全解码 |
164 | - * 返回:void | |
191 | + * 返回:bool 成功返回true,失败返回false | |
165 | 192 | * 备注: |
166 | 193 | **************************************************/ |
167 | 194 | bool setDecKeyframe(const string name, bool bKeyframe); |
168 | 195 | |
196 | + /************************************************** | |
197 | + * 接口:getResolution | |
198 | + * 功能:获取视频分辨率 | |
199 | + * 参数:const string name 解码器名称 | |
200 | + * int &width 从 width 返回视频宽度 | |
201 | + * int &height 从 height 返回视频高度 | |
202 | + * 返回:bool 成功获取返回true,失败返回false | |
203 | + * 备注: | |
204 | + **************************************************/ | |
205 | + bool getResolution(const string name, int &width, int &height); | |
206 | + | |
207 | + /************************************************** | |
208 | + * 接口:getAllDecodeName | |
209 | + * 功能:获取全部解码器名称 | |
210 | + * 参数:void | |
211 | + * 返回:vector<string> 返回全部解码器名称 | |
212 | + * 备注: | |
213 | + **************************************************/ | |
214 | + vector<string> getAllDecodeName(); | |
215 | + | |
216 | + /************************************************** | |
217 | + * 接口:getCachedQueueLength | |
218 | + * 功能:获取解码缓冲队列当前长度 | |
219 | + * 参数:const string name 解码器名称 | |
220 | + * 返回:int 解码缓冲队列当前长度 | |
221 | + * 备注: | |
222 | + **************************************************/ | |
223 | + int getCachedQueueLength(const string name); | |
224 | + | |
225 | + /************************************************** | |
226 | + * 接口:snapshot | |
227 | + * 功能:获取视频快照 | |
228 | + * 参数:const string& uri 视频地址 | |
229 | + * 返回:FFImgInfo* 快照信息 | |
230 | + * 备注: | |
231 | + **************************************************/ | |
232 | + FFImgInfo* snapshot(const string& uri); | |
233 | + | |
234 | + /************************************************** | |
235 | + * 接口:releaseFFImgInfo | |
236 | + * 功能:释放视频快照信息 | |
237 | + * 参数:FFImgInfo* info 视频快照信息 | |
238 | + * 返回:void | |
239 | + * 备注: | |
240 | + **************************************************/ | |
241 | + void releaseFFImgInfo(FFImgInfo* info); | |
242 | + | |
169 | 243 | private: |
170 | 244 | FFNvDecoderManager(){} |
171 | 245 | |
... | ... | @@ -174,5 +248,5 @@ private: |
174 | 248 | private: |
175 | 249 | map<string, FFNvDecoder*> decoderMap; |
176 | 250 | |
177 | - mutex m_mutex_erase; | |
251 | + mutex m_mutex; | |
178 | 252 | }; |
179 | 253 | \ No newline at end of file | ... | ... |
src/Makefile
... | ... | @@ -2,14 +2,11 @@ |
2 | 2 | XX = g++ |
3 | 3 | NVCC = nvcc |
4 | 4 | |
5 | - | |
6 | -DEFS= -DPOST_USE_RABBITMQ | |
7 | - | |
8 | -PROJECT_ROOT= /home/cmhu/FFNvDecoder | |
5 | +PROJECT_ROOT= /mnt/e/fiss/FFNvDecoder | |
9 | 6 | |
10 | 7 | DEPEND_DIR = $(PROJECT_ROOT)/bin |
11 | 8 | SRC_ROOT = $(PROJECT_ROOT)/src |
12 | -CUDA_ROOT = /usr/local/cuda-11.7 | |
9 | +CUDA_ROOT = /usr/local/cuda | |
13 | 10 | |
14 | 11 | TARGET= $(DEPEND_DIR)/lib/test |
15 | 12 | |
... | ... | @@ -21,12 +18,13 @@ INCLUDE= -I $(DEPEND_DIR)/include \ |
21 | 18 | -I $(SRC_ROOT)\ |
22 | 19 | |
23 | 20 | LIBSPATH= -L $(DEPEND_DIR)/lib -lavformat -lavcodec -lswscale -lavutil -lavfilter -lswresample -lavdevice \ |
24 | - -L $(CUDA_ROOT)/lib64 -lcuda -lcudart -lnvcuvid -lcurand -lcublas -lnvjpeg \ | |
21 | + -L $(CUDA_ROOT)/lib64 -lcudart -lcurand -lcublas -lnvjpeg \ | |
22 | + -L /usr/lib/wsl/lib -lcuda -lnvcuvid\ | |
25 | 23 | |
26 | -CFLAGS= -g -fPIC -O0 $(DEFS) $(INCLUDE) -pthread -lrt -lz -std=c++11 -fvisibility=hidden -Wl,-Bsymbolic -ldl | |
24 | +CFLAGS= -g -fPIC -O0 $(INCLUDE) -pthread -lrt -lz -std=c++11 -fvisibility=hidden -Wl,-Bsymbolic -ldl | |
27 | 25 | # -DUNICODE -D_UNICODE |
28 | 26 | |
29 | -NFLAGS_LIB=-g -c $(DEFS) -shared -Xcompiler -fPIC -Xcompiler -fvisibility=hidden | |
27 | +NFLAGS_LIB=-g -c -shared -Xcompiler -fPIC -Xcompiler -fvisibility=hidden | |
30 | 28 | NFLAGS = $(NFLAGS_LIB) $(INCLUDE) -std=c++11 |
31 | 29 | |
32 | 30 | SRCS:=$(wildcard $(SRC_ROOT)/*.cpp) | ... | ... |
src/common/inc/helper_cuda_drvapi.h
... | ... | @@ -218,7 +218,8 @@ inline int gpuGetMaxGflopsDeviceIdDRV() |
218 | 218 | // Find the best major SM Architecture GPU device |
219 | 219 | while (current_device < device_count) |
220 | 220 | { |
221 | - checkCudaErrors(cuDeviceComputeCapability(&major, &minor, current_device)); | |
221 | + checkCudaErrors(cuDeviceGetAttribute(&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, current_device)); | |
222 | + checkCudaErrors(cuDeviceGetAttribute(&minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, current_device)); | |
222 | 223 | |
223 | 224 | if (major > 0 && major < 9999) |
224 | 225 | { |
... | ... | @@ -239,7 +240,9 @@ inline int gpuGetMaxGflopsDeviceIdDRV() |
239 | 240 | checkCudaErrors(cuDeviceGetAttribute(&clockRate, |
240 | 241 | CU_DEVICE_ATTRIBUTE_CLOCK_RATE, |
241 | 242 | current_device)); |
242 | - checkCudaErrors(cuDeviceComputeCapability(&major, &minor, current_device)); | |
243 | + | |
244 | + checkCudaErrors(cuDeviceGetAttribute(&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, current_device)); | |
245 | + checkCudaErrors(cuDeviceGetAttribute(&minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, current_device)); | |
243 | 246 | |
244 | 247 | int computeMode; |
245 | 248 | getCudaAttribute<int>(&computeMode, CU_DEVICE_ATTRIBUTE_COMPUTE_MODE, current_device); |
... | ... | @@ -317,7 +320,9 @@ inline int gpuGetMaxGflopsGLDeviceIdDRV() |
317 | 320 | while (current_device < device_count) |
318 | 321 | { |
319 | 322 | checkCudaErrors(cuDeviceGetName(deviceName, 256, current_device)); |
320 | - checkCudaErrors(cuDeviceComputeCapability(&major, &minor, current_device)); | |
323 | + | |
324 | + checkCudaErrors(cuDeviceGetAttribute(&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, current_device)); | |
325 | + checkCudaErrors(cuDeviceGetAttribute(&minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, current_device)); | |
321 | 326 | |
322 | 327 | #if CUDA_VERSION >= 3020 |
323 | 328 | checkCudaErrors(cuDeviceGetAttribute(&bTCC, CU_DEVICE_ATTRIBUTE_TCC_DRIVER, current_device)); |
... | ... | @@ -369,7 +374,9 @@ inline int gpuGetMaxGflopsGLDeviceIdDRV() |
369 | 374 | checkCudaErrors(cuDeviceGetAttribute(&clockRate, |
370 | 375 | CU_DEVICE_ATTRIBUTE_CLOCK_RATE, |
371 | 376 | current_device)); |
372 | - checkCudaErrors(cuDeviceComputeCapability(&major, &minor, current_device)); | |
377 | + | |
378 | + checkCudaErrors(cuDeviceGetAttribute(&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, current_device)); | |
379 | + checkCudaErrors(cuDeviceGetAttribute(&minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, current_device)); | |
373 | 380 | |
374 | 381 | #if CUDA_VERSION >= 3020 |
375 | 382 | checkCudaErrors(cuDeviceGetAttribute(&bTCC, CU_DEVICE_ATTRIBUTE_TCC_DRIVER, current_device)); |
... | ... | @@ -500,7 +507,9 @@ inline bool checkCudaCapabilitiesDRV(int major_version, int minor_version, int d |
500 | 507 | |
501 | 508 | checkCudaErrors(cuDeviceGet(&cuDevice, devID)); |
502 | 509 | checkCudaErrors(cuDeviceGetName(name, 100, cuDevice)); |
503 | - checkCudaErrors(cuDeviceComputeCapability(&major, &minor, devID)); | |
510 | + | |
511 | + checkCudaErrors(cuDeviceGetAttribute(&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, devID)); | |
512 | + checkCudaErrors(cuDeviceGetAttribute(&minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, devID)); | |
504 | 513 | |
505 | 514 | if ((major > major_version) || |
506 | 515 | (major == major_version && minor >= minor_version)) | ... | ... |
src/main.cpp
... | ... | @@ -54,7 +54,7 @@ void postDecoded(const void * userPtr, AVFrame * gpuFrame){ |
54 | 54 | return; |
55 | 55 | } |
56 | 56 | |
57 | - string path = "/home/cmhu/data/" + decoder->getName() + "/" + to_string(sum) + ".jpg"; | |
57 | + string path = "/mnt/f/fiss/data/" + decoder->getName() + "/" + to_string(sum) + ".jpg"; | |
58 | 58 | saveJpeg(path.c_str(), pHwRgb[0], gpuFrame->width, gpuFrame->height, stream[0]); // 验证 CUDAToRGB |
59 | 59 | } |
60 | 60 | } else if (decoder->getName() == "dec2") |
... | ... | @@ -79,7 +79,7 @@ void postDecoded(const void * userPtr, AVFrame * gpuFrame){ |
79 | 79 | return; |
80 | 80 | } |
81 | 81 | |
82 | - string path = "/home/cmhu/data/" + decoder->getName() + "/" + to_string(sum) + ".jpg"; | |
82 | + string path = "/mnt/f/fiss/data/" + decoder->getName() + "/" + to_string(sum) + ".jpg"; | |
83 | 83 | saveJpeg(path.c_str(), pHwRgb[1], gpuFrame->width, gpuFrame->height, stream[1]); // 验证 CUDAToRGB |
84 | 84 | } |
85 | 85 | } |
... | ... | @@ -94,14 +94,10 @@ int count_std = 100; |
94 | 94 | |
95 | 95 | static long long get_cur_time(){ |
96 | 96 | // 获取操作系统当前时间点(精确到微秒) |
97 | - chrono::time_point<chrono::system_clock, chrono::microseconds> tpMicro | |
98 | - = chrono::time_point_cast<chrono::microseconds>(chrono::system_clock::now()); | |
97 | + chrono::time_point<chrono::system_clock, chrono::milliseconds> tpMicro | |
98 | + = chrono::time_point_cast<chrono::milliseconds>(chrono::system_clock::now()); | |
99 | 99 | // (微秒精度的)时间点 => (微秒精度的)时间戳 |
100 | - time_t totalMicroSeconds = tpMicro.time_since_epoch().count(); | |
101 | - | |
102 | - long long currentTime = ((long long)totalMicroSeconds)/1000; | |
103 | - | |
104 | - return currentTime; | |
100 | + return tpMicro.time_since_epoch().count(); | |
105 | 101 | } |
106 | 102 | |
107 | 103 | static int sum = 0; |
... | ... | @@ -124,47 +120,52 @@ void postDecoded0(const void * userPtr, AVFrame * gpuFrame){ |
124 | 120 | } |
125 | 121 | count++; |
126 | 122 | sum ++ ; |
127 | - // if (count >= count_std) | |
128 | - // { | |
129 | - // // end_time = get_cur_time(); | |
130 | - // // long time_using = end_time - start_time; | |
131 | - // // double time_per_frame = double(time_using)/count_std ; | |
132 | - // // cout << count_std << "帧用时:" << time_using << "ms 每帧用时:" << time_per_frame << "ms" << endl; | |
133 | - // cout << "keyframe: " << gpuFrame->key_frame << " width: " << gpuFrame->width << " height: "<< gpuFrame->height << endl; | |
134 | - // cout << gpuFrame->pts << endl; | |
135 | - | |
136 | - // count_flag = false; | |
137 | - // } | |
138 | - // cout << "帧数:" << sum << endl; | |
139 | - | |
140 | - // if (gpuFrame->format == AV_PIX_FMT_CUDA) | |
141 | - // { | |
142 | - // cudaSetDevice(atoi(decoder->m_cfg.gpuid.c_str())); | |
143 | - // // cout << "gpu id : " << decoder->m_cfg.gpuid.c_str() << endl; | |
144 | - // cudaError_t cudaStatus; | |
145 | - // if(pHwData == nullptr){ | |
146 | - // cuda_common::setColorSpace2( ITU709, 0 ); | |
147 | - // cudaStatus = cudaMalloc((void **)&pHwData, 3 * gpuFrame->width * gpuFrame->height * sizeof(unsigned char)); | |
148 | - // } | |
149 | - // cudaStatus = cuda_common::CUDAToBGR((CUdeviceptr)gpuFrame->data[0],(CUdeviceptr)gpuFrame->data[1], gpuFrame->linesize[0], gpuFrame->linesize[1], pHwData, gpuFrame->width, gpuFrame->height); | |
150 | - // cudaDeviceSynchronize(); | |
151 | - // if (cudaStatus != cudaSuccess) { | |
152 | - // cout << "CUDAToBGR failed !!!" << endl; | |
153 | - // return; | |
154 | - // } | |
155 | - | |
156 | - // string path = "/home/cmhu/data/test/" + to_string(sum) + ".jpg"; | |
157 | - // saveJpeg(path.c_str(), pHwData, gpuFrame->width, gpuFrame->height, nullptr); // 验证 CUDAToRGB | |
158 | - // } | |
123 | + if (count >= count_std) | |
124 | + { | |
125 | + // end_time = get_cur_time(); | |
126 | + // long time_using = end_time - start_time; | |
127 | + // double time_per_frame = double(time_using)/count_std ; | |
128 | + // cout << count_std << "帧用时:" << time_using << "ms 每帧用时:" << time_per_frame << "ms" << endl; | |
129 | + cout << "keyframe: " << gpuFrame->key_frame << " width: " << gpuFrame->width << " height: "<< gpuFrame->height << endl; | |
130 | + cout << gpuFrame->pts << endl; | |
131 | + | |
132 | + count_flag = false; | |
133 | + } | |
134 | + cout << "帧数:" << sum << endl; | |
135 | + | |
136 | + if (gpuFrame->format == AV_PIX_FMT_CUDA) | |
137 | + { | |
138 | + cudaSetDevice(atoi(decoder->m_cfg.gpuid.c_str())); | |
139 | + // cout << "gpu id : " << decoder->m_cfg.gpuid.c_str() << endl; | |
140 | + cudaError_t cudaStatus; | |
141 | + if(pHwData == nullptr){ | |
142 | + cuda_common::setColorSpace2( ITU709, 0 ); | |
143 | + cudaStatus = cudaMalloc((void **)&pHwData, 3 * gpuFrame->width * gpuFrame->height * sizeof(unsigned char)); | |
144 | + } | |
145 | + cudaStatus = cuda_common::CUDAToBGR((CUdeviceptr)gpuFrame->data[0],(CUdeviceptr)gpuFrame->data[1], gpuFrame->linesize[0], gpuFrame->linesize[1], pHwData, gpuFrame->width, gpuFrame->height); | |
146 | + cudaDeviceSynchronize(); | |
147 | + if (cudaStatus != cudaSuccess) { | |
148 | + cout << "CUDAToBGR failed !!!" << endl; | |
149 | + return; | |
150 | + } | |
151 | + | |
152 | + string path = "/mnt/f/fiss/data/" + to_string(sum) + ".jpg"; | |
153 | + saveJpeg(path.c_str(), pHwData, gpuFrame->width, gpuFrame->height, nullptr); // 验证 CUDAToRGB | |
154 | + } | |
159 | 155 | } |
160 | 156 | } |
161 | 157 | } |
162 | 158 | |
159 | +void decode_finished_cbk(const void* userPtr){ | |
160 | + cout << "decode_finish timestamp: " << get_cur_time() << endl; | |
161 | +} | |
162 | + | |
163 | 163 | // string test_uri = "rtmp://192.168.10.56:1935/objecteye/1"; |
164 | 164 | // string test_uri = "/home/cmhu/data/output_800x480.mp4"; |
165 | 165 | // string test_uri = "/home/cmhu/data/output_1920x1080.mp4"; |
166 | 166 | // string test_uri = "rtsp://176.10.0.2:8554/stream"; |
167 | -string test_uri = "/home/cmhu/data2/Street.uvf"; | |
167 | +// string test_uri = "/mnt/f/fiss/test_data/h265.mp4"; | |
168 | +string test_uri = "rtsp://176.10.0.4:8554/stream"; | |
168 | 169 | |
169 | 170 | void createDecode(int index){ |
170 | 171 | FFNvDecoderManager* pDecManager = FFNvDecoderManager::getInstance(); |
... | ... | @@ -172,15 +173,16 @@ void createDecode(int index){ |
172 | 173 | config.name = "dec" + to_string(index); |
173 | 174 | config.cfg.uri = test_uri; |
174 | 175 | config.cfg.post_decoded_cbk = postDecoded; |
176 | + config.cfg.decode_finished_cbk = decode_finished_cbk; | |
175 | 177 | config.cfg.force_tcp = true; |
176 | 178 | |
177 | 179 | if (index % 2 == 0) |
178 | 180 | { |
179 | - config.cfg.gpuid = "2"; | |
181 | + config.cfg.gpuid = "0"; | |
180 | 182 | } |
181 | 183 | else |
182 | 184 | { |
183 | - config.cfg.gpuid = "1"; | |
185 | + config.cfg.gpuid = "0"; | |
184 | 186 | } |
185 | 187 | |
186 | 188 | FFNvDecoder* decoder = pDecManager->createDecoder(config); |
... | ... | @@ -207,7 +209,10 @@ int CheckCUDAProperty( int devId ) |
207 | 209 | int major = 0, minor = 0; |
208 | 210 | CUresult rlt = CUDA_SUCCESS; |
209 | 211 | |
210 | - rlt = cuDeviceComputeCapability( &major, &minor, dev ); | |
212 | + rlt = cuDeviceGetAttribute(&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, dev); | |
213 | + checkCudaErrors( rlt ); | |
214 | + | |
215 | + rlt = cuDeviceGetAttribute(&minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, dev); | |
211 | 216 | checkCudaErrors( rlt ); |
212 | 217 | |
213 | 218 | rlt = cuDeviceGetName( devName, sizeof( devName ), dev ); |
... | ... | @@ -225,9 +230,17 @@ int CheckCUDAProperty( int devId ) |
225 | 230 | return 0; |
226 | 231 | } |
227 | 232 | |
233 | +void logFF(void *, int level, const char *fmt, va_list ap) | |
234 | +{ | |
235 | + vfprintf(stdout, fmt, ap); | |
236 | +} | |
237 | + | |
238 | + | |
228 | 239 | int main(){ |
229 | 240 | |
230 | - CheckCUDAProperty(1); | |
241 | + // av_log_set_callback(&logFF); | |
242 | + | |
243 | + CheckCUDAProperty(0); | |
231 | 244 | |
232 | 245 | FFNvDecoderManager* pDecManager = FFNvDecoderManager::getInstance(); |
233 | 246 | |
... | ... | @@ -241,17 +254,22 @@ int main(){ |
241 | 254 | config.name = "dec"; |
242 | 255 | config.cfg.uri = test_uri; |
243 | 256 | config.cfg.post_decoded_cbk = postDecoded0; |
257 | + config.cfg.decode_finished_cbk = decode_finished_cbk; | |
244 | 258 | config.cfg.force_tcp = true; |
245 | - config.cfg.gpuid = "2"; | |
259 | + config.cfg.gpuid = "0"; | |
246 | 260 | FFNvDecoder* dec2 = pDecManager->createDecoder(config); |
247 | 261 | if (!dec2) |
248 | 262 | { |
249 | 263 | return 1; |
250 | 264 | } |
251 | 265 | pDecManager->setUserPtr(config.name, dec2); |
252 | - pDecManager->setDecKeyframe(config.name, true); | |
266 | + // pDecManager->setDecKeyframe(config.name, true); | |
253 | 267 | pDecManager->startDecodeByName(config.name); |
254 | 268 | |
269 | + int w,h; | |
270 | + pDecManager->getResolution(config.name, w,h); | |
271 | + printf( "%s : %dx%d\n", config.name.c_str() , w,h ); | |
272 | + | |
255 | 273 | pthread_t m_decode_thread; |
256 | 274 | pthread_create(&m_decode_thread,0, |
257 | 275 | [](void* arg) | ... | ... |