Blame view

src/FFNvDecoder.cpp 5.92 KB
aac5773f   hucm   功能基本完成,接口待打磨
1
2
3
4
5
  #include "FFNvDecoder.h"
  #include<iostream>
  
  #include <chrono>
  #include <thread>
8c180bab   hucm   添加是否实时流判断
6
  #include <fstream>
aac5773f   hucm   功能基本完成,接口待打磨
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
  
  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;
  	}
  
  	//cout << "Failed to get HW surface format";
  	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;
      name = "";
  
  	m_bPause = false;
8c180bab   hucm   添加是否实时流判断
40
  	m_bReal = true;
e96e6489   Hu Chunming   优化代码;添加isRunning函数
41
42
43
  
  	m_decode_thread = 0;
  	m_post_decode_thread = 0;
48330793   Hu Chunming   修正解码线程自然结束时解码器内存没...
44
45
  
  	m_bFinished = false;
aac5773f   hucm   功能基本完成,接口待打磨
46
47
48
49
50
51
52
  }
  
  FFNvDecoder::~FFNvDecoder()
  {
  	
  }
  
e96e6489   Hu Chunming   优化代码;添加isRunning函数
53
  bool FFNvDecoder::init(FFDecConfig& cfg)
7319ea36   Hu Chunming   多显卡设置
54
55
56
57
58
59
60
61
62
63
64
  {
  	m_cfg = cfg;
  
  	fstream infile(cfg.uri);
  	if (infile.is_open()){
  		m_bReal = false;
  		infile.close();
  	}else {
  		m_bReal = true;
  	}
  
e96e6489   Hu Chunming   优化代码;添加isRunning函数
65
66
67
68
69
70
71
  	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)
  {
  	av_register_all();
  	avformat_network_init();
7319ea36   Hu Chunming   多显卡设置
72
73
74
75
  
  	// 打开输入视频文件
  	AVDictionary *options = nullptr;
  	av_dict_set( &options, "bufsize", "655360", 0 );
e96e6489   Hu Chunming   优化代码;添加isRunning函数
76
  	av_dict_set( &options, "rtsp_transport", force_tcp ? "tcp" : "udp", 0 );
7319ea36   Hu Chunming   多显卡设置
77
  	// av_dict_set( &options, "listen_timeout", "30", 0 ); // 单位为s
48330793   Hu Chunming   修正解码线程自然结束时解码器内存没...
78
  	av_dict_set( &options, "stimeout", "30000000", 0 ); // 单位为 百万分之一秒
7319ea36   Hu Chunming   多显卡设置
79
80
  	
  	fmt_ctx = avformat_alloc_context();
e96e6489   Hu Chunming   优化代码;添加isRunning函数
81
  	const char* input_file = uri;
7319ea36   Hu Chunming   多显卡设置
82
  	if (avformat_open_input(&fmt_ctx, input_file, nullptr, &options) != 0) {
48330793   Hu Chunming   修正解码线程自然结束时解码器内存没...
83
  		cout << "Cannot open input file: " << input_file;
7319ea36   Hu Chunming   多显卡设置
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
  		return false;
  	}
  
  	// 查找流信息
  	if (avformat_find_stream_info(fmt_ctx, nullptr) < 0) {
  		cout << "Cannot find input stream information";
  		return false;
  	}
  
  	// 查找视频流信息
  	AVCodec *decoder = nullptr;
  	stream_index = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &decoder, 0);
  	if (stream_index < 0) {
  		cout << "Cannot find a video stream in the input file";
  		return false;
  	}
  
7319ea36   Hu Chunming   多显卡设置
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
  	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;
  
  	avctx->opaque = this;
  	// 设置解码器管理器的像素格式回调函数
  	avctx->get_format = get_hw_format;
  
  	hw_pix_fmt = AV_PIX_FMT_CUDA;
  
  	// 打开解码器流
  	AVDictionary *op = nullptr;
e96e6489   Hu Chunming   优化代码;添加isRunning函数
119
  	av_dict_set( &op, "gpu", gpuid, 0 );
7319ea36   Hu Chunming   多显卡设置
120
121
122
123
124
125
126
127
  	if (avcodec_open2(avctx, vcodec, &op) < 0) {
  		cout << "Failed to open codec for stream" << stream_index;
  		return false;
  	}
  
  	return true;
  }
  
aac5773f   hucm   功能基本完成,接口待打磨
128
129
130
131
132
133
134
135
136
137
138
139
  void FFNvDecoder::start(){
  
  	m_bRunning = true;
  
  	pthread_create(&m_decode_thread,0,
          [](void* arg)
          {
              FFNvDecoder* a=(FFNvDecoder*)arg;
              a->decode_thread();
              return (void*)0;
          }
      ,this);
48330793   Hu Chunming   修正解码线程自然结束时解码器内存没...
140
141
142
143
144
145
146
  }
  
  void FFNvDecoder::decode_thread()
  {
  	AVPacket* pkt ;
  	pkt = av_packet_alloc();
  	av_init_packet( pkt );
aac5773f   hucm   功能基本完成,接口待打磨
147
148
149
150
151
152
153
154
155
  
  	pthread_create(&m_post_decode_thread,0,
          [](void* arg)
          {
              FFNvDecoder* a=(FFNvDecoder*)arg;
              a->post_decode_thread();
              return (void*)0;
          }
      ,this);
aac5773f   hucm   功能基本完成,接口待打磨
156
157
158
  
  	while (m_bRunning)
  	{
8c180bab   hucm   添加是否实时流判断
159
  		if (!m_bReal)
aac5773f   hucm   功能基本完成,接口待打磨
160
  		{
8c180bab   hucm   添加是否实时流判断
161
162
163
164
165
  			if (m_bPause)
  			{
  				std::this_thread::sleep_for(std::chrono::milliseconds(3));
  				continue;
  			}
aac5773f   hucm   功能基本完成,接口待打磨
166
  		}
e41a52bb   Hu Chunming   1.优化数据读取线程;2. 添加A...
167
168
169
170
171
172
173
  
  		AVFrame * gpuFrame = mFrameQueue.getTail();
  		if (gpuFrame == nullptr)
  		{
  			std::this_thread::sleep_for(std::chrono::milliseconds(1));
  			continue;
  		}
aac5773f   hucm   功能基本完成,接口待打磨
174
175
176
177
178
179
180
181
182
183
184
185
186
  		
  		int result = av_read_frame(fmt_ctx, pkt);
  		if (result == AVERROR_EOF)
  		{
  			cout << "Failed to read frame!" << endl;
  			break;
  		}
  		if (result < 0)
  		{
  			cout << "Failed to read frame!" << endl;
  			break;
  		}
  
f49bbf3d   Hu Chunming   修正pause逻辑;添加ignore
187
  		if (m_bReal)
8c180bab   hucm   添加是否实时流判断
188
189
190
191
192
193
194
195
196
  		{
  			if (m_bPause)
  			{
  				av_packet_unref(pkt);
  				std::this_thread::sleep_for(std::chrono::milliseconds(3));
  				continue;
  			}
  		}
  
aac5773f   hucm   功能基本完成,接口待打磨
197
198
199
200
201
  		if (stream_index == pkt->stream_index)
  		{
  			result = avcodec_send_packet(avctx, pkt);
  			if (result < 0)
  			{
7319ea36   Hu Chunming   多显卡设置
202
  				cout << "Failed to send pkt:" << result << endl;
aac5773f   hucm   功能基本完成,接口待打磨
203
204
205
  				continue;
  			}
  
aac5773f   hucm   功能基本完成,接口待打磨
206
207
208
209
210
211
212
213
  			result = avcodec_receive_frame(avctx, gpuFrame);
  			if (result == AVERROR(EAGAIN) || result == AVERROR_EOF || result < 0)
  			{
  				cout << "Failed to receive frame"<< endl;
  				continue;
  			}
  
  			mFrameQueue.addTail();
aac5773f   hucm   功能基本完成,接口待打磨
214
215
216
217
218
  		}
  		av_packet_unref(pkt);
  	}
  
  	m_bRunning = false;
48330793   Hu Chunming   修正解码线程自然结束时解码器内存没...
219
220
221
222
223
224
225
226
  
  	if (m_post_decode_thread != 0)
  	{
  		pthread_join(m_post_decode_thread,0);
  	}
  
  	decode_finished();
  
aac5773f   hucm   功能基本完成,接口待打磨
227
228
229
  	cout << "decode thread exited." << endl;
  }
  
48330793   Hu Chunming   修正解码线程自然结束时解码器内存没...
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
  void FFNvDecoder::decode_finished()
  {
  	if (avctx)
  	{
  		if (avctx->hw_device_ctx)
  		{
  			av_buffer_unref(&avctx->hw_device_ctx);
  		}
  		avcodec_free_context(&avctx);
  	}
  	
  	if (fmt_ctx)
  	{
  		avformat_close_input(&fmt_ctx);
  	}
  
  	m_bFinished = true;
  }
  
aac5773f   hucm   功能基本完成,接口待打磨
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
  void FFNvDecoder::post_decode_thread()
  {
  	 while (m_bRunning)
  	 {
  		AVFrame * gpuFrame = mFrameQueue.getHead();
  		if (gpuFrame == nullptr)
  		{
  			std::this_thread::sleep_for(std::chrono::milliseconds(3));
  			continue;
  		}
  
  		post_decoded_cbk(m_userPtr, gpuFrame);
  
  		mFrameQueue.addHead();
  	 }
  	 
  	 cout << "post decode thread exited." << endl;
  }
  
  void FFNvDecoder::close()
  {
  	m_bRunning=false;
e96e6489   Hu Chunming   优化代码;添加isRunning函数
271
272
273
  	if(m_decode_thread != 0){
  		pthread_join(m_decode_thread,0);
  	}
aac5773f   hucm   功能基本完成,接口待打磨
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
  }
  
  void FFNvDecoder::setName(string nm){
  	name = nm;
  }
  
  string FFNvDecoder::getName(){
  	return name;
  }
  
  AVPixelFormat FFNvDecoder::getHwPixFmt()
  {
  	return hw_pix_fmt;
  }
  
  bool FFNvDecoder::isRunning()
  {
  	return m_bRunning;
  }
  
48330793   Hu Chunming   修正解码线程自然结束时解码器内存没...
294
295
296
297
298
  bool FFNvDecoder::isFinished()
  {
  	return m_bFinished;
  }
  
aac5773f   hucm   功能基本完成,接口待打磨
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
  bool FFNvDecoder::getResolution( int &width, int &height )
  {
  	if (avctx != nullptr)
  	{
  		width = avctx->width;
  		height = avctx->height;
  		return true;
  	}
  	
  	return false;
  }
  
  void FFNvDecoder::pause()
  {
  	m_bPause = true;
  }
  
  void FFNvDecoder::resume()
  {
  	m_bPause = false;
  }