aac5773f
hucm
功能基本完成,接口待打磨
|
1
|
#include "FFNvDecoder.h"
|
aac5773f
hucm
功能基本完成,接口待打磨
|
2
3
4
|
#include <chrono>
#include <thread>
|
8c180bab
hucm
添加是否实时流判断
|
5
|
#include <fstream>
|
aac5773f
hucm
功能基本完成,接口待打磨
|
6
|
|
3d2ab595
Hu Chunming
支持gb28181
|
7
8
|
#include <chrono>
|
f40cc409
Hu Chunming
优化显存占用。当前在3080显卡上...
|
9
10
|
#include "FFCuContextManager.h"
|
3d2ab595
Hu Chunming
支持gb28181
|
11
12
|
#include "logger.hpp"
|
92989af0
ming
更新解码器
|
13
14
|
#include "utiltools.hpp"
|
aac5773f
hucm
功能基本完成,接口待打磨
|
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
using namespace std;
// 参考博客: https://blog.csdn.net/qq_40116098/article/details/120704340
static AVPixelFormat get_hw_format(AVCodecContext *avctx, const AVPixelFormat *pix_fmts)
{
FFNvDecoder* _this = (FFNvDecoder*)avctx->opaque;
const AVPixelFormat *p;
for (p = pix_fmts; *p != -1; p++) {
if (*p == _this->getHwPixFmt())
return *p;
}
|
3d2ab595
Hu Chunming
支持gb28181
|
30
|
LOG_ERROR("Failed to get HW surface format");
|
aac5773f
hucm
功能基本完成,接口待打磨
|
31
32
33
34
35
36
37
38
39
40
41
42
43
|
return AV_PIX_FMT_NONE;
}
FFNvDecoder::FFNvDecoder()
{
// 初始化解码对象
fmt_ctx = nullptr;
avctx = nullptr;
m_bRunning = false;
stream = nullptr;
stream_index = -1;
hw_pix_fmt = AV_PIX_FMT_NONE;
|
3d2ab595
Hu Chunming
支持gb28181
|
44
|
m_dec_name = "";
|
aac5773f
hucm
功能基本完成,接口待打磨
|
45
46
|
m_bPause = false;
|
8c180bab
hucm
添加是否实时流判断
|
47
|
m_bReal = true;
|
e96e6489
Hu Chunming
优化代码;添加isRunning函数
|
48
49
50
|
m_decode_thread = 0;
m_post_decode_thread = 0;
|
48330793
Hu Chunming
修正解码线程自然结束时解码器内存没...
|
51
52
|
m_bFinished = false;
|
bc52e542
Hu Chunming
添加关键帧解码功能
|
53
|
m_dec_keyframe = false;
|
3d2ab595
Hu Chunming
支持gb28181
|
54
|
m_fps = 0.0;
|
aac5773f
hucm
功能基本完成,接口待打磨
|
55
56
57
58
|
}
FFNvDecoder::~FFNvDecoder()
{
|
bc52e542
Hu Chunming
添加关键帧解码功能
|
59
|
m_dec_keyframe = false;
|
aac5773f
hucm
功能基本完成,接口待打磨
|
60
61
|
}
|
e96e6489
Hu Chunming
优化代码;添加isRunning函数
|
62
|
bool FFNvDecoder::init(FFDecConfig& cfg)
|
7319ea36
Hu Chunming
多显卡设置
|
63
64
65
66
67
68
69
70
71
72
73
|
{
m_cfg = cfg;
fstream infile(cfg.uri);
if (infile.is_open()){
m_bReal = false;
infile.close();
}else {
m_bReal = true;
}
|
372e629f
ming
gb28181支持TCP数据流
|
74
75
76
|
post_decoded_cbk = cfg.post_decoded_cbk;
decode_finished_cbk = cfg.decode_finished_cbk;
|
e96e6489
Hu Chunming
优化代码;添加isRunning函数
|
77
78
79
80
81
|
return init(cfg.uri.c_str(), cfg.gpuid.c_str(),cfg.force_tcp);
}
bool FFNvDecoder::init(const char* uri, const char* gpuid, bool force_tcp)
{
|
f40cc409
Hu Chunming
优化显存占用。当前在3080显卡上...
|
82
83
|
// av_log_set_level(AV_LOG_DEBUG);
|
e96e6489
Hu Chunming
优化代码;添加isRunning函数
|
84
|
avformat_network_init();
|
7319ea36
Hu Chunming
多显卡设置
|
85
86
87
88
|
// 打开输入视频文件
AVDictionary *options = nullptr;
av_dict_set( &options, "bufsize", "655360", 0 );
|
e96e6489
Hu Chunming
优化代码;添加isRunning函数
|
89
|
av_dict_set( &options, "rtsp_transport", force_tcp ? "tcp" : "udp", 0 );
|
7319ea36
Hu Chunming
多显卡设置
|
90
|
// av_dict_set( &options, "listen_timeout", "30", 0 ); // 单位为s
|
48330793
Hu Chunming
修正解码线程自然结束时解码器内存没...
|
91
|
av_dict_set( &options, "stimeout", "30000000", 0 ); // 单位为 百万分之一秒
|
7319ea36
Hu Chunming
多显卡设置
|
92
93
|
fmt_ctx = avformat_alloc_context();
|
e96e6489
Hu Chunming
优化代码;添加isRunning函数
|
94
|
const char* input_file = uri;
|
7319ea36
Hu Chunming
多显卡设置
|
95
|
if (avformat_open_input(&fmt_ctx, input_file, nullptr, &options) != 0) {
|
3d2ab595
Hu Chunming
支持gb28181
|
96
|
LOG_ERROR("Cannot open input file:{}",input_file);
|
7319ea36
Hu Chunming
多显卡设置
|
97
98
99
100
101
|
return false;
}
// 查找流信息
if (avformat_find_stream_info(fmt_ctx, nullptr) < 0) {
|
3d2ab595
Hu Chunming
支持gb28181
|
102
|
LOG_ERROR("Cannot find input stream information");
|
7319ea36
Hu Chunming
多显卡设置
|
103
104
105
106
107
108
109
|
return false;
}
// 查找视频流信息
AVCodec *decoder = nullptr;
stream_index = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &decoder, 0);
if (stream_index < 0) {
|
3d2ab595
Hu Chunming
支持gb28181
|
110
|
LOG_ERROR("Cannot find a video stream in the input file");
|
7319ea36
Hu Chunming
多显卡设置
|
111
112
113
|
return false;
}
|
7319ea36
Hu Chunming
多显卡设置
|
114
115
116
117
118
119
120
121
122
123
|
string cuvid_dec_name = string(decoder->name) + "_cuvid";
AVCodec *vcodec = avcodec_find_decoder_by_name(cuvid_dec_name.c_str());
if (!(avctx = avcodec_alloc_context3(vcodec)))
return (bool)AVERROR(ENOMEM);
// 得到视频流对象
stream = fmt_ctx->streams[stream_index];
if (avcodec_parameters_to_context(avctx, stream->codecpar) < 0)
return false;
|
3d2ab595
Hu Chunming
支持gb28181
|
124
125
|
m_fps = av_q2d(stream ->avg_frame_rate);
|
7319ea36
Hu Chunming
多显卡设置
|
126
127
128
129
130
131
|
avctx->opaque = this;
// 设置解码器管理器的像素格式回调函数
avctx->get_format = get_hw_format;
hw_pix_fmt = AV_PIX_FMT_CUDA;
|
f40cc409
Hu Chunming
优化显存占用。当前在3080显卡上...
|
132
|
FFCuContextManager* pCtxMgr = FFCuContextManager::getInstance();
|
d384f0e9
Hu Chunming
代码优化
|
133
134
135
136
137
138
139
|
AVBufferRef *hw_device_ctx = pCtxMgr->getCuCtx(gpuid);
if(nullptr == hw_device_ctx){
av_log(nullptr, AV_LOG_ERROR, "create CUDA context failed ! \n");
return false;
}
avctx->hw_device_ctx = av_buffer_ref(hw_device_ctx);
|
f40cc409
Hu Chunming
优化显存占用。当前在3080显卡上...
|
140
141
142
143
144
|
if (nullptr == avctx->hw_device_ctx)
{
return false;
}
|
7319ea36
Hu Chunming
多显卡设置
|
145
146
|
// 打开解码器流
AVDictionary *op = nullptr;
|
e96e6489
Hu Chunming
优化代码;添加isRunning函数
|
147
|
av_dict_set( &op, "gpu", gpuid, 0 );
|
3d2ab595
Hu Chunming
支持gb28181
|
148
|
// av_dict_set( &op, "surfaces", "5", 0 );
|
7319ea36
Hu Chunming
多显卡设置
|
149
|
if (avcodec_open2(avctx, vcodec, &op) < 0) {
|
3d2ab595
Hu Chunming
支持gb28181
|
150
|
LOG_ERROR("Failed to open codec for stream");
|
7319ea36
Hu Chunming
多显卡设置
|
151
152
|
return false;
}
|
3d2ab595
Hu Chunming
支持gb28181
|
153
|
|
7319ea36
Hu Chunming
多显卡设置
|
154
155
156
|
return true;
}
|
0573bd98
Hu Chunming
优化代码;添加注释
|
157
158
159
160
161
162
163
|
bool FFNvDecoder::isSurport(FFDecConfig& cfg)
{
bool bRet = init(cfg);
decode_finished();
return bRet;
}
|
3d2ab595
Hu Chunming
支持gb28181
|
164
|
bool FFNvDecoder::start(){
|
aac5773f
hucm
功能基本完成,接口待打磨
|
165
166
167
168
169
170
171
172
173
174
175
|
m_bRunning = true;
pthread_create(&m_decode_thread,0,
[](void* arg)
{
FFNvDecoder* a=(FFNvDecoder*)arg;
a->decode_thread();
return (void*)0;
}
,this);
|
3d2ab595
Hu Chunming
支持gb28181
|
176
177
|
return true;
|
48330793
Hu Chunming
修正解码线程自然结束时解码器内存没...
|
178
179
|
}
|
48330793
Hu Chunming
修正解码线程自然结束时解码器内存没...
|
180
181
182
183
184
|
void FFNvDecoder::decode_thread()
{
AVPacket* pkt ;
pkt = av_packet_alloc();
av_init_packet( pkt );
|
aac5773f
hucm
功能基本完成,接口待打磨
|
185
186
187
188
189
190
191
192
193
|
pthread_create(&m_post_decode_thread,0,
[](void* arg)
{
FFNvDecoder* a=(FFNvDecoder*)arg;
a->post_decode_thread();
return (void*)0;
}
,this);
|
aac5773f
hucm
功能基本完成,接口待打磨
|
194
|
|
92989af0
ming
更新解码器
|
195
|
// long start_time = UtilTools::get_cur_time_ms();
|
bc52e542
Hu Chunming
添加关键帧解码功能
|
196
|
|
aac5773f
hucm
功能基本完成,接口待打磨
|
197
198
|
while (m_bRunning)
{
|
8c180bab
hucm
添加是否实时流判断
|
199
|
if (!m_bReal)
|
aac5773f
hucm
功能基本完成,接口待打磨
|
200
|
{
|
8c180bab
hucm
添加是否实时流判断
|
201
202
203
204
205
|
if (m_bPause)
{
std::this_thread::sleep_for(std::chrono::milliseconds(3));
continue;
}
|
aac5773f
hucm
功能基本完成,接口待打磨
|
206
|
}
|
aac5773f
hucm
功能基本完成,接口待打磨
|
207
208
|
int result = av_read_frame(fmt_ctx, pkt);
|
3c7e3e11
Hu Chunming
1.修改日志
|
209
|
if (result == AVERROR_EOF || result < 0)
|
aac5773f
hucm
功能基本完成,接口待打磨
|
210
|
{
|
3d2ab595
Hu Chunming
支持gb28181
|
211
|
LOG_ERROR("Failed to read frame!");
|
aac5773f
hucm
功能基本完成,接口待打磨
|
212
213
214
|
break;
}
|
bc52e542
Hu Chunming
添加关键帧解码功能
|
215
216
217
218
219
|
if (m_dec_keyframe && !(pkt->flags & AV_PKT_FLAG_KEY)) {
av_packet_unref(pkt);
continue;
}
|
f49bbf3d
Hu Chunming
修正pause逻辑;添加ignore
|
220
|
if (m_bReal)
|
8c180bab
hucm
添加是否实时流判断
|
221
222
223
224
225
226
227
228
229
|
{
if (m_bPause)
{
av_packet_unref(pkt);
std::this_thread::sleep_for(std::chrono::milliseconds(3));
continue;
}
}
|
3c7e3e11
Hu Chunming
1.修改日志
|
230
|
if (stream_index == pkt->stream_index){
|
aac5773f
hucm
功能基本完成,接口待打磨
|
231
|
result = avcodec_send_packet(avctx, pkt);
|
3c7e3e11
Hu Chunming
1.修改日志
|
232
|
if (result < 0){
|
92989af0
ming
更新解码器
|
233
|
av_packet_unref(pkt);
|
3d2ab595
Hu Chunming
支持gb28181
|
234
|
LOG_ERROR("{} - Failed to send pkt: {}", m_dec_name, result);
|
aac5773f
hucm
功能基本完成,接口待打磨
|
235
236
237
|
continue;
}
|
92989af0
ming
更新解码器
|
238
|
AVFrame* gpuFrame = av_frame_alloc();
|
aac5773f
hucm
功能基本完成,接口待打磨
|
239
|
result = avcodec_receive_frame(avctx, gpuFrame);
|
3c7e3e11
Hu Chunming
1.修改日志
|
240
|
if ((result == AVERROR(EAGAIN) || result == AVERROR_EOF) || result < 0){
|
3d2ab595
Hu Chunming
支持gb28181
|
241
|
LOG_ERROR("{} - Failed to receive frame: {}", m_dec_name, result);
|
92989af0
ming
更新解码器
|
242
243
|
av_frame_free(&gpuFrame);
av_packet_unref(pkt);
|
aac5773f
hucm
功能基本完成,接口待打磨
|
244
245
|
continue;
}
|
92989af0
ming
更新解码器
|
246
|
av_packet_unref(pkt);
|
aac5773f
hucm
功能基本完成,接口待打磨
|
247
|
|
92989af0
ming
更新解码器
|
248
249
250
251
252
253
254
255
256
|
if(gpuFrame != nullptr){
m_queue_mutex.lock();
if(mFrameQueue.size() <= 10){
mFrameQueue.push(gpuFrame);
}else{
av_frame_free(&gpuFrame);
}
m_queue_mutex.unlock();
}
|
aac5773f
hucm
功能基本完成,接口待打磨
|
257
258
259
260
|
}
av_packet_unref(pkt);
}
|
aac5773f
hucm
功能基本完成,接口待打磨
|
261
|
m_bRunning = false;
|
48330793
Hu Chunming
修正解码线程自然结束时解码器内存没...
|
262
|
|
92989af0
ming
更新解码器
|
263
|
// long end_time = UtilTools::get_cur_time_ms();
|
bc52e542
Hu Chunming
添加关键帧解码功能
|
264
265
|
// cout << "解码用时:" << end_time - start_time << endl;
|
48330793
Hu Chunming
修正解码线程自然结束时解码器内存没...
|
266
267
268
269
270
|
if (m_post_decode_thread != 0)
{
pthread_join(m_post_decode_thread,0);
}
|
3d2ab595
Hu Chunming
支持gb28181
|
271
|
decode_finished_cbk(m_finishedDecArg);
|
3c7e3e11
Hu Chunming
1.修改日志
|
272
|
|
48330793
Hu Chunming
修正解码线程自然结束时解码器内存没...
|
273
274
|
decode_finished();
|
92989af0
ming
更新解码器
|
275
276
277
278
279
280
281
|
// 清空队列
while(mFrameQueue.size() > 0){
AVFrame * gpuFrame = mFrameQueue.front();
av_frame_free(&gpuFrame);
mFrameQueue.pop();
}
|
3d2ab595
Hu Chunming
支持gb28181
|
282
|
LOG_INFO("{} - decode thread exited.", m_dec_name);
|
aac5773f
hucm
功能基本完成,接口待打磨
|
283
284
|
}
|
3d2ab595
Hu Chunming
支持gb28181
|
285
|
void FFNvDecoder::decode_finished(){
|
48330793
Hu Chunming
修正解码线程自然结束时解码器内存没...
|
286
287
|
if (avctx)
{
|
48330793
Hu Chunming
修正解码线程自然结束时解码器内存没...
|
288
289
290
291
292
293
294
295
296
|
avcodec_free_context(&avctx);
}
if (fmt_ctx)
{
avformat_close_input(&fmt_ctx);
}
m_bFinished = true;
|
bc52e542
Hu Chunming
添加关键帧解码功能
|
297
|
m_dec_keyframe = false;
|
48330793
Hu Chunming
修正解码线程自然结束时解码器内存没...
|
298
299
|
}
|
3d2ab595
Hu Chunming
支持gb28181
|
300
301
302
303
304
305
306
|
void FFNvDecoder::post_decode_thread(){
int skip_frame = m_cfg.skip_frame;
if (skip_frame <= 0){
skip_frame = 1;
}
int index = 0;
|
92989af0
ming
更新解码器
|
307
|
while (m_bRunning)
|
3d2ab595
Hu Chunming
支持gb28181
|
308
|
{
|
92989af0
ming
更新解码器
|
309
310
311
312
313
314
315
316
317
318
319
320
|
if(mFrameQueue.size() > 0){
std::lock_guard<std::mutex> l(m_snapshot_mutex);
// 取队头数据
m_queue_mutex.lock();
AVFrame * gpuFrame = mFrameQueue.front();
mFrameQueue.pop();
m_queue_mutex.unlock();
// 跳帧
if (skip_frame == 1 || index % skip_frame == 0){
post_decoded_cbk(m_postDecArg, gpuFrame);
index = 0;
}
|
aac5773f
hucm
功能基本完成,接口待打磨
|
321
|
|
92989af0
ming
更新解码器
|
322
|
av_frame_free(&gpuFrame);
|
3c7e3e11
Hu Chunming
1.修改日志
|
323
|
|
92989af0
ming
更新解码器
|
324
325
|
index++;
}
|
3d2ab595
Hu Chunming
支持gb28181
|
326
327
328
|
}
LOG_INFO("post decode thread exited.");
|
aac5773f
hucm
功能基本完成,接口待打磨
|
329
330
|
}
|
3d2ab595
Hu Chunming
支持gb28181
|
331
|
void FFNvDecoder::close(){
|
aac5773f
hucm
功能基本完成,接口待打磨
|
332
|
m_bRunning=false;
|
e96e6489
Hu Chunming
优化代码;添加isRunning函数
|
333
334
335
|
if(m_decode_thread != 0){
pthread_join(m_decode_thread,0);
}
|
bc52e542
Hu Chunming
添加关键帧解码功能
|
336
|
m_dec_keyframe = false;
|
aac5773f
hucm
功能基本完成,接口待打磨
|
337
338
|
}
|
3d2ab595
Hu Chunming
支持gb28181
|
339
|
AVPixelFormat FFNvDecoder::getHwPixFmt(){
|
aac5773f
hucm
功能基本完成,接口待打磨
|
340
341
342
|
return hw_pix_fmt;
}
|
3d2ab595
Hu Chunming
支持gb28181
|
343
|
bool FFNvDecoder::isRunning(){
|
aac5773f
hucm
功能基本完成,接口待打磨
|
344
345
346
|
return m_bRunning;
}
|
3d2ab595
Hu Chunming
支持gb28181
|
347
|
bool FFNvDecoder::isFinished(){
|
48330793
Hu Chunming
修正解码线程自然结束时解码器内存没...
|
348
349
350
|
return m_bFinished;
}
|
3c7e3e11
Hu Chunming
1.修改日志
|
351
352
353
354
|
bool FFNvDecoder::isPausing(){
return m_bPause;
}
|
3d2ab595
Hu Chunming
支持gb28181
|
355
356
|
bool FFNvDecoder::getResolution( int &width, int &height ){
if (avctx != nullptr)
|
aac5773f
hucm
功能基本完成,接口待打磨
|
357
|
{
|
3d2ab595
Hu Chunming
支持gb28181
|
358
359
|
width = avctx->width;
height = avctx->height;
|
aac5773f
hucm
功能基本完成,接口待打磨
|
360
361
362
363
364
365
|
return true;
}
return false;
}
|
3d2ab595
Hu Chunming
支持gb28181
|
366
|
void FFNvDecoder::pause(){
|
aac5773f
hucm
功能基本完成,接口待打磨
|
367
368
369
|
m_bPause = true;
}
|
3d2ab595
Hu Chunming
支持gb28181
|
370
|
void FFNvDecoder::resume(){
|
aac5773f
hucm
功能基本完成,接口待打磨
|
371
|
m_bPause = false;
|
bc52e542
Hu Chunming
添加关键帧解码功能
|
372
373
374
375
376
|
}
void FFNvDecoder::setDecKeyframe(bool bKeyframe)
{
m_dec_keyframe = bKeyframe;
|
3c7e3e11
Hu Chunming
1.修改日志
|
377
378
379
|
}
int FFNvDecoder::getCachedQueueLength(){
|
92989af0
ming
更新解码器
|
380
381
382
383
|
m_queue_mutex.lock();
int queue_size = mFrameQueue.size();
m_queue_mutex.lock();
return queue_size;
|
3c7e3e11
Hu Chunming
1.修改日志
|
384
385
|
}
|
3d2ab595
Hu Chunming
支持gb28181
|
386
387
|
float FFNvDecoder::fps(){
return m_fps;
|
d384f0e9
Hu Chunming
代码优化
|
388
|
}
|