Commit c027963f5bf730c6ca10c85b5af7e84cc09d4c9d
1 parent
150d457d
ffmpeg6.1.1版本的接收rtp
Showing
27 changed files
with
1833 additions
and
721 deletions
src/decoder/dvpp/DvppDecoder.cpp
... | ... | @@ -174,7 +174,7 @@ AVCodecContext* DvppDecoder::init_FFmpeg(FFDecConfig config){ |
174 | 174 | } |
175 | 175 | |
176 | 176 | // 查找视频流信息 |
177 | - AVCodec *decoder = nullptr; | |
177 | + const AVCodec *decoder = nullptr; | |
178 | 178 | video_index = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &decoder, 0); |
179 | 179 | if (video_index < 0) { |
180 | 180 | LOG_ERROR("[{}]- Cannot find a video stream in the input file!", m_dec_name); |
... | ... | @@ -480,10 +480,6 @@ DeviceMemory* DvppDecoder::snapshot(){ |
480 | 480 | return snapshot_mem; |
481 | 481 | } |
482 | 482 | |
483 | -int DvppDecoder::getCachedQueueLength(){ | |
484 | - return 0; | |
485 | -} | |
486 | - | |
487 | 483 | void DvppDecoder::release_ffmpeg() { |
488 | 484 | m_dec_keyframe = false; |
489 | 485 | if(h264bsfc){ | ... | ... |
src/decoder/dvpp/DvppDecoder.h
src/decoder/dvpp/DvppDecoderApi.cpp
... | ... | @@ -100,13 +100,6 @@ float DvppDecoderApi::fps(){ |
100 | 100 | return 0.0; |
101 | 101 | } |
102 | 102 | |
103 | -int DvppDecoderApi::getCachedQueueLength(){ | |
104 | - if(m_pDecoder != nullptr){ | |
105 | - return m_pDecoder->getCachedQueueLength(); | |
106 | - } | |
107 | - return 0; | |
108 | -} | |
109 | - | |
110 | 103 | void DvppDecoderApi::setName(string nm){ |
111 | 104 | if(m_pDecoder != nullptr){ |
112 | 105 | return m_pDecoder->setName(nm); | ... | ... |
src/decoder/dvpp/DvppDecoderApi.h
src/decoder/dvpp/DvppRtpDecoder.cpp
0 → 100644
1 | +#include "DvppRtpDecoder.h" | |
2 | + | |
3 | +#include "DvppSourceManager.h" | |
4 | +#include "../gb28181/rtp2/Rtp.h" | |
5 | + | |
6 | + | |
7 | +#define CHECK_AND_RETURN(ret, message) \ | |
8 | + if(ret != 0) {LOG_ERROR("[{}]- {}", m_dec_name, message); return ret;} | |
9 | +#define CHECK_NOT_RETURN(ret, message) \ | |
10 | + if(ret != 0) {LOG_ERROR("[{}]- {}", m_dec_name, message);} | |
11 | +#define CHECK_AND_RETURN_NOVALUE(ret, message) \ | |
12 | + if(ret != 0) {LOG_ERROR("[{}]- {}", m_dec_name, message); return;} | |
13 | +#define CHECK_AND_BREAK(ret, message) \ | |
14 | + if(ret != 0) {LOG_ERROR("[{}]- {}", m_dec_name, message); break;} | |
15 | + | |
16 | + | |
17 | + | |
18 | + | |
19 | +struct Vdec_CallBack_UserData { | |
20 | + uint64_t frameId; | |
21 | + uint64_t frame_nb; | |
22 | + long startTime; | |
23 | + long sendTime; | |
24 | + DvppRtpDecoder* self; | |
25 | + | |
26 | + Vdec_CallBack_UserData() { | |
27 | + frameId = 0; | |
28 | + frame_nb = 0; | |
29 | + } | |
30 | +}; | |
31 | + | |
32 | + | |
33 | +static long get_cur_time_ms() { | |
34 | + chrono::time_point<chrono::system_clock, chrono::milliseconds> tpMicro | |
35 | + = chrono::time_point_cast<chrono::milliseconds>(chrono::system_clock::now()); | |
36 | + return tpMicro.time_since_epoch().count(); | |
37 | +} | |
38 | + | |
39 | +static void *ReportThd(void *arg) | |
40 | +{ | |
41 | + DvppRtpDecoder *self = (DvppRtpDecoder *)arg; | |
42 | + if(nullptr != self){ | |
43 | + self->doProcessReport(); | |
44 | + } | |
45 | + return (void *)0; | |
46 | +} | |
47 | + | |
48 | +static void VdecCallback(acldvppStreamDesc *input, acldvppPicDesc *output, void *pUserData) | |
49 | +{ | |
50 | + Vdec_CallBack_UserData *userData = (Vdec_CallBack_UserData *) pUserData; | |
51 | + if(nullptr != userData){ | |
52 | + DvppRtpDecoder* self = userData->self; | |
53 | + if(self != nullptr){ | |
54 | + self->doVdppVdecCallBack(input, output, userData); | |
55 | + } | |
56 | + delete userData; | |
57 | + userData = nullptr; | |
58 | + } | |
59 | +} | |
60 | + | |
61 | +static int avio_read_packet(void* opaque, uint8_t* buf, int buffsize){ | |
62 | + DvppRtpDecoder* rtpDecoder = (DvppRtpDecoder*)opaque; | |
63 | + if(rtpDecoder) { | |
64 | + return rtpDecoder->ReadBuffer(buf, buffsize); | |
65 | + } | |
66 | + | |
67 | + LOG_ERROR("rtpDecoder is null"); | |
68 | + | |
69 | + return 0; | |
70 | +} | |
71 | + | |
72 | +DvppRtpDecoder::DvppRtpDecoder(){ | |
73 | + m_read_thread = nullptr; | |
74 | + | |
75 | + fmt_ctx = nullptr; | |
76 | + m_bRunning = false; | |
77 | + | |
78 | + mVideoIndex = -1; | |
79 | + pix_fmt = AV_PIX_FMT_NONE; | |
80 | + m_dec_name = ""; | |
81 | + | |
82 | + m_bPause = false; | |
83 | + | |
84 | + m_bFinished = false; | |
85 | + m_dec_keyframe = false; | |
86 | + m_fps = 0.0; | |
87 | +} | |
88 | + | |
89 | +DvppRtpDecoder::~DvppRtpDecoder() { | |
90 | + Close(); | |
91 | + | |
92 | + LOG_DEBUG("[{}]- ~DvppRtpDecoder() in_count:{} out_count:{}", m_dec_name, m_in_count, m_out_count); | |
93 | +} | |
94 | + | |
95 | +bool DvppRtpDecoder::Init(FFDecConfig cfg) { | |
96 | + | |
97 | + m_dec_name = cfg.dec_name; | |
98 | + m_frameSkip = cfg.skip_frame; | |
99 | + | |
100 | + m_cfg = cfg; | |
101 | + | |
102 | + m_bResize = m_cfg.resize; | |
103 | + | |
104 | + decode_finished_cbk = cfg.decode_finished_cbk; | |
105 | + | |
106 | + bool bRet = init_dvpp(cfg); | |
107 | + if(!bRet){ | |
108 | + return false; | |
109 | + } | |
110 | + | |
111 | + m_bFinished = false; | |
112 | + | |
113 | + return true; | |
114 | +} | |
115 | + | |
116 | +void DvppRtpDecoder::calcOutResolution(int width, int height) { | |
117 | + if(m_bResize) { | |
118 | + float srcRatio = width / (float)height; | |
119 | + float stdRatio = 1920.0 / 1080.0f ; | |
120 | + int outWidth = 1920; | |
121 | + int outHeight = 1080; | |
122 | + if (srcRatio > stdRatio) { | |
123 | + outHeight = static_cast<int>(outWidth * (float)height / width) ; | |
124 | + if (outHeight % 2 == 1) { | |
125 | + outHeight += 1; | |
126 | + } | |
127 | + } else if (srcRatio < stdRatio) { | |
128 | + outWidth = static_cast<int>(outHeight * (float)width / height) ; | |
129 | + if (outWidth % 2 == 1) { | |
130 | + outWidth += 1; | |
131 | + } | |
132 | + } | |
133 | + | |
134 | + out_frame_width = outWidth; | |
135 | + out_frame_height = outHeight; | |
136 | + } else { | |
137 | + out_frame_width = width; | |
138 | + out_frame_height = height; | |
139 | + } | |
140 | +} | |
141 | + | |
142 | +int DvppRtpDecoder::getVdecType(int videoType, int profile) | |
143 | +{ | |
144 | + int streamFormat = H264_MAIN_LEVEL; | |
145 | + | |
146 | + // VDEC only support H265 main level,264 baseline level,main level,high level | |
147 | + if (videoType == AV_CODEC_ID_HEVC) { | |
148 | + streamFormat = H265_MAIN_LEVEL; | |
149 | + } else if (videoType == AV_CODEC_ID_H264) { | |
150 | + switch (profile) { | |
151 | + case FF_PROFILE_H264_BASELINE: | |
152 | + streamFormat = H264_BASELINE_LEVEL; | |
153 | + break; | |
154 | + case FF_PROFILE_H264_MAIN: | |
155 | + streamFormat = H264_MAIN_LEVEL; | |
156 | + break; | |
157 | + case FF_PROFILE_H264_HIGH: | |
158 | + case FF_PROFILE_H264_HIGH_10: | |
159 | + case FF_PROFILE_H264_HIGH_10_INTRA: | |
160 | + case FF_PROFILE_H264_MULTIVIEW_HIGH: | |
161 | + case FF_PROFILE_H264_HIGH_422: | |
162 | + case FF_PROFILE_H264_HIGH_422_INTRA: | |
163 | + case FF_PROFILE_H264_STEREO_HIGH: | |
164 | + case FF_PROFILE_H264_HIGH_444: | |
165 | + case FF_PROFILE_H264_HIGH_444_PREDICTIVE: | |
166 | + case FF_PROFILE_H264_HIGH_444_INTRA: | |
167 | + streamFormat = H264_HIGH_LEVEL; | |
168 | + break; | |
169 | + default: | |
170 | + LOG_INFO("Not support h264 profile {}, use as mp", profile); | |
171 | + streamFormat = H264_MAIN_LEVEL; | |
172 | + break; | |
173 | + } | |
174 | + } else { | |
175 | + streamFormat = -1; | |
176 | + LOG_ERROR("Not support stream, type {}, profile {}", videoType, profile); | |
177 | + } | |
178 | + | |
179 | + return streamFormat; | |
180 | +} | |
181 | + | |
182 | + bool DvppRtpDecoder::init_dvpp(FFDecConfig cfg) { | |
183 | + | |
184 | + LOG_INFO("[{}]- Init device start...", m_dec_name); | |
185 | + | |
186 | + m_dvpp_deviceId = atoi(cfg.gpuid.c_str()); | |
187 | + | |
188 | + post_decoded_cbk = cfg.post_decoded_cbk; | |
189 | + | |
190 | + do{ | |
191 | + aclError ret = aclrtSetDevice(m_dvpp_deviceId); | |
192 | + if(ret != ACL_ERROR_NONE){ | |
193 | + LOG_ERROR("[{}]-aclrtSetDevice failed !", m_dec_name); | |
194 | + break; | |
195 | + } | |
196 | + | |
197 | + ret = aclrtCreateContext(&m_context, m_dvpp_deviceId); | |
198 | + if (ret != ACL_ERROR_NONE) { | |
199 | + LOG_ERROR("[{}]-aclrtCreateContext failed !", m_dec_name); | |
200 | + break; | |
201 | + } | |
202 | + | |
203 | + // DvppSourceManager 创建时包含 aclInit,析构时包含 aclFinalize | |
204 | + DvppSourceManager* pSrcMgr = DvppSourceManager::getInstance(); | |
205 | + m_dvpp_channel = pSrcMgr->getChannel(m_dvpp_deviceId); | |
206 | + if(m_dvpp_channel < 0){ | |
207 | + LOG_ERROR("[{}]-该设备channel已经用完了!", m_dec_name); | |
208 | + break; | |
209 | + } | |
210 | + | |
211 | + m_vpcUtils.init(m_dvpp_deviceId); | |
212 | + | |
213 | + LOG_INFO("[{}]- init vdpp success! device:{} channel:{}", m_dec_name, m_dvpp_deviceId, m_dvpp_channel); | |
214 | + return true; | |
215 | + }while(0); | |
216 | + | |
217 | + release_dvpp(); | |
218 | + | |
219 | + return false; | |
220 | +} | |
221 | + | |
222 | +bool DvppRtpDecoder::isSurport(FFDecConfig& cfg){ | |
223 | + return true; | |
224 | +} | |
225 | + | |
226 | +bool DvppRtpDecoder::start(){ | |
227 | + | |
228 | + if(!probe()) { | |
229 | + return false; | |
230 | + } | |
231 | + | |
232 | + m_bRunning = true; | |
233 | + | |
234 | + m_read_thread = new std::thread([](void* arg) | |
235 | + { | |
236 | + DvppRtpDecoder* a=(DvppRtpDecoder*)arg; | |
237 | + a->read_thread(); | |
238 | + return (void*)0; | |
239 | + }, this); | |
240 | + | |
241 | + return true; | |
242 | +} | |
243 | + | |
244 | +void DvppRtpDecoder::Close(){ | |
245 | + m_bRunning=false; | |
246 | + | |
247 | + if(m_read_thread != nullptr){ | |
248 | + m_read_thread->join(); | |
249 | + delete m_read_thread; | |
250 | + m_read_thread = nullptr; | |
251 | + } | |
252 | + | |
253 | + m_recoderManager.close(); | |
254 | + | |
255 | + release_ffmpeg(); | |
256 | + release_dvpp(); | |
257 | +} | |
258 | + | |
259 | +void DvppRtpDecoder::setPostDecArg(const void* postDecArg){ | |
260 | + m_postDecArg = postDecArg; | |
261 | +} | |
262 | + | |
263 | +void DvppRtpDecoder::setFinishedDecArg(const void* finishedDecArg){ | |
264 | + m_finishedDecArg = finishedDecArg; | |
265 | +} | |
266 | + | |
267 | +void DvppRtpDecoder::pause(){ | |
268 | + m_bPause = true; | |
269 | +} | |
270 | + | |
271 | +void DvppRtpDecoder::resume(){ | |
272 | + m_bPause = false; | |
273 | +} | |
274 | + | |
275 | +void DvppRtpDecoder::setDecKeyframe(bool bKeyframe){ | |
276 | + m_dec_keyframe = bKeyframe; | |
277 | +} | |
278 | + | |
279 | +bool DvppRtpDecoder::isRunning(){ | |
280 | + return m_bRunning; | |
281 | +} | |
282 | + | |
283 | +bool DvppRtpDecoder::isFinished(){ | |
284 | + return m_bFinished; | |
285 | +} | |
286 | + | |
287 | +bool DvppRtpDecoder::isPausing(){ | |
288 | + return m_bPause; | |
289 | +} | |
290 | + | |
291 | +bool DvppRtpDecoder::getResolution(int &width, int &height){ | |
292 | + width = frame_width; | |
293 | + height = frame_height; | |
294 | + return true; | |
295 | +} | |
296 | + | |
297 | +bool DvppRtpDecoder::getOutResolution( int &width, int &height ) { | |
298 | + width = out_frame_width; | |
299 | + height = out_frame_height; | |
300 | + return true; | |
301 | +} | |
302 | + | |
303 | +float DvppRtpDecoder::fps(){ | |
304 | + return m_fps; | |
305 | +} | |
306 | + | |
307 | +static int snap_count = 0; | |
308 | + | |
309 | +DeviceMemory* DvppRtpDecoder::snapshot(){ | |
310 | + | |
311 | + int ret = aclrtSetCurrentContext(m_context); | |
312 | + if(ret != ACL_ERROR_NONE){ | |
313 | + LOG_ERROR("[{}]- aclrtSetCurrentContext failed", m_dec_name); | |
314 | + return nullptr; | |
315 | + } | |
316 | + | |
317 | + // 注意有锁 | |
318 | + DeviceMemory* snapshot_mem = nullptr; | |
319 | + int loop_times = 0; | |
320 | + while(m_bRunning) { | |
321 | + m_decoded_data_queue_mtx.lock(); | |
322 | + if(m_decoded_data_queue.size() <= 0) { | |
323 | + m_decoded_data_queue_mtx.unlock(); | |
324 | + loop_times++; | |
325 | + if(loop_times > 100) { | |
326 | + // 1s都没截取到图,退出 | |
327 | + break; | |
328 | + } | |
329 | + std::this_thread::sleep_for(std::chrono::milliseconds(10)); | |
330 | + continue; | |
331 | + } | |
332 | + | |
333 | + DvppDataMemory* mem = m_decoded_data_queue.front(); | |
334 | + snapshot_mem = new DvppDataMemory(mem); | |
335 | + m_decoded_data_queue_mtx.unlock(); | |
336 | + | |
337 | + // snap_count++; | |
338 | + // LOG_INFO("[{}]- snap_count:{} ", m_dec_name, snap_count); | |
339 | + break; | |
340 | + } | |
341 | + | |
342 | + return snapshot_mem; | |
343 | +} | |
344 | + | |
345 | +void DvppRtpDecoder::release_ffmpeg() { | |
346 | + m_dec_keyframe = false; | |
347 | + if(h264bsfc){ | |
348 | + av_bsf_free(&h264bsfc); | |
349 | + h264bsfc = nullptr; | |
350 | + } | |
351 | + if(avctx){ | |
352 | + avcodec_free_context(&avctx); | |
353 | + avctx = nullptr; | |
354 | + } | |
355 | + if (fmt_ctx){ | |
356 | + avformat_close_input(&fmt_ctx); | |
357 | + fmt_ctx = nullptr; | |
358 | + } | |
359 | + | |
360 | + LOG_DEBUG("[{}]- release_ffmpeg", m_dec_name); | |
361 | +} | |
362 | + | |
363 | +void DvppRtpDecoder::CacheBuffer(uint8_t* recvBuf, int recvBufSize) { | |
364 | + if ((m_bufferSize + recvBufSize - RTP_HEADER_SIZE) < MAX_RTP_BUFFER_SIZE) { | |
365 | + memcpy(m_buffer + m_bufferSize, recvBuf + RTP_HEADER_SIZE, recvBufSize - RTP_HEADER_SIZE); | |
366 | + m_bufferSize += recvBufSize - RTP_HEADER_SIZE; | |
367 | + } else { | |
368 | + LOG_WARN("recvBufSize = {} over MAX_RTP_BUFFER_SIZE ", recvBufSize); | |
369 | + } | |
370 | +} | |
371 | + | |
372 | +int DvppRtpDecoder::ReadBuffer(uint8_t* buf, int buffsize) { | |
373 | + int ret = 0; | |
374 | + if (m_bufferSize >= buffsize) { | |
375 | + memcpy(buf, m_buffer, buffsize); | |
376 | + m_bufferSize = m_bufferSize - buffsize; | |
377 | + memmove(m_buffer, m_buffer + buffsize, m_bufferSize); | |
378 | + ret = buffsize; | |
379 | + | |
380 | + LOG_DEBUG("avio_read_packet={}", buffsize); | |
381 | + } | |
382 | + | |
383 | + return ret; | |
384 | +} | |
385 | + | |
386 | +bool DvppRtpDecoder::probe() { | |
387 | + // todo: 此处可能有泄露 | |
388 | + unsigned char* avioBuff = (unsigned char*)av_malloc(7680 * 4320); | |
389 | + ioCtx = avio_alloc_context(avioBuff, sizeof(avioBuff), 0, this, avio_read_packet, NULL, NULL); | |
390 | + //探测流(获取码流格式) | |
391 | + const AVInputFormat* inputFmt; | |
392 | + int ret = av_probe_input_buffer2(ioCtx, &inputFmt, "", NULL, 0, 0); | |
393 | + if (ret < 0){ | |
394 | + LOG_ERROR("av_probe_input_buffer2 error: {}", ret); | |
395 | + return false; | |
396 | + } | |
397 | + | |
398 | + do{ | |
399 | + fmt_ctx = avformat_alloc_context(); | |
400 | + fmt_ctx->pb = ioCtx; | |
401 | + | |
402 | + | |
403 | + AVDictionary* net_options{nullptr};//网络连接参数 | |
404 | + | |
405 | + //配置流参数 | |
406 | + //av_dict_set(&net_options, "fflags", "nobuffer", 0); //不缓存直接解码 | |
407 | + | |
408 | + //打开流 | |
409 | + ret = avformat_open_input(&fmt_ctx, "", inputFmt, &net_options); | |
410 | + if (ret != 0) | |
411 | + { | |
412 | + LOG_ERROR("avformat_open_input error: {}", ret); | |
413 | + break; | |
414 | + } | |
415 | + //获取流信息 | |
416 | + if (avformat_find_stream_info(fmt_ctx, NULL) < 0)//? | |
417 | + { | |
418 | + LOG_ERROR("avformat_find_stream_info error"); | |
419 | + break; | |
420 | + } | |
421 | + //获取视频流 | |
422 | + mVideoIndex = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0); | |
423 | + if (mVideoIndex < 0) | |
424 | + { | |
425 | + LOG_ERROR("av_find_best_stream error"); | |
426 | + break; | |
427 | + } | |
428 | + //获取解码信息 | |
429 | + AVStream* stream = fmt_ctx->streams[mVideoIndex]; | |
430 | + AVCodecParameters *codecpar = stream->codecpar; | |
431 | + const AVCodec* videoCodec = avcodec_find_decoder(codecpar->codec_id); | |
432 | + if (!videoCodec){ | |
433 | + LOG_ERROR("avcodec_find_decoder error"); | |
434 | + break; | |
435 | + } | |
436 | + avctx = avcodec_alloc_context3(videoCodec); | |
437 | + | |
438 | + //codecpar为解码器上下文赋值 | |
439 | + if (avcodec_parameters_to_context(avctx, codecpar) != 0) | |
440 | + { | |
441 | + LOG_ERROR("avcodec_parameters_to_context error"); | |
442 | + break; | |
443 | + } | |
444 | + | |
445 | + int enType = getVdecType(codecpar->codec_id, codecpar->profile); | |
446 | + if(-1 == enType) { | |
447 | + break; | |
448 | + } | |
449 | + m_enType = static_cast<acldvppStreamFormat>(enType); | |
450 | + | |
451 | + const AVBitStreamFilter * filter = nullptr; | |
452 | + if(codecpar->codec_id == AV_CODEC_ID_H264){ | |
453 | + filter = av_bsf_get_by_name("h264_mp4toannexb"); | |
454 | + }else if(codecpar->codec_id == AV_CODEC_ID_HEVC){ | |
455 | + filter = av_bsf_get_by_name("hevc_mp4toannexb"); | |
456 | + }else { | |
457 | + LOG_ERROR("[{}]- codec_id is not supported!", m_dec_name); | |
458 | + break; | |
459 | + } | |
460 | + | |
461 | + ret = av_bsf_alloc(filter, &h264bsfc); | |
462 | + if (ret < 0){ | |
463 | + break; | |
464 | + } | |
465 | + | |
466 | + avcodec_parameters_copy(h264bsfc->par_in, codecpar); | |
467 | + av_bsf_init(h264bsfc); | |
468 | + | |
469 | + frame_width = codecpar->width; | |
470 | + frame_height = codecpar->height; | |
471 | + pix_fmt = (AVPixelFormat)codecpar->format; | |
472 | + | |
473 | + calcOutResolution(frame_width, frame_height); | |
474 | + | |
475 | + if (stream->avg_frame_rate.den) { | |
476 | + m_fps = av_q2d(stream ->avg_frame_rate); | |
477 | + } else { | |
478 | + m_fps = 0.0; | |
479 | + } | |
480 | + | |
481 | + m_vdec_out_size = frame_width * frame_height * 3 / 2; | |
482 | + | |
483 | + if (avctx->gop_size > 0) { | |
484 | + m_cache_gop = avctx->gop_size + 1; | |
485 | + } else { | |
486 | + m_cache_gop = 20; | |
487 | + } | |
488 | + | |
489 | + #ifdef USE_VILLAGE | |
490 | + bool bRet = m_recoderManager.init(frame_width, frame_height, m_fps, avctx->bit_rate); | |
491 | + if (!bRet){ | |
492 | + LOG_ERROR("[{}]- m_recoderManager 初始化失败!", m_dec_name); | |
493 | + } | |
494 | + #endif | |
495 | + | |
496 | + LOG_INFO("[{}]- init ffmpeg success! src:({}, {}) out:({}, {}) fps:{} ", m_dec_name, frame_width, frame_height, out_frame_width, out_frame_height, m_fps); | |
497 | + | |
498 | + return true; | |
499 | + } while(0); | |
500 | + | |
501 | + release_ffmpeg(); | |
502 | + | |
503 | + return false; | |
504 | +} | |
505 | + | |
506 | +void DvppRtpDecoder::read_thread() { | |
507 | + | |
508 | + int ret = -1; | |
509 | + | |
510 | + m_bExitReportThd = false; | |
511 | + pthread_t report_thread; | |
512 | + ret = pthread_create(&report_thread, nullptr, ReportThd, (void *)this); | |
513 | + if(ret != 0){ | |
514 | + LOG_ERROR("[{}]- pthread_create failed", m_dec_name); | |
515 | + return; | |
516 | + } | |
517 | + | |
518 | + aclrtContext ctx = nullptr; | |
519 | + aclvdecChannelDesc *vdecChannelDesc = nullptr; | |
520 | + | |
521 | + do { | |
522 | + CHECK_AND_BREAK(aclrtSetDevice(m_dvpp_deviceId), "aclrtSetDevice failed"); | |
523 | + int ret = aclrtSetCurrentContext(m_context); | |
524 | + if(ret != ACL_ERROR_NONE){ | |
525 | + LOG_ERROR("[{}]- aclrtSetCurrentContext failed", m_dec_name); | |
526 | + break; | |
527 | + } | |
528 | + | |
529 | + vdecChannelDesc = aclvdecCreateChannelDesc(); | |
530 | + if (vdecChannelDesc == nullptr) { | |
531 | + LOG_ERROR("[{}]- aclvdecCreateChannelDesc failed", m_dec_name); | |
532 | + break; | |
533 | + } | |
534 | + | |
535 | + // 创建 channel dec结构体 | |
536 | + // 通道ID在dvpp层面为0~31 | |
537 | + CHECK_AND_BREAK(aclvdecSetChannelDescChannelId(vdecChannelDesc, m_dvpp_channel), "aclvdecSetChannelDescChannelId failed"); | |
538 | + CHECK_AND_BREAK(aclvdecSetChannelDescThreadId(vdecChannelDesc, report_thread), "aclvdecSetChannelDescThreadId failed"); | |
539 | + CHECK_AND_BREAK(aclvdecSetChannelDescCallback(vdecChannelDesc, VdecCallback), "aclvdecSetChannelDescCallback failed"); | |
540 | + CHECK_AND_BREAK(aclvdecSetChannelDescEnType(vdecChannelDesc, m_enType), "aclvdecSetChannelDescEnType failed"); | |
541 | + CHECK_AND_BREAK(aclvdecSetChannelDescOutPicFormat(vdecChannelDesc, PIXEL_FORMAT_YUV_SEMIPLANAR_420), "aclvdecSetChannelDescOutPicFormat failed"); | |
542 | + CHECK_AND_BREAK(aclvdecCreateChannel(vdecChannelDesc), "aclvdecCreateChannel failed"); | |
543 | + | |
544 | + unsigned long long frame_nb = 0; | |
545 | + while (m_bRunning){ | |
546 | + | |
547 | + AVPacket* pkt = av_packet_alloc(); | |
548 | + av_init_packet( pkt ); | |
549 | + int result = av_read_frame(fmt_ctx, pkt); | |
550 | + if (result == AVERROR_EOF || result < 0){ | |
551 | + av_packet_free(&pkt); | |
552 | + pkt = nullptr; | |
553 | + LOG_WARN("[{}]- Failed to read frame!", m_dec_name); | |
554 | + break; | |
555 | + } | |
556 | + | |
557 | + if (m_DvppCacheCounter.load() > m_cache_gop){ | |
558 | + // 解码器解码不过来。实时流在此处的处理会导致花屏,这是由于解码器性能问题导致,无法避免 | |
559 | + // 实时流在这里处理是为了避免长时间不读取数据导致数据中断 | |
560 | + std::this_thread::sleep_for(std::chrono::milliseconds(10)); | |
561 | + continue; | |
562 | + } | |
563 | + | |
564 | + if (m_dec_keyframe && !(pkt->flags & AV_PKT_FLAG_KEY)) { | |
565 | + av_packet_free(&pkt); | |
566 | + pkt = nullptr; | |
567 | + continue; | |
568 | + } | |
569 | + | |
570 | + if (mVideoIndex == pkt->stream_index){ | |
571 | + | |
572 | + ret = av_bsf_send_packet(h264bsfc, pkt); | |
573 | + if(ret < 0) { | |
574 | + LOG_ERROR("[{}]- av_bsf_send_packet error!", m_dec_name); | |
575 | + av_packet_free(&pkt); | |
576 | + pkt = nullptr; | |
577 | + continue; | |
578 | + } | |
579 | + | |
580 | + frame_nb++; | |
581 | + int nSended = -1; | |
582 | + while ((ret = av_bsf_receive_packet(h264bsfc, pkt)) == 0) { | |
583 | + if(!m_bRunning){ | |
584 | + break; | |
585 | + } | |
586 | + nSended = sendPkt(vdecChannelDesc, pkt, frame_nb); | |
587 | + } | |
588 | + | |
589 | + if(nSended < 0) { | |
590 | + // 执行出错,强行结束整个任务 | |
591 | + m_bRunning=false; | |
592 | + break; | |
593 | + } | |
594 | + | |
595 | + #ifdef USE_VILLAGE | |
596 | + m_recoderManager.cache_pkt(pkt, frame_nb, m_dec_name); | |
597 | + #endif | |
598 | + } else { | |
599 | + av_packet_free(&pkt); | |
600 | + pkt = nullptr; | |
601 | + } | |
602 | + } | |
603 | + | |
604 | + if (vdecChannelDesc) { | |
605 | + sendVdecEos(vdecChannelDesc); | |
606 | + } | |
607 | + | |
608 | + while(m_bRunning && m_decoded_data_queue.size() > 0) { | |
609 | + std::this_thread::sleep_for(std::chrono::milliseconds(5)); | |
610 | + } | |
611 | + | |
612 | + } while (0); | |
613 | + | |
614 | + if (vdecChannelDesc) { | |
615 | + CHECK_NOT_RETURN(aclvdecDestroyChannel(vdecChannelDesc), "aclvdecDestroyChannel failed"); | |
616 | + CHECK_NOT_RETURN(aclvdecDestroyChannelDesc(vdecChannelDesc), "aclvdecDestroyChannelDesc failed"); | |
617 | + vdecChannelDesc = nullptr; | |
618 | + } | |
619 | + | |
620 | + m_bRunning=false; | |
621 | + | |
622 | + m_bExitReportThd = true; | |
623 | + CHECK_NOT_RETURN(pthread_join(report_thread, nullptr), "report_thread join failed"); | |
624 | + | |
625 | + m_bFinished = true; | |
626 | + | |
627 | + LOG_INFO("[{}]- read thread exit.", m_dec_name); | |
628 | + | |
629 | + if(decode_finished_cbk) { | |
630 | + decode_finished_cbk(m_finishedDecArg); | |
631 | + } | |
632 | +} | |
633 | + | |
634 | +int DvppRtpDecoder::sendPkt(aclvdecChannelDesc *vdecChannelDesc, AVPacket* pkt, unsigned long long frame_nb){ | |
635 | + | |
636 | + void *vdecInputbuf = nullptr; | |
637 | + void *vdecOutputBuf = nullptr; | |
638 | + acldvppStreamDesc *input_stream_desc = nullptr; | |
639 | + acldvppPicDesc *output_pic_desc = nullptr; | |
640 | + do{ | |
641 | + int ret = acldvppMalloc((void **)&vdecInputbuf, pkt->size); | |
642 | + if(ACL_ERROR_NONE != ret){ | |
643 | + LOG_ERROR("[{}]- acldvppMalloc failed!, ret:{}", m_dec_name, ret); | |
644 | + break; | |
645 | + } | |
646 | + | |
647 | + ret = aclrtMemcpy(vdecInputbuf, pkt->size, pkt->data, pkt->size, ACL_MEMCPY_HOST_TO_DEVICE); | |
648 | + if(ACL_ERROR_NONE != ret){ | |
649 | + LOG_ERROR("[{}]- aclrtMemcpy failed", m_dec_name); | |
650 | + break; | |
651 | + } | |
652 | + | |
653 | + ret = acldvppMalloc((void **)&vdecOutputBuf, m_vdec_out_size); | |
654 | + if(ret != ACL_ERROR_NONE){ | |
655 | + LOG_ERROR("[{}]- acldvppMalloc failed", m_dec_name); | |
656 | + break; | |
657 | + } | |
658 | + | |
659 | + input_stream_desc = acldvppCreateStreamDesc(); | |
660 | + if (input_stream_desc == nullptr) { | |
661 | + LOG_ERROR("[{}]- acldvppCreateStreamDesc failed", m_dec_name); | |
662 | + break; | |
663 | + } | |
664 | + output_pic_desc = acldvppCreatePicDesc(); | |
665 | + if (output_pic_desc == nullptr) { | |
666 | + LOG_ERROR("[{}]- acldvppCreatePicDesc failed", m_dec_name); | |
667 | + break; | |
668 | + } | |
669 | + CHECK_AND_BREAK(acldvppSetStreamDescData(input_stream_desc, vdecInputbuf), "acldvppSetStreamDescData failed"); | |
670 | + CHECK_AND_BREAK(acldvppSetStreamDescSize(input_stream_desc, pkt->size), "acldvppSetStreamDescSize failed"); | |
671 | + CHECK_AND_BREAK(acldvppSetPicDescData(output_pic_desc, vdecOutputBuf), "acldvppSetPicDescData failed"); | |
672 | + CHECK_AND_BREAK(acldvppSetPicDescSize(output_pic_desc, m_vdec_out_size), "acldvppSetPicDescSize failed"); | |
673 | + | |
674 | + Vdec_CallBack_UserData *user_data = NULL; | |
675 | + user_data = new Vdec_CallBack_UserData; | |
676 | + user_data->frameId = frame_nb; | |
677 | + user_data->frame_nb = frame_nb; | |
678 | + // user_data->startTime = startTime; | |
679 | + user_data->sendTime = UtilTools::get_cur_time_ms(); | |
680 | + user_data->self = this; | |
681 | + | |
682 | + m_in_count++; | |
683 | + | |
684 | + // 内部缓存计数加1 | |
685 | + m_DvppCacheCounter++; | |
686 | + ret = aclvdecSendFrame(vdecChannelDesc, input_stream_desc, output_pic_desc, nullptr, reinterpret_cast<void *>(user_data)); | |
687 | + if(ret != ACL_ERROR_NONE){ | |
688 | + LOG_ERROR("[{}]- aclvdecSendFrame failed", m_dec_name); | |
689 | + delete user_data; | |
690 | + user_data = nullptr; | |
691 | + return -2; | |
692 | + } | |
693 | + | |
694 | + return 0; | |
695 | + }while (0); | |
696 | + | |
697 | + if (vdecInputbuf){ | |
698 | + acldvppFree(vdecInputbuf); | |
699 | + vdecInputbuf = nullptr; | |
700 | + } | |
701 | + | |
702 | + // 报错情形 | |
703 | + if(input_stream_desc){ | |
704 | + CHECK_NOT_RETURN(acldvppDestroyStreamDesc(input_stream_desc), "acldvppDestroyStreamDesc failed"); | |
705 | + } | |
706 | + | |
707 | + if (vdecOutputBuf){ | |
708 | + acldvppFree(vdecOutputBuf); | |
709 | + vdecOutputBuf = nullptr; | |
710 | + } | |
711 | + | |
712 | + if(output_pic_desc){ | |
713 | + CHECK_NOT_RETURN(acldvppDestroyPicDesc(output_pic_desc), "acldvppDestroyPicDesc failed"); | |
714 | + } | |
715 | + | |
716 | + return -1; | |
717 | +} | |
718 | + | |
719 | +void DvppRtpDecoder::doProcessReport(){ | |
720 | + | |
721 | + aclError ret = aclrtSetDevice(m_dvpp_deviceId); | |
722 | + if(ret != ACL_ERROR_NONE){ | |
723 | + // cout << "aclrtSetDevice failed" << endl; | |
724 | + LOG_ERROR("aclrtSetDevice failed !"); | |
725 | + return ; | |
726 | + } | |
727 | + | |
728 | + aclrtContext ctx; | |
729 | + ret = aclrtCreateContext(&ctx, m_dvpp_deviceId); | |
730 | + if (ret != ACL_ERROR_NONE) { | |
731 | + // cout << "aclrtCreateContext failed " << endl; | |
732 | + LOG_ERROR("aclrtCreateContext failed !"); | |
733 | + return ; | |
734 | + } | |
735 | + | |
736 | + while (!m_bExitReportThd) { | |
737 | + aclrtProcessReport(1000); | |
738 | + } | |
739 | + | |
740 | + ret = aclrtDestroyContext(ctx); | |
741 | + if(ret != ACL_ERROR_NONE){ | |
742 | + LOG_ERROR("aclrtDestroyContext failed !"); | |
743 | + } | |
744 | + LOG_INFO("doProcessReport exit."); | |
745 | +} | |
746 | + | |
747 | +void DvppRtpDecoder::doVdppVdecCallBack(acldvppStreamDesc *input, acldvppPicDesc *output, void *pUserData){ | |
748 | + | |
749 | + // 内部缓存计数减1 | |
750 | + m_DvppCacheCounter--; | |
751 | + | |
752 | + if(nullptr == pUserData){ | |
753 | + return; | |
754 | + } | |
755 | + | |
756 | + Vdec_CallBack_UserData *userData = (Vdec_CallBack_UserData *) pUserData; | |
757 | + uint64_t frame_nb = userData->frame_nb; | |
758 | + | |
759 | + m_out_count++; | |
760 | + | |
761 | + CHECK_AND_RETURN_NOVALUE(aclrtSetCurrentContext(m_context), "aclrtSetCurrentContext failed"); | |
762 | + | |
763 | + void *inputDataDev = acldvppGetStreamDescData(input); | |
764 | + acldvppFree(inputDataDev); | |
765 | + inputDataDev = nullptr; | |
766 | + | |
767 | + void *outputDataDev = acldvppGetPicDescData(output); | |
768 | + uint32_t outputSize = acldvppGetPicDescSize(output); | |
769 | + uint32_t width = acldvppGetPicDescWidth(output); | |
770 | + uint32_t width_stride = acldvppGetPicDescWidthStride(output); | |
771 | + uint32_t height = acldvppGetPicDescHeight(output); | |
772 | + uint32_t height_stride = acldvppGetPicDescHeightStride(output); | |
773 | + | |
774 | + do{ | |
775 | + int ret = acldvppGetPicDescRetCode(output); | |
776 | + if(ret != ACL_ERROR_NONE){ | |
777 | + LOG_ERROR("[{}]- decode result error, retCode:{} ", m_dec_name, ret); | |
778 | + acldvppFree(outputDataDev); | |
779 | + outputDataDev = nullptr; | |
780 | + break; | |
781 | + } | |
782 | + | |
783 | + bool bCached = false; | |
784 | + if(width > 0 && height > 0 && outputSize > 0){ | |
785 | + | |
786 | + // cout << m_dec_name << " 解码时间间隔: " << get_cur_time_ms() - last_ts << endl; | |
787 | + // last_ts = get_cur_time_ms(); | |
788 | + | |
789 | + // 换成解码后数据, 这里这样做的是为了保证解码一直持续进行,避免后续操作阻碍文件读取和解码从而导致花屏 | |
790 | + DvppDataMemory* mem = nullptr; | |
791 | + if (m_bResize && (width > 1920 || height > 1080)) { | |
792 | + | |
793 | + mem = m_vpcUtils.resize(output, out_frame_width, out_frame_height); | |
794 | + if (mem) { | |
795 | + acldvppFree(outputDataDev); | |
796 | + outputDataDev = nullptr; | |
797 | + | |
798 | + mem->setDeviceId(to_string(m_dvpp_deviceId)); | |
799 | + mem->setId(m_dec_name); | |
800 | + mem->setFrameNb(frame_nb); | |
801 | + } | |
802 | + } else { | |
803 | + mem = new DvppDataMemory(width, width_stride, height, height_stride, outputSize, m_dec_name, to_string(m_dvpp_deviceId), false, frame_nb, (unsigned char *)outputDataDev); | |
804 | + } | |
805 | + | |
806 | + if(mem){ | |
807 | + m_decoded_data_queue_mtx.lock(); | |
808 | + m_decoded_data_queue.push(mem); | |
809 | + m_decoded_data_queue_mtx.unlock(); | |
810 | + bCached = true; | |
811 | + } | |
812 | + } | |
813 | + | |
814 | + if(!bCached) { | |
815 | + LOG_WARN("[{}]- decode result warning, width:{} width_stride:{} height:{} height_stride:{} size:{}", m_dec_name, width, width_stride, height, height_stride, outputSize); | |
816 | + acldvppFree(outputDataDev); | |
817 | + outputDataDev = nullptr; | |
818 | + } | |
819 | + }while(0); | |
820 | + | |
821 | + CHECK_AND_RETURN_NOVALUE(acldvppDestroyStreamDesc(input), "acldvppDestroyStreamDesc failed"); | |
822 | + CHECK_AND_RETURN_NOVALUE(acldvppDestroyPicDesc(output), "acldvppDestroyPicDesc failed"); | |
823 | +} | |
824 | + | |
825 | +bool DvppRtpDecoder::sendVdecEos(aclvdecChannelDesc *vdecChannelDesc) { | |
826 | + // create stream desc | |
827 | + acldvppStreamDesc *streamInputDesc = acldvppCreateStreamDesc(); | |
828 | + if (streamInputDesc == nullptr) { | |
829 | + LOG_ERROR("[{}]- fail to create input stream desc", m_dec_name); | |
830 | + return false; | |
831 | + } | |
832 | + aclError ret = acldvppSetStreamDescEos(streamInputDesc, 1); | |
833 | + if (ret != ACL_SUCCESS) { | |
834 | + LOG_ERROR("[{}]- fail to set eos for stream desc, errorCode = {}", m_dec_name, static_cast<int32_t>(ret)); | |
835 | + (void)acldvppDestroyStreamDesc(streamInputDesc); | |
836 | + return false; | |
837 | + } | |
838 | + | |
839 | + // send vdec eos frame. when all vdec callback are completed, aclvdecSendFrame can be returned. | |
840 | + LOG_INFO("[{}]- send eos", m_dec_name); | |
841 | + ret = aclvdecSendFrame(vdecChannelDesc, streamInputDesc, nullptr, nullptr, nullptr); | |
842 | + (void)acldvppDestroyStreamDesc(streamInputDesc); | |
843 | + if (ret != ACL_SUCCESS) { | |
844 | + LOG_ERROR("[{}]- fail to send eos frame, ret={}", m_dec_name, ret); | |
845 | + return false; | |
846 | + } | |
847 | + | |
848 | + return true; | |
849 | +} | |
850 | + | |
851 | +DvppDataMemory* DvppRtpDecoder::GetFrame() { | |
852 | + DvppDataMemory* mem = nullptr; | |
853 | + m_decoded_data_queue_mtx.lock(); | |
854 | + if (m_decoded_data_queue.size() > 0) { | |
855 | + mem = m_decoded_data_queue.front(); | |
856 | + m_decoded_data_queue.pop(); | |
857 | + } | |
858 | + m_decoded_data_queue_mtx.unlock(); | |
859 | + | |
860 | + return mem; | |
861 | +} | |
862 | + | |
863 | +void DvppRtpDecoder::release_dvpp(){ | |
864 | + if(m_context){ | |
865 | + aclError ret = aclrtDestroyContext(m_context); | |
866 | + if(ret != ACL_ERROR_NONE){ | |
867 | + LOG_ERROR("[{}]- aclrtDestroyContext failed !", m_dec_name); | |
868 | + } | |
869 | + m_context = nullptr; | |
870 | + } | |
871 | + | |
872 | + if(m_dvpp_channel >= 0){ | |
873 | + DvppSourceManager* pSrcMgr = DvppSourceManager::getInstance(); | |
874 | + pSrcMgr->releaseChannel(m_dvpp_deviceId, m_dvpp_channel); | |
875 | + m_dvpp_channel = -1; | |
876 | + } | |
877 | +} | |
878 | + | |
879 | +void DvppRtpDecoder::doRecode(RecoderInfo& recoderInfo) { | |
880 | + m_recoderManager.create_recode_task(recoderInfo); | |
881 | +} | |
882 | + | |
883 | +void DvppRtpDecoder::set_mq_callback(mq_callback_t cb) { | |
884 | + m_recoderManager.set_mq_callback(cb); | |
885 | +} | |
0 | 886 | \ No newline at end of file | ... | ... |
src/decoder/dvpp/DvppRtpDecoder.h
0 → 100644
1 | +#ifndef __DVPP_RTP_DECODER_H__ | |
2 | +#define __DVPP_RTP_DECODER_H__ | |
3 | + | |
4 | +#include <stdint.h> | |
5 | +#include <atomic> | |
6 | +#include <thread> | |
7 | +#include <queue> | |
8 | +#include <mutex> | |
9 | +#include <chrono> | |
10 | +#include<string> | |
11 | + | |
12 | +#include "depend_headers.h" | |
13 | +#include "dvpp_headers.h" | |
14 | +#include "DvppDataMemory.hpp" | |
15 | + | |
16 | +#include "FFRecoderTaskManager.h" | |
17 | + | |
18 | +#include "VpcUtils.h" | |
19 | + | |
20 | +using namespace std; | |
21 | + | |
22 | +#define MAX_RTP_BUFFER_SIZE 4194304 // 4M = 4 * 1024 * 1024 = 4194304 字节 | |
23 | + | |
24 | +class DvppRtpDecoder | |
25 | +{ | |
26 | +public: | |
27 | + DvppRtpDecoder(); | |
28 | + ~DvppRtpDecoder(); | |
29 | + | |
30 | +public: | |
31 | + std::atomic<char> m_buffer[MAX_RTP_BUFFER_SIZE]; | |
32 | + std::atomic_int m_bufferSize {0}; | |
33 | + | |
34 | +public: | |
35 | + bool Init(FFDecConfig cfg); | |
36 | + void Close(); | |
37 | + bool start(); | |
38 | + void pause(); | |
39 | + void resume(); | |
40 | + | |
41 | + void setDecKeyframe(bool bKeyframe); | |
42 | + | |
43 | + bool isRunning(); | |
44 | + bool isFinished(); | |
45 | + bool isPausing(); | |
46 | + bool getResolution( int &width, int &height ); | |
47 | + bool getOutResolution( int &width, int &height ); | |
48 | + | |
49 | + bool isSurport(FFDecConfig& cfg); | |
50 | + | |
51 | + float fps(); | |
52 | + | |
53 | + void setName(string nm){ | |
54 | + m_dec_name = nm; | |
55 | + } | |
56 | + | |
57 | + string getName(){ | |
58 | + return m_dec_name; | |
59 | + } | |
60 | + | |
61 | + DeviceMemory* snapshot(); | |
62 | + | |
63 | + void setPostDecArg(const void* postDecArg); | |
64 | + void setFinishedDecArg(const void* finishedDecArg); | |
65 | + | |
66 | + DvppDataMemory* GetFrame(); | |
67 | + | |
68 | + void doRecode(RecoderInfo& recoderInfo); | |
69 | + | |
70 | + void set_mq_callback(mq_callback_t cb); | |
71 | + | |
72 | + void CacheBuffer(uint8_t* buf, int buf_size); | |
73 | + | |
74 | + int ReadBuffer(uint8_t* buf, int buffsize); | |
75 | + | |
76 | +public: | |
77 | + void doVdppVdecCallBack(acldvppStreamDesc *input, acldvppPicDesc *output, void *pUserData); | |
78 | + void doProcessReport(); | |
79 | + | |
80 | +private: | |
81 | + bool init_dvpp(FFDecConfig cfg); | |
82 | + void release_ffmpeg(); | |
83 | + void read_thread(); | |
84 | + bool probe();//阻塞式探测国标流并获取解码参数 | |
85 | + | |
86 | + int sendPkt(aclvdecChannelDesc *vdecChannelDesc, AVPacket* pkt, unsigned long long frame_nb); | |
87 | + bool sendVdecEos(aclvdecChannelDesc *vdecChannelDesc); | |
88 | + void release_dvpp(); | |
89 | + | |
90 | + int getVdecType(int videoType, int profile); | |
91 | + | |
92 | + void calcOutResolution(int w, int h); | |
93 | + | |
94 | +private: | |
95 | + FFDecConfig m_cfg; | |
96 | + string m_dec_name; | |
97 | + | |
98 | + const void * m_finishedDecArg {nullptr}; | |
99 | + DECODE_FINISHED_CALLBACK decode_finished_cbk {nullptr}; | |
100 | + | |
101 | + bool m_bFinished{false}; | |
102 | + bool m_bRunning{false}; | |
103 | + bool m_bPause{false}; | |
104 | + | |
105 | + bool m_bExitReportThd{false}; | |
106 | + | |
107 | + // 读取数据 | |
108 | + AVFormatContext *fmt_ctx{nullptr}; | |
109 | + AVIOContext * ioCtx{nullptr}; | |
110 | + int mVideoIndex {-1}; | |
111 | + AVPixelFormat pix_fmt; | |
112 | + AVCodecContext *avctx{nullptr}; | |
113 | + AVBSFContext * h264bsfc{nullptr}; | |
114 | + | |
115 | + int frame_width{0}; | |
116 | + int frame_height{0}; | |
117 | + int out_frame_width{0}; | |
118 | + int out_frame_height{0}; | |
119 | + float m_fps{0.0}; | |
120 | + | |
121 | + std::thread* m_read_thread{nullptr}; | |
122 | + | |
123 | + bool m_dec_keyframe {false}; | |
124 | + bool m_bResize {false}; | |
125 | + | |
126 | + // 解码 | |
127 | + int m_dvpp_deviceId {-1}; | |
128 | + int m_dvpp_channel {-1}; | |
129 | + aclrtContext m_context{nullptr}; | |
130 | + acldvppStreamFormat m_enType; | |
131 | + | |
132 | + const void * m_postDecArg {nullptr}; | |
133 | + POST_DECODE_CALLBACK post_decoded_cbk {nullptr}; | |
134 | + | |
135 | + int m_vdec_out_size {-1}; | |
136 | + | |
137 | + FFRecoderTaskManager m_recoderManager; | |
138 | + | |
139 | + queue<DvppDataMemory*> m_decoded_data_queue; | |
140 | + mutex m_decoded_data_queue_mtx; | |
141 | + | |
142 | + long long last_ts {0}; | |
143 | + | |
144 | + long long m_last_read_ts {0}; | |
145 | + | |
146 | + uint64_t m_in_count {0}; | |
147 | + uint64_t m_out_count {0}; | |
148 | + | |
149 | + int m_frameSkip {1}; | |
150 | + | |
151 | + std::atomic<int> m_DvppCacheCounter{0}; | |
152 | + int m_cache_gop{0}; | |
153 | + | |
154 | + VpcUtils m_vpcUtils; | |
155 | + | |
156 | +}; | |
157 | +#endif //__DVPP_RTP_DECODER_H__ | |
0 | 158 | \ No newline at end of file | ... | ... |
src/decoder/dvpp/DvppStreamDecoder.cpp
... | ... | @@ -668,6 +668,16 @@ void DvppStreamDecoder::Close() { |
668 | 668 | decode_finished_cbk(m_finishedDecArg); |
669 | 669 | decode_finished_cbk = nullptr; |
670 | 670 | } |
671 | + | |
672 | + DvppDataMemory* mem = nullptr; | |
673 | + m_decoded_data_queue_mtx.lock(); | |
674 | + while (m_decoded_data_queue.size() > 0) { | |
675 | + mem = m_decoded_data_queue.front(); | |
676 | + delete mem; | |
677 | + mem = nullptr; | |
678 | + m_decoded_data_queue.pop(); | |
679 | + } | |
680 | + m_decoded_data_queue_mtx.unlock(); | |
671 | 681 | } |
672 | 682 | |
673 | 683 | void DvppStreamDecoder::doRecode(RecoderInfo& recoderInfo) { | ... | ... |
src/decoder/dvpp/FFRecoder.cpp
... | ... | @@ -134,10 +134,17 @@ bool FFRecoder::init(AVStream* stream, AVCodecContext* avctx, const char* outfil |
134 | 134 | return false; |
135 | 135 | } |
136 | 136 | |
137 | - avcodec_copy_context(codec_ctx_, avctx); | |
138 | - codec_ctx_->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; | |
139 | 137 | m_inStream = stream; |
140 | 138 | |
139 | + int ret = avcodec_parameters_to_context(codec_ctx_, m_inStream->codecpar); | |
140 | + if (ret < 0) { | |
141 | + printf("Failed to copy in_stream codecpar to codec context\n"); | |
142 | + return false; | |
143 | + } | |
144 | + | |
145 | + // avcodec_copy_context(codec_ctx_, avctx); | |
146 | + codec_ctx_->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; | |
147 | + | |
141 | 148 | // [2] 创建输出上下文 |
142 | 149 | avformat_alloc_output_context2(&fmt_ctx_, nullptr, nullptr, outfile_name); |
143 | 150 | |
... | ... | @@ -154,8 +161,8 @@ bool FFRecoder::init(AVStream* stream, AVCodecContext* avctx, const char* outfil |
154 | 161 | |
155 | 162 | codec_ctx_->time_base = out_stream_->time_base; |
156 | 163 | |
157 | - av_opt_set(out_stream_->codec->priv_data, "preset", "ultrafast", 0); | |
158 | - av_opt_set(out_stream_->codec->priv_data, "tune", "zerolatency", 0); | |
164 | + av_opt_set(out_stream_->priv_data, "preset", "ultrafast", 0); | |
165 | + av_opt_set(out_stream_->priv_data, "tune", "zerolatency", 0); | |
159 | 166 | |
160 | 167 | // av_dump_format(fmt_ctx_, out_stream_->id, outfile_name, 1); |
161 | 168 | |
... | ... | @@ -175,8 +182,7 @@ bool FFRecoder::init(AVStream* stream, AVCodecContext* avctx, const char* outfil |
175 | 182 | void FFRecoder::release() { |
176 | 183 | av_write_trailer(fmt_ctx_); |
177 | 184 | |
178 | - avcodec_close(fmt_ctx_->streams[0]->codec); | |
179 | - av_freep(&fmt_ctx_->streams[0]->codec); | |
185 | + avcodec_parameters_free(&fmt_ctx_->streams[0]->codecpar); | |
180 | 186 | av_freep(&fmt_ctx_->streams[0]); |
181 | 187 | |
182 | 188 | avio_close(fmt_ctx_->pb); | ... | ... |
src/decoder/dvpp/depend_headers.h
... | ... | @@ -27,9 +27,10 @@ extern "C" { |
27 | 27 | #include "libavutil/samplefmt.h" |
28 | 28 | #include "libavformat/avformat.h" |
29 | 29 | #include "libavcodec/avcodec.h" |
30 | - #include <libavutil/opt.h> | |
31 | - #include <libavutil/timestamp.h> | |
32 | - #include <libswscale/swscale.h> | |
30 | + #include "libavcodec/bsf.h" | |
31 | + #include "libavutil/opt.h" | |
32 | + #include "libavutil/timestamp.h" | |
33 | + #include "libswscale/swscale.h" | |
33 | 34 | } |
34 | 35 | |
35 | 36 | ... | ... |
src/decoder/gb28181/DvppGB28181Decoder.cpp renamed to src/decoder/gb28181/DvppGB28181Decoder.cpp0
... | ... | @@ -373,10 +373,6 @@ bool DvppGB28181Decoder::isSurport(FFDecConfig& cfg){ |
373 | 373 | return true; |
374 | 374 | } |
375 | 375 | |
376 | -int DvppGB28181Decoder::getCachedQueueLength(){ | |
377 | - return m_rtpPtr->GetPsFrameListSize(); | |
378 | -} | |
379 | - | |
380 | 376 | DeviceMemory* DvppGB28181Decoder::snapshot() { |
381 | 377 | |
382 | 378 | DeviceMemory* snapshot_mem = nullptr; | ... | ... |
src/decoder/gb28181/DvppGB28181Decoder.h
src/decoder/gb28181/DvppGB28181Decoder2.cpp
0 → 100644
1 | +//#include "LOG_manager.h" | |
2 | +#include <iostream> | |
3 | +#include "DvppGB28181Decoder2.h" | |
4 | +#include "common_header.h" | |
5 | + | |
6 | + | |
7 | +#define ECLOSED 0 | |
8 | +#define ECLOSING 1 | |
9 | +#define ERUNNING 2 | |
10 | +#define EPAUSE 3 | |
11 | +#define EINITED 4 | |
12 | + | |
13 | +static void RTP_Stream_CallBack(void* userdata, uint8_t* buf, int buf_size, uint64_t pts) | |
14 | +{ | |
15 | + DvppGB28181Decoder2* decoder = (DvppGB28181Decoder2*)userdata; | |
16 | + decoder->stream_callback(buf, buf_size, pts); | |
17 | +} | |
18 | + | |
19 | +static void RTP_Stream_End_CallBack(void* userdata) | |
20 | +{ | |
21 | + DvppGB28181Decoder2* decoder = (DvppGB28181Decoder2*)userdata; | |
22 | + decoder->stream_end_callback(); | |
23 | +} | |
24 | + | |
25 | +DvppGB28181Decoder2::DvppGB28181Decoder2() { | |
26 | + m_frameSkip = 1; | |
27 | + m_dec_keyframe = false; | |
28 | + m_post_decode_thread = 0; | |
29 | +} | |
30 | + | |
31 | +DvppGB28181Decoder2::~DvppGB28181Decoder2() | |
32 | +{ | |
33 | + close(); | |
34 | + | |
35 | + m_dec_keyframe = false; | |
36 | + | |
37 | + LOG_INFO("destroy OK--{}", m_dec_name); | |
38 | +} | |
39 | + | |
40 | +void DvppGB28181Decoder2::close(){ | |
41 | + | |
42 | + if (m_status == ECLOSED) return; | |
43 | + | |
44 | + m_status = ECLOSING; | |
45 | + | |
46 | + LOG_DEBUG("real decode thread exit success 1--{}", m_dec_name); | |
47 | + | |
48 | + if(nullptr != m_rtpPtr){ | |
49 | + if (m_rtpPtr->IsOpened()) { | |
50 | + m_rtpPtr->Close(); | |
51 | + LOG_DEBUG("real decode thread exit success 2--{}", m_dec_name); | |
52 | + } | |
53 | + | |
54 | + delete m_rtpPtr; | |
55 | + m_rtpPtr = nullptr; | |
56 | + } | |
57 | + | |
58 | + if (m_post_decode_thread != 0) { | |
59 | + pthread_join(m_post_decode_thread,0); | |
60 | + m_post_decode_thread = 0; | |
61 | + } | |
62 | + | |
63 | + rtpDecoder.Close(); | |
64 | + | |
65 | + m_status = ECLOSED; | |
66 | + | |
67 | + LOG_INFO("解码器关闭成功 --{}", m_dec_name); | |
68 | +} | |
69 | + | |
70 | +bool DvppGB28181Decoder2::init(FFDecConfig& cfg){ | |
71 | + | |
72 | + m_rtpPtr = new RTPReceiver2(); | |
73 | + if(nullptr == m_rtpPtr){ | |
74 | + return false; | |
75 | + } | |
76 | + | |
77 | + m_dec_name = cfg.dec_name; | |
78 | + m_frameSkip = cfg.skip_frame; | |
79 | + if (m_frameSkip < 1) m_frameSkip = 1; | |
80 | + | |
81 | + m_gpuid = atoi(cfg.gpuid.c_str()); | |
82 | + | |
83 | + m_rtpPtr->SetOutputCallback(RTP_Stream_CallBack, this); | |
84 | + m_rtpPtr->SetVodEndCallback(RTP_Stream_End_CallBack, this); | |
85 | + | |
86 | + post_decoded_cbk = cfg.post_decoded_cbk; | |
87 | + decode_finished_cbk = cfg.decode_finished_cbk; | |
88 | + | |
89 | + if (!rtpDecoder.Init(cfg)) { | |
90 | + return false; | |
91 | + } | |
92 | + | |
93 | + m_cfg = cfg; | |
94 | + | |
95 | + LOG_INFO("init - {} ", m_dec_name); | |
96 | + | |
97 | + m_status = EINITED; | |
98 | + | |
99 | + return true; | |
100 | +} | |
101 | + | |
102 | +bool DvppGB28181Decoder2::start() { | |
103 | + | |
104 | + m_status = ERUNNING; | |
105 | + | |
106 | + bool bRet = m_rtpPtr->Open(m_cfg.uri, !m_cfg.force_tcp); | |
107 | + if(bRet && rtpDecoder.start()) { | |
108 | + pthread_create(&m_post_decode_thread,0, | |
109 | + [](void* arg) | |
110 | + { | |
111 | + DvppGB28181Decoder2* a=(DvppGB28181Decoder2*)arg; | |
112 | + a->display_thread(); | |
113 | + return (void*)0; | |
114 | + } | |
115 | + ,this); | |
116 | + | |
117 | + return true; | |
118 | + } | |
119 | + | |
120 | + close(); | |
121 | + | |
122 | + LOG_ERROR("[{}] - rtp receiver open failed !", m_dec_name); | |
123 | + | |
124 | + return false; | |
125 | +} | |
126 | + | |
127 | +void DvppGB28181Decoder2::setDecKeyframe(bool bKeyframe){ | |
128 | + m_dec_keyframe = bKeyframe; | |
129 | +} | |
130 | + | |
131 | +void DvppGB28181Decoder2::stream_callback(uint8_t* buf, int buf_size, uint64_t pts) { | |
132 | + if (m_status == EPAUSE) return; | |
133 | + | |
134 | + // 若设置为关键帧解码,非关键帧数据直接返回 | |
135 | + // if(m_dec_keyframe && !isKey) return; | |
136 | + | |
137 | + rtpDecoder.CacheBuffer(buf, buf_size); | |
138 | +} | |
139 | + | |
140 | +void DvppGB28181Decoder2::display_thread(){ | |
141 | + | |
142 | + int index = 0; | |
143 | + while (isRunning()) | |
144 | + { | |
145 | + auto mem = rtpDecoder.GetFrame(); | |
146 | + if(mem) { | |
147 | + if ((m_frameSkip == 1 || index % m_frameSkip == 0) && post_decoded_cbk){ | |
148 | + post_decoded_cbk(m_postDecArg, mem); | |
149 | + } else { | |
150 | + delete mem; | |
151 | + mem = nullptr; | |
152 | + } | |
153 | + | |
154 | + index++; | |
155 | + if(index >= 100000){ | |
156 | + index = 0; | |
157 | + } | |
158 | + } | |
159 | + | |
160 | + std::this_thread::sleep_for(std::chrono::milliseconds(10)); | |
161 | + } | |
162 | + | |
163 | + LOG_INFO("[{}] - display thread exited.", m_dec_name); | |
164 | +} | |
165 | + | |
166 | +void DvppGB28181Decoder2::stream_end_callback() | |
167 | +{ | |
168 | + LOG_INFO("[{}] - stream end.", m_dec_name); | |
169 | + | |
170 | + m_status = ECLOSING; | |
171 | + | |
172 | + decode_finished_cbk(m_finishedDecArg); | |
173 | + | |
174 | + return; | |
175 | +} | |
176 | + | |
177 | +void DvppGB28181Decoder2::setPostDecArg(const void* postDecArg){ | |
178 | + m_postDecArg = postDecArg; | |
179 | +} | |
180 | + | |
181 | +void DvppGB28181Decoder2::setFinishedDecArg(const void* finishedDecArg){ | |
182 | + m_finishedDecArg = finishedDecArg; | |
183 | +} | |
184 | + | |
185 | +void DvppGB28181Decoder2::pause() { | |
186 | + m_status = EPAUSE; | |
187 | + LOG_INFO("[{}] - pause", m_dec_name); | |
188 | +} | |
189 | + | |
190 | +void DvppGB28181Decoder2::resume() { | |
191 | + m_status = ERUNNING; | |
192 | + LOG_INFO("[{}] - resume", m_dec_name); | |
193 | +} | |
194 | + | |
195 | +bool DvppGB28181Decoder2::isRunning(){ | |
196 | + if (m_status == ECLOSED || m_status == ECLOSING){ | |
197 | + return false; | |
198 | + } | |
199 | + return true; | |
200 | +} | |
201 | + | |
202 | +bool DvppGB28181Decoder2::isFinished(){ | |
203 | + if (m_status == ECLOSED || m_status == ECLOSING){ | |
204 | + return true; | |
205 | + } | |
206 | + return false; | |
207 | +} | |
208 | + | |
209 | +bool DvppGB28181Decoder2::isPausing(){ | |
210 | + if (m_status == EPAUSE){ | |
211 | + return true; | |
212 | + } | |
213 | + return false; | |
214 | +} | |
215 | + | |
216 | +bool DvppGB28181Decoder2::getResolution( int &width, int &height ){ | |
217 | + width = frameW; | |
218 | + height = frameH; | |
219 | + return true; | |
220 | +} | |
221 | + | |
222 | +bool DvppGB28181Decoder2::getOutResolution( int &width, int &height ) { | |
223 | + width = frameW; | |
224 | + height = frameH; | |
225 | + return true; | |
226 | +} | |
227 | + | |
228 | +float DvppGB28181Decoder2::fps() { | |
229 | + return m_fps; | |
230 | +} | |
231 | + | |
232 | +bool DvppGB28181Decoder2::isSurport(FFDecConfig& cfg){ | |
233 | + // 由于是否支持需要在拿到数据后才能断定,无法事先判断,所以这个地方默认返回true | |
234 | + return true; | |
235 | +} | |
236 | + | |
237 | +DeviceMemory* DvppGB28181Decoder2::snapshot() { | |
238 | + | |
239 | + DeviceMemory* snapshot_mem = nullptr; | |
240 | + int loop_times = 0; | |
241 | + while (isRunning()) { | |
242 | + snapshot_mem = rtpDecoder.GetFrame(); | |
243 | + if (snapshot_mem) { | |
244 | + break; | |
245 | + } | |
246 | + | |
247 | + loop_times++; | |
248 | + if(loop_times > 100) { | |
249 | + // 1s都没截取到图,退出 | |
250 | + break; | |
251 | + } | |
252 | + std::this_thread::sleep_for(std::chrono::milliseconds(10)); | |
253 | + } | |
254 | + | |
255 | + return snapshot_mem; | |
256 | +} | |
257 | + | |
258 | +void DvppGB28181Decoder2::doRecode(RecoderInfo& recoderInfo) { | |
259 | + return rtpDecoder.doRecode(recoderInfo); | |
260 | +} | |
261 | + | |
262 | +void DvppGB28181Decoder2::set_mq_callback(std::function<bool(const char *msg)> mq_publish) { | |
263 | + rtpDecoder.set_mq_callback(mq_publish); | |
264 | +} | |
0 | 265 | \ No newline at end of file | ... | ... |
src/decoder/gb28181/DvppGB28181Decoder2.h
0 → 100644
1 | +#ifndef _GB28181_DECODER_H_ | |
2 | +#define _GB28181_DECODER_H_ | |
3 | + | |
4 | +#include <atomic> | |
5 | +#include <mutex> | |
6 | + | |
7 | +#include "./rtp2/RTPReceiver2.h" | |
8 | +#include "../dvpp/DvppRtpDecoder.h" | |
9 | + | |
10 | +#include "common_header.h" | |
11 | +#include "../interface/AbstractDecoder.h" | |
12 | + | |
13 | +using namespace std; | |
14 | + | |
15 | +class DvppGB28181Decoder2: public AbstractDecoder | |
16 | +{ | |
17 | +public: | |
18 | + DvppGB28181Decoder2(); | |
19 | + ~DvppGB28181Decoder2(); | |
20 | + | |
21 | + bool init(FFDecConfig& cfg); | |
22 | + void close(); | |
23 | + bool start(); | |
24 | + void pause(); | |
25 | + void resume(); | |
26 | + | |
27 | + void setDecKeyframe(bool bKeyframe); | |
28 | + | |
29 | + bool isRunning(); | |
30 | + bool isFinished(); | |
31 | + bool isPausing(); | |
32 | + bool getResolution( int &width, int &height ); | |
33 | + bool getOutResolution( int &width, int &height ); | |
34 | + | |
35 | + bool isSurport(FFDecConfig& cfg); | |
36 | + | |
37 | + float fps(); | |
38 | + | |
39 | + DECODER_TYPE getDecoderType(){ return DECODER_TYPE_DVPP_GB28181; } | |
40 | + | |
41 | + DeviceMemory* snapshot(); | |
42 | + | |
43 | + void setName(string nm){ | |
44 | + m_dec_name = nm; | |
45 | + } | |
46 | + | |
47 | + string getName(){ | |
48 | + return m_dec_name; | |
49 | + } | |
50 | + | |
51 | + void setPostDecArg(const void* postDecArg); | |
52 | + void setFinishedDecArg(const void* finishedDecArg); | |
53 | + | |
54 | + void doRecode(RecoderInfo& recoderInfo); | |
55 | + | |
56 | + void set_mq_callback(std::function<bool(const char *msg)> mq_publish); | |
57 | + | |
58 | +public: | |
59 | + void stream_callback(uint8_t* buf, int buf_size, uint64_t pts); | |
60 | + void stream_end_callback(); | |
61 | + void display_thread(); | |
62 | + | |
63 | +private: | |
64 | + string m_dec_name; // 必须为28181编码 | |
65 | + FFDecConfig m_cfg; | |
66 | + | |
67 | + RTPReceiver2* m_rtpPtr {nullptr}; | |
68 | + | |
69 | + uint64_t m_startPts {}; | |
70 | + uint64_t m_lastPts {}; //上一次pts的值 | |
71 | + uint64_t m_curPts {}; //当前的pts值 | |
72 | + uint64_t m_diffPts {}; | |
73 | + | |
74 | + uint32_t frameW {}, frameH {}; | |
75 | + float m_fps {}; | |
76 | + int m_frameSkip {}; | |
77 | + | |
78 | + int log_count {}; | |
79 | + | |
80 | + std::atomic_int m_status {}; | |
81 | + | |
82 | + pthread_t m_post_decode_thread; | |
83 | + const void * m_postDecArg; | |
84 | + POST_DECODE_CALLBACK post_decoded_cbk; // 解码数据回调接口 | |
85 | + | |
86 | + const void * m_finishedDecArg; | |
87 | + DECODE_FINISHED_CALLBACK decode_finished_cbk; | |
88 | + | |
89 | + queue<AVFrame*> mFrameQueue; | |
90 | + mutex m_queue_mutex; | |
91 | + mutex m_snapshot_mutex; | |
92 | + | |
93 | + bool m_dec_keyframe; | |
94 | + | |
95 | + DvppRtpDecoder rtpDecoder; | |
96 | + | |
97 | + int m_gpuid {0}; | |
98 | +}; | |
99 | + | |
100 | +#endif // _GB28181_DECODER_H_ | ... | ... |
src/decoder/gb28181/rtp/FFRtpParser.cpp deleted
1 | -// | |
2 | -// Created by bxc on 2023/4/18. | |
3 | -// 作者:北小菜 | |
4 | -// 邮箱:bilibili_bxc@126.com | |
5 | -// 西瓜视频主页:https://www.ixigua.com/home/4171970536803763 | |
6 | -// 哔哩哔哩主页:https://space.bilibili.com/487906612/ | |
7 | -// | |
8 | - | |
9 | -#include "FFRtpParser.h" | |
10 | -#include "Utils.h" | |
11 | -#include <string.h> | |
12 | - | |
13 | -int avio_read_packet(void* opaque, uint8_t* buf, int buffsize){ | |
14 | - FFRtpParser* player = (FFRtpParser*)opaque; | |
15 | - | |
16 | - int ret = 0; | |
17 | - if (player->bufferSize >= buffsize) | |
18 | - { | |
19 | - memcpy(buf, player->buffer, buffsize); | |
20 | - player->bufferSize = player->bufferSize - buffsize; | |
21 | - memmove(player->buffer, player->buffer + buffsize, player->bufferSize); | |
22 | - ret = buffsize; | |
23 | - | |
24 | - LOG_INFO("avio_read_packet=%d", buffsize); | |
25 | - } | |
26 | - return ret; | |
27 | -} | |
28 | - | |
29 | -FFRtpParser::FFRtpParser() | |
30 | -{ | |
31 | -} | |
32 | - | |
33 | -FFRtpParser::~FFRtpParser() | |
34 | -{ | |
35 | - if (mVideoCodecPar) { | |
36 | - avcodec_parameters_free(&mVideoCodecPar); | |
37 | - } | |
38 | - if (mVideoCodecCtx) { | |
39 | - avcodec_close(mVideoCodecCtx); | |
40 | - mVideoCodecCtx = nullptr; | |
41 | - } | |
42 | - | |
43 | - if (mFmtCtx) { | |
44 | - avformat_close_input(&mFmtCtx); | |
45 | - mFmtCtx = nullptr; | |
46 | - } | |
47 | -} | |
48 | - | |
49 | -bool FFRtpParser::probe() | |
50 | -{ | |
51 | - mFmtCtx = avformat_alloc_context(); | |
52 | - | |
53 | - unsigned char* avioBuff = (unsigned char*)av_malloc(1920 * 1080); | |
54 | - mAvioCtx = avio_alloc_context(avioBuff, sizeof(avioBuff), 0, this, avio_read_packet, NULL, NULL); | |
55 | - //探测流(获取码流格式) | |
56 | - if (av_probe_input_buffer2(mAvioCtx, (const AVInputFormat**)&mInputFmt, "", NULL, 0, 0) < 0){ | |
57 | - LOG_ERROR("av_probe_input_buffer2 error"); | |
58 | - return false; | |
59 | - } | |
60 | - mFmtCtx->pb = mAvioCtx; | |
61 | - | |
62 | - //配置流参数 | |
63 | - //av_dict_set(&options, "fflags", "nobuffer", 0); //不缓存直接解码 | |
64 | - | |
65 | - //打开流 | |
66 | - if (avformat_open_input(&mFmtCtx, "", mInputFmt, &net_options) != 0) | |
67 | - { | |
68 | - LOG_ERROR("avformat_open_input error"); | |
69 | - return false; | |
70 | - } | |
71 | - //获取流信息 | |
72 | - if (avformat_find_stream_info(mFmtCtx, NULL) < 0)//? | |
73 | - { | |
74 | - LOG_ERROR("avformat_find_stream_info error"); | |
75 | - return false; | |
76 | - } | |
77 | - //获取视频流 | |
78 | - mVideoStream = av_find_best_stream(mFmtCtx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0); | |
79 | - if (mVideoStream < 0) | |
80 | - { | |
81 | - LOG_ERROR("av_find_best_stream error"); | |
82 | - return false; | |
83 | - } | |
84 | - //获取解码信息 | |
85 | - mVideoCodecPar = mFmtCtx->streams[mVideoStream]->codecpar; | |
86 | - const AVCodec* videoCodec = avcodec_find_decoder(mVideoCodecPar->codec_id); | |
87 | - if (!videoCodec){ | |
88 | - LOG_ERROR("avcodec_find_decoder error"); | |
89 | - return false; | |
90 | - } | |
91 | - mVideoCodecCtx = avcodec_alloc_context3(videoCodec); | |
92 | - | |
93 | - //codecpar为解码器上下文赋值 | |
94 | - if (avcodec_parameters_to_context(mVideoCodecCtx, mVideoCodecPar) != 0) | |
95 | - { | |
96 | - LOG_ERROR("avcodec_parameters_to_context error"); | |
97 | - return false; | |
98 | - } | |
99 | - | |
100 | - //设置解码器参数 | |
101 | - //av_dict_set(&codec_options, "tune", "zero-latency", 0);//设置零延迟 | |
102 | - //av_dict_set(&codec_options, "preset", "ultrafast", 0);//设置最模糊但是最快的解码方式 | |
103 | - //av_dict_set(&codec_options, "x265-params", "qp=20", 0);//设置265量化参数 | |
104 | - //量化参数:控制了视频帧中每一个宏区块(Macroblock)的压缩量。较大的数值,量化值更高,意味着更多的压缩,更低的质量,较小的数值代表相反的含义。 | |
105 | - | |
106 | - //打开解码器 | |
107 | - if (avcodec_open2(mVideoCodecCtx, videoCodec, &codec_options) < 0) | |
108 | - { | |
109 | - LOG_ERROR("avcodec_open2 error"); | |
110 | - return false; | |
111 | - } | |
112 | - LOG_INFO("mVideoCodecCtx->width=%d,mVideoCodecCtx->height=%d", mVideoCodecCtx->width, mVideoCodecCtx->height); | |
113 | - return true; | |
114 | -} | |
115 | - | |
116 | -void FFRtpParser::play(){ | |
117 | - LOG_INFO("start"); | |
118 | - | |
119 | - AVPacket pkt; | |
120 | - while (av_read_frame(mFmtCtx, &pkt) >= 0) { | |
121 | - if (pkt.stream_index == mVideoStream){ | |
122 | - | |
123 | - } | |
124 | - av_packet_unref(&pkt); | |
125 | - } | |
126 | - LOG_INFO("end"); | |
127 | -} | |
128 | 0 | \ No newline at end of file |
src/decoder/gb28181/rtp/FFRtpParser.h deleted
1 | -// | |
2 | -// Created by bxc on 2023/4/18. | |
3 | -// 作者:北小菜 | |
4 | -// 邮箱:bilibili_bxc@126.com | |
5 | -// 西瓜视频主页:https://www.ixigua.com/home/4171970536803763 | |
6 | -// 哔哩哔哩主页:https://space.bilibili.com/487906612/ | |
7 | -// | |
8 | - | |
9 | -#ifndef GB28181_RTP_FFRTPPARSER_H | |
10 | -#define GB28181_RTP_FFRTPPARSER_H | |
11 | - | |
12 | -#include <atomic> | |
13 | - | |
14 | -extern "C" | |
15 | -{ | |
16 | - #include <libavcodec/avcodec.h> | |
17 | - #include <libavformat/avformat.h> | |
18 | - #include <libswscale/swscale.h> | |
19 | -} | |
20 | - | |
21 | -#define RtpParser_buffer_max_size 4194304 // 4M = 4 * 1024 * 1024 = 4194304 字节 | |
22 | - | |
23 | -class FFRtpParser | |
24 | -{ | |
25 | -public: | |
26 | - FFRtpParser(); | |
27 | - ~FFRtpParser(); | |
28 | -public: | |
29 | - bool probe();//阻塞式探测国标流并获取解码参数 | |
30 | - void play();//在探测国标流成功以后,解码并渲染国标视频流 | |
31 | -public: | |
32 | - std::atomic<char> buffer[RtpParser_buffer_max_size]; | |
33 | - std::atomic_int bufferSize {0}; | |
34 | -private: | |
35 | - AVFormatContext * mFmtCtx; | |
36 | - AVIOContext * mAvioCtx; | |
37 | - const AVInputFormat* mInputFmt; | |
38 | - int mVideoStream = -1; | |
39 | - AVCodecParameters * mVideoCodecPar; | |
40 | - AVCodecContext * mVideoCodecCtx; | |
41 | - | |
42 | - AVDictionary* net_options;//网络连接参数 | |
43 | - AVDictionary* codec_options;//编码参数 | |
44 | - | |
45 | -}; | |
46 | -#endif //GB28181_RTP_FFRTPPARSER_H | |
47 | 0 | \ No newline at end of file |
src/decoder/gb28181/rtp/RTPReceiver2.cpp deleted
1 | -#include "RTPReceiver2.h" | |
2 | -#include "rtppacket.h" | |
3 | -#include <thread> | |
4 | - | |
5 | -#include "../common_header.h" | |
6 | -#include "../websocket/WebsocketClient.h" | |
7 | - | |
8 | -#ifdef __linux__ | |
9 | -#include "arpa/inet.h" | |
10 | -#endif | |
11 | - | |
12 | -#include "Rtp.h" | |
13 | - | |
14 | -const int MAX_RTP_BUFFER_SIZE = 1024*1024*10; | |
15 | - | |
16 | -#define Server_cache_max_size 4194304 // 1M = 1 * 1024 * 1024 = 1048576 字节 | |
17 | -#define Server_rtp_max_size 1800 | |
18 | - | |
19 | - | |
20 | -RTPReceiver2::RTPReceiver2() | |
21 | -{ | |
22 | - mRecvCache = (uint8_t*)malloc(Server_cache_max_size); | |
23 | - mRecvRtpBuffer = (uint8_t*)malloc(Server_rtp_max_size); | |
24 | -} | |
25 | - | |
26 | -RTPReceiver2::~RTPReceiver2(){ | |
27 | - if (mRecvCache) { | |
28 | - free(mRecvCache); | |
29 | - mRecvCache = nullptr; | |
30 | - } | |
31 | - | |
32 | - if (mRecvRtpBuffer) { | |
33 | - free(mRecvRtpBuffer); | |
34 | - mRecvRtpBuffer = nullptr; | |
35 | - } | |
36 | -} | |
37 | - | |
38 | -int RTPReceiver2::init(const char* ip, uint16_t port, bool isUdp) { | |
39 | - if (!isUdp) { | |
40 | - LOG_INFO("tcp://%s:%d", ip, port); | |
41 | - startTcpServer(ip, port); | |
42 | - } | |
43 | - else { | |
44 | - LOG_INFO("udp://%s:%d", ip, port); | |
45 | - startUdpServer(ip, port); | |
46 | - } | |
47 | -} | |
48 | - | |
49 | -int RTPReceiver2::startUdpServer(const char* ip, uint16_t port) { | |
50 | - | |
51 | - int server_fd, ret; | |
52 | - struct sockaddr_in ser_addr; | |
53 | - | |
54 | - server_fd = socket(AF_INET, SOCK_DGRAM, 0); //AF_INET:IPV4;SOCK_DGRAM:UDP | |
55 | - if(server_fd < 0) | |
56 | - { | |
57 | - printf("create socket fail!\n"); | |
58 | - return -1; | |
59 | - } | |
60 | - | |
61 | - memset(&ser_addr, 0, sizeof(ser_addr)); | |
62 | - ser_addr.sin_family = AF_INET; | |
63 | - ser_addr.sin_addr.s_addr = htonl(INADDR_ANY); //IP地址,需要进行网络序转换,INADDR_ANY:本地地址 | |
64 | - ser_addr.sin_port = htons(port); //端口号,需要网络序转换 | |
65 | - | |
66 | - ret = bind(server_fd, (struct sockaddr*)&ser_addr, sizeof(ser_addr)); | |
67 | - if(ret < 0) | |
68 | - { | |
69 | - printf("socket bind fail!\n"); | |
70 | - return -1; | |
71 | - } | |
72 | - | |
73 | - | |
74 | - char recvBuf[10000]; | |
75 | - int recvBufSize; | |
76 | - | |
77 | - socklen_t len; | |
78 | - struct sockaddr_in clent_addr; //clent_addr用于记录发送方的地址信息 | |
79 | - while(!m_bRtpExit) | |
80 | - { | |
81 | - memset(recvBuf, 0, sizeof(recvBuf)); | |
82 | - len = sizeof(clent_addr); | |
83 | - recvBufSize = recvfrom(server_fd, recvBuf, sizeof(recvBuf), 0, (struct sockaddr*)&clent_addr, &len); //recvfrom是拥塞函数,没有数据就一直拥塞 | |
84 | - if(recvBufSize <= 0) { | |
85 | - printf("recieve data fail!\n"); | |
86 | - break; | |
87 | - } | |
88 | - | |
89 | - if ((mPlayer->bufferSize + recvBufSize - RTP_HEADER_SIZE) < MAX_RTP_BUFFER_SIZE) { | |
90 | - memcpy(mPlayer->buffer + mPlayer->bufferSize, recvBuf + RTP_HEADER_SIZE, recvBufSize - RTP_HEADER_SIZE); | |
91 | - mPlayer->bufferSize += recvBufSize - RTP_HEADER_SIZE; | |
92 | - } else { | |
93 | - LOG_ERROR("recvBufSize = {} over GB28181Player_buffer_max_size ", recvBufSize); | |
94 | - } | |
95 | - } | |
96 | - | |
97 | - close(server_fd); | |
98 | - | |
99 | - return 0; | |
100 | -} | |
101 | - | |
102 | -int RTPReceiver2::startTcpServer(const char* ip, uint16_t port) { | |
103 | - | |
104 | - int listenfd, connfd; | |
105 | - struct sockaddr_in servaddr; | |
106 | - char buff[4096]; | |
107 | - int n; | |
108 | - | |
109 | - if( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ){ | |
110 | - printf("create socket error: %s(errno: %d)\n",strerror(errno),errno); | |
111 | - return 0; | |
112 | - } | |
113 | - | |
114 | - memset(&servaddr, 0, sizeof(servaddr)); | |
115 | - servaddr.sin_family = AF_INET; | |
116 | - servaddr.sin_addr.s_addr = htonl(INADDR_ANY); | |
117 | - servaddr.sin_port = htons(port); | |
118 | - | |
119 | - if( bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1){ | |
120 | - printf("bind socket error: %s(errno: %d)\n",strerror(errno),errno); | |
121 | - return 0; | |
122 | - } | |
123 | - | |
124 | - if( listen(listenfd, 10) == -1){ | |
125 | - printf("listen socket error: %s(errno: %d)\n",strerror(errno),errno); | |
126 | - return 0; | |
127 | - } | |
128 | - | |
129 | - | |
130 | - char recvBuf[10000]; | |
131 | - int recvBufSize = 0; | |
132 | - | |
133 | - while (!m_bRtpExit) | |
134 | - { | |
135 | - LOG_INFO("阻塞监听新连接..."); | |
136 | - // 阻塞接收请求 start | |
137 | - | |
138 | - int clientFd = accept(listenfd, (struct sockaddr*)NULL, NULL); | |
139 | - if (clientFd < 0) { | |
140 | - LOG_ERROR("accept connection error"); | |
141 | - continue; | |
142 | - } | |
143 | - // 阻塞接收请求 end | |
144 | - LOG_INFO("发现新连接:clientFd=%d", clientFd); | |
145 | - | |
146 | - while (!m_bRtpExit) { | |
147 | - recvBufSize = recv(clientFd, recvBuf, sizeof(recvBuf), 0); | |
148 | - if (recvBufSize <= 0) { | |
149 | - LOG_ERROR("::recv error: clientFd={},recvBufSize={}", clientFd, recvBufSize); | |
150 | - break; | |
151 | - } | |
152 | - | |
153 | - parseTcpData(recvBuf, recvBufSize); | |
154 | - } | |
155 | - | |
156 | - close(clientFd); | |
157 | - LOG_INFO("关闭连接 clientFd={}", clientFd); | |
158 | - | |
159 | - } | |
160 | - | |
161 | - close(listenfd); | |
162 | - return 0; | |
163 | -} | |
164 | - | |
165 | -void RTPReceiver2::parseTcpData(char* recvBuf, int recvBufSize) { | |
166 | - | |
167 | - if ((mRecvCacheSize + recvBufSize) > Server_cache_max_size) { | |
168 | - LOG_ERROR("超过缓冲容量上限,忽略本次读取的数据。mRecvCacheSize=%d,recvBufSize=%d",mRecvCacheSize, recvBufSize); | |
169 | - | |
170 | - } | |
171 | - else { | |
172 | - memcpy(mRecvCache + mRecvCacheSize, recvBuf, recvBufSize); | |
173 | - mRecvCacheSize += recvBufSize; | |
174 | - } | |
175 | - //LOGI("cacheSize=%d,开始进入解析 ... ...", cacheSize); | |
176 | - | |
177 | - while (true) { | |
178 | - | |
179 | - if (mRecvCacheSize > 2) { | |
180 | - | |
181 | - bool success = false; | |
182 | - | |
183 | - if (mRecvCacheSize > 2) { | |
184 | - mRecvRtpBufferSize = ntohs(*(int16_t*)(mRecvCache)); | |
185 | - if ((mRecvCacheSize - 2) >= mRecvRtpBufferSize) { | |
186 | - success = true; | |
187 | - } | |
188 | - } | |
189 | - | |
190 | - if (success) { | |
191 | - mRecvCacheSize -= 2; | |
192 | - mRecvCacheSize -= mRecvRtpBufferSize; | |
193 | - | |
194 | - // 提取RTP | |
195 | - memcpy(mRecvRtpBuffer, mRecvCache + 2, mRecvRtpBufferSize); | |
196 | - memmove(mRecvCache, mRecvCache + 2 + mRecvRtpBufferSize, mRecvCacheSize); | |
197 | - | |
198 | - // RTP | |
199 | - RtpHeader rtpHeader; | |
200 | - parseRtpHeader(mRecvRtpBuffer, &rtpHeader); | |
201 | - printf("get a rtp seq=%d,RtpBufferSize=%d,mRecvCacheSize=%d,marker=%d,timestamp=%d\n", | |
202 | - rtpHeader.seq, | |
203 | - mRecvRtpBufferSize, | |
204 | - mRecvCacheSize,rtpHeader.marker, rtpHeader.timestamp); | |
205 | - | |
206 | - | |
207 | - // 将从mRecvCache提取出来的rtp字节流 mRecvRtpBuffer去掉RTP_HEADER_SIZE,存储到播放器缓存中 | |
208 | - if ((mPlayer->bufferSize + mRecvRtpBufferSize - RTP_HEADER_SIZE) < MAX_RTP_BUFFER_SIZE) { | |
209 | - memcpy(mPlayer->buffer + mPlayer->bufferSize, mRecvRtpBuffer + RTP_HEADER_SIZE, mRecvRtpBufferSize - RTP_HEADER_SIZE); | |
210 | - mPlayer->bufferSize += mRecvRtpBufferSize - RTP_HEADER_SIZE; | |
211 | - } | |
212 | - else { | |
213 | - LOG_ERROR("recvBufSize = %d over MAX_RTP_BUFFER_SIZE ", recvBufSize); | |
214 | - } | |
215 | - | |
216 | - } | |
217 | - else { | |
218 | - //LOGI("跳出解析:cacheSize=%d,pktSize=%d", cacheSize, pktSize); | |
219 | - break; | |
220 | - } | |
221 | - } | |
222 | - else { | |
223 | - //LOGI("跳出解析:缓冲数据未发现完整数据包"); | |
224 | - break; | |
225 | - } | |
226 | - } | |
227 | -} | |
228 | - | |
229 | -int RTPReceiver2::allocRtpPort() { | |
230 | - | |
231 | - WebsocketClient* pServer = WebsocketClient::getInstance(); | |
232 | - int MIN_RTP_PORT = pServer->GetMinRtpPort() ; | |
233 | - int MAX_RTP_PORT = pServer->GetMaxRtpPort(); | |
234 | - | |
235 | - int s_rtpPort = MIN_RTP_PORT; | |
236 | - | |
237 | - srand((unsigned int)time(NULL)); | |
238 | - s_rtpPort = MIN_RTP_PORT + (rand() % MIN_RTP_PORT); | |
239 | - | |
240 | - if (s_rtpPort % 2) | |
241 | - ++s_rtpPort; | |
242 | - | |
243 | - int count = 0; | |
244 | - | |
245 | - while (true) | |
246 | - { | |
247 | - if (s_rtpPort >= MAX_RTP_PORT) { | |
248 | - s_rtpPort = MIN_RTP_PORT; | |
249 | - count ++; | |
250 | - if (count > 1) { | |
251 | - LOG_ERROR("[{}] - 范围内没有可用的port", m_SipChannelId); | |
252 | - } | |
253 | - } | |
254 | - | |
255 | - int i = 0; | |
256 | - for (; i < 2; i++) { | |
257 | - sockaddr_in sRecvAddr; | |
258 | - int s = socket(AF_INET, SOCK_DGRAM, 0); | |
259 | - | |
260 | - sRecvAddr.sin_family = AF_INET; | |
261 | - sRecvAddr.sin_addr.s_addr = htonl(INADDR_ANY); | |
262 | - sRecvAddr.sin_port = htons(s_rtpPort + i); | |
263 | - | |
264 | - int nResult = bind(s, (sockaddr *)&sRecvAddr, sizeof(sRecvAddr)); | |
265 | - if (nResult != 0) { | |
266 | - break; | |
267 | - } | |
268 | - | |
269 | - nResult = close(s); | |
270 | - if (nResult != 0) { | |
271 | - LOG_ERROR("[{}] - closesocket failed : {}", m_SipChannelId, nResult); | |
272 | - break; | |
273 | - } | |
274 | - } | |
275 | - | |
276 | - if (i == 2) | |
277 | - break; | |
278 | - | |
279 | - s_rtpPort += 2; | |
280 | - } | |
281 | - | |
282 | - return s_rtpPort; | |
283 | -} | |
284 | - | |
285 | -void RTPReceiver2::RequestStreamFailed() { | |
286 | - m_bRtpExit = true; | |
287 | -} | |
288 | 0 | \ No newline at end of file |
src/decoder/gb28181/rtp2/RTPReceiver2.cpp
0 → 100644
1 | +#include "RTPReceiver2.h" | |
2 | +#include "rtppacket.h" | |
3 | +#include <thread> | |
4 | + | |
5 | +#include "../common_header.h" | |
6 | +#include "../websocket/WebsocketClient.h" | |
7 | + | |
8 | +#ifdef __linux__ | |
9 | +#include "arpa/inet.h" | |
10 | +#endif | |
11 | + | |
12 | +#include "Rtp.h" | |
13 | + | |
14 | +const int MAX_RTP_BUFFER_SIZE = 1024*1024*10; | |
15 | + | |
16 | +#define Server_cache_max_size 4194304 // 1M = 1 * 1024 * 1024 = 1048576 字节 | |
17 | +#define Server_rtp_max_size 1800 | |
18 | + | |
19 | + | |
20 | +RTPReceiver2::RTPReceiver2() | |
21 | +{ | |
22 | + mRecvCache = (uint8_t*)malloc(Server_cache_max_size); | |
23 | + mRecvRtpBuffer = (uint8_t*)malloc(Server_rtp_max_size); | |
24 | +} | |
25 | + | |
26 | +RTPReceiver2::~RTPReceiver2(){ | |
27 | + if (mRecvCache) { | |
28 | + free(mRecvCache); | |
29 | + mRecvCache = nullptr; | |
30 | + } | |
31 | + | |
32 | + if (mRecvRtpBuffer) { | |
33 | + free(mRecvRtpBuffer); | |
34 | + mRecvRtpBuffer = nullptr; | |
35 | + } | |
36 | +} | |
37 | + | |
38 | +void RTPReceiver2::SetOutputCallback(CallBack_Stream cb, void* param) | |
39 | +{ | |
40 | + m_buffer_cbk = cb; | |
41 | + m_bufferParam = param; | |
42 | +} | |
43 | + | |
44 | +void RTPReceiver2::SetVodEndCallback(CallBack_VodFileEnd cb, void* param) | |
45 | +{ | |
46 | + m_finish_cbk = cb; | |
47 | + m_finishParam = param; | |
48 | +} | |
49 | + | |
50 | +bool RTPReceiver2::Open(string channel_id, bool isUdp) { | |
51 | + m_SipChannelId = channel_id; | |
52 | + | |
53 | + m_rtp_port = allocRtpPort(); | |
54 | + if (m_rtp_port < 0) { | |
55 | + return false; | |
56 | + } | |
57 | + | |
58 | + bool bReq = start_server(channel_id, m_rtp_port, isUdp); | |
59 | + if (!bReq) { | |
60 | + LOG_INFO("[{}] start_server failed !", m_SipChannelId); | |
61 | + Close(); | |
62 | + return false; | |
63 | + } | |
64 | + | |
65 | + m_bOpened = true; | |
66 | + | |
67 | + LOG_INFO("[{}] started.", m_SipChannelId); | |
68 | + | |
69 | + return true; | |
70 | +} | |
71 | + | |
72 | +bool RTPReceiver2::IsOpened(){ | |
73 | + LOG_INFO("[{}] isopen:{} ", m_SipChannelId, m_bOpened); | |
74 | + return m_bOpened; | |
75 | +} | |
76 | + | |
77 | +void RTPReceiver2::Close(){ | |
78 | + m_bRtpExit = true; | |
79 | + | |
80 | + WebsocketClient* pServer = WebsocketClient::getInstance(); | |
81 | + if (pServer){ | |
82 | + pServer->ByeInvite(m_SipChannelId, m_rtp_port); | |
83 | + } | |
84 | + | |
85 | + if(m_server_thread) { | |
86 | + m_server_thread->join(); | |
87 | + delete m_server_thread; | |
88 | + m_server_thread = nullptr; | |
89 | + } | |
90 | +} | |
91 | + | |
92 | +bool RTPReceiver2::start_server(string channel_id, int port, bool isUdp) { | |
93 | + WebsocketClient* pClient = WebsocketClient::getInstance(); | |
94 | + if (pClient){ | |
95 | + | |
96 | + if (isUdp) { | |
97 | + m_server_thread = new std::thread([](void* arg) { | |
98 | + RTPReceiver2* a=(RTPReceiver2*)arg; | |
99 | + a->udp_server(); | |
100 | + return (void*)0; | |
101 | + }, this); | |
102 | + | |
103 | + if (pClient->InviteUdp(channel_id, port, this) < 0) { | |
104 | + return false; | |
105 | + } | |
106 | + | |
107 | + } else { | |
108 | + m_server_thread = new std::thread([](void* arg) { | |
109 | + RTPReceiver2* a=(RTPReceiver2*)arg; | |
110 | + a->tcp_server(); | |
111 | + return (void*)0; | |
112 | + }, this); | |
113 | + | |
114 | + if (pClient->InviteTcp(channel_id, port, this) < 0) { | |
115 | + return false; | |
116 | + } | |
117 | + } | |
118 | + } | |
119 | + | |
120 | + return true; | |
121 | +} | |
122 | + | |
123 | +int RTPReceiver2::udp_server() { | |
124 | + | |
125 | + uint16_t port = m_rtp_port; | |
126 | + | |
127 | + LOG_INFO("udp {}",port); | |
128 | + | |
129 | + int server_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); //AF_INET:IPV4;SOCK_DGRAM:UDP | |
130 | + if(server_fd < 0) | |
131 | + { | |
132 | + printf("create socket fail!\n"); | |
133 | + return -1; | |
134 | + } | |
135 | + | |
136 | + struct sockaddr_in ser_addr; | |
137 | + memset(&ser_addr, 0, sizeof(ser_addr)); | |
138 | + ser_addr.sin_family = AF_INET; | |
139 | + ser_addr.sin_addr.s_addr = htonl(INADDR_ANY); //IP地址,需要进行网络序转换,INADDR_ANY:本地地址 | |
140 | + ser_addr.sin_port = htons(port); //端口号,需要网络序转换 | |
141 | + | |
142 | + int ret = bind(server_fd, (struct sockaddr*)&ser_addr, sizeof(ser_addr)); | |
143 | + if(ret < 0) { | |
144 | + printf("socket bind fail!\n"); | |
145 | + return -1; | |
146 | + } | |
147 | + | |
148 | + uint8_t recvBuf[10000]; | |
149 | + int recvBufSize; | |
150 | + | |
151 | + socklen_t len; | |
152 | + struct sockaddr_in clent_addr; //clent_addr用于记录发送方的地址信息 | |
153 | + while(!m_bRtpExit) | |
154 | + { | |
155 | + memset(recvBuf, 0, sizeof(recvBuf)); | |
156 | + len = sizeof(clent_addr); | |
157 | + recvBufSize = recvfrom(server_fd, recvBuf, sizeof(recvBuf), 0, (struct sockaddr*)&clent_addr, &len); //recvfrom是拥塞函数,没有数据就一直拥塞 | |
158 | + if(recvBufSize <= 0) { | |
159 | + LOG_ERROR("recieve data fail!"); | |
160 | + break; | |
161 | + } | |
162 | + | |
163 | + // buffer 抛出 | |
164 | + m_buffer_cbk(m_bufferParam, recvBuf, recvBufSize, 0); | |
165 | + } | |
166 | + | |
167 | + close(server_fd); | |
168 | + | |
169 | + m_finish_cbk(m_finishParam); | |
170 | + | |
171 | + LOG_INFO("udp server exit."); | |
172 | + | |
173 | + return 0; | |
174 | +} | |
175 | + | |
176 | +int RTPReceiver2::tcp_server() { | |
177 | + | |
178 | + uint16_t port = m_rtp_port; | |
179 | + | |
180 | + LOG_INFO("tcp {}", port); | |
181 | + | |
182 | + int listenfd, connfd; | |
183 | + struct sockaddr_in servaddr; | |
184 | + char buff[4096]; | |
185 | + int n; | |
186 | + | |
187 | + if( (listenfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1 ){ | |
188 | + printf("create socket error: %s(errno: %d)\n",strerror(errno),errno); | |
189 | + return 0; | |
190 | + } | |
191 | + | |
192 | + memset(&servaddr, 0, sizeof(servaddr)); | |
193 | + servaddr.sin_family = AF_INET; | |
194 | + servaddr.sin_addr.s_addr = htonl(INADDR_ANY); | |
195 | + servaddr.sin_port = htons(port); | |
196 | + | |
197 | + if( bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1){ | |
198 | + printf("bind socket error: %s(errno: %d)\n",strerror(errno),errno); | |
199 | + return 0; | |
200 | + } | |
201 | + | |
202 | + if( listen(listenfd, SOMAXCONN) == -1){ | |
203 | + printf("listen socket error: %s(errno: %d)\n",strerror(errno),errno); | |
204 | + return 0; | |
205 | + } | |
206 | + | |
207 | + char recvBuf[10000]; | |
208 | + int recvBufSize = 0; | |
209 | + | |
210 | + while (!m_bRtpExit) | |
211 | + { | |
212 | + LOG_INFO("阻塞监听新连接..."); | |
213 | + // 阻塞接收请求 start | |
214 | + socklen_t len = sizeof(sockaddr); | |
215 | + sockaddr_in accept_addr; | |
216 | + int clientFd = accept(listenfd, (struct sockaddr*)&accept_addr, &len); | |
217 | + if (clientFd < 0) { | |
218 | + LOG_WARN("accept connection error"); | |
219 | + std::this_thread::sleep_for(std::chrono::milliseconds(5)); | |
220 | + continue; | |
221 | + } | |
222 | + // 阻塞接收请求 end | |
223 | + LOG_INFO("发现新连接:clientFd={}", clientFd); | |
224 | + | |
225 | + while (!m_bRtpExit) { | |
226 | + recvBufSize = recv(clientFd, recvBuf, sizeof(recvBuf), 0); | |
227 | + if (recvBufSize <= 0) { | |
228 | + LOG_ERROR("::recv error: clientFd={},recvBufSize={}", clientFd, recvBufSize); | |
229 | + break; | |
230 | + } | |
231 | + | |
232 | + parseTcpData(recvBuf, recvBufSize); | |
233 | + } | |
234 | + | |
235 | + close(clientFd); | |
236 | + LOG_WARN("关闭连接 clientFd={}", clientFd); | |
237 | + } | |
238 | + | |
239 | + close(listenfd); | |
240 | + | |
241 | + m_finish_cbk(m_finishParam); | |
242 | + | |
243 | + LOG_INFO("tcp server exit."); | |
244 | + return 0; | |
245 | +} | |
246 | + | |
247 | +void RTPReceiver2::parseTcpData(char* recvBuf, int recvBufSize) { | |
248 | + | |
249 | + if ((mRecvCacheSize + recvBufSize) > Server_cache_max_size) { | |
250 | + LOG_ERROR("超过缓冲容量上限,忽略本次读取的数据。mRecvCacheSize=%d,recvBufSize=%d",mRecvCacheSize, recvBufSize); | |
251 | + } else { | |
252 | + memcpy(mRecvCache + mRecvCacheSize, recvBuf, recvBufSize); | |
253 | + mRecvCacheSize += recvBufSize; | |
254 | + } | |
255 | + //LOGI("cacheSize=%d,开始进入解析 ... ...", cacheSize); | |
256 | + | |
257 | + while (true) { | |
258 | + | |
259 | + if (mRecvCacheSize > 2) { | |
260 | + | |
261 | + bool success = false; | |
262 | + | |
263 | + if (mRecvCacheSize > 2) { | |
264 | + mRecvRtpBufferSize = ntohs(*(int16_t*)(mRecvCache)); | |
265 | + if ((mRecvCacheSize - 2) >= mRecvRtpBufferSize) { | |
266 | + success = true; | |
267 | + } | |
268 | + } | |
269 | + | |
270 | + if (success) { | |
271 | + mRecvCacheSize -= 2; | |
272 | + mRecvCacheSize -= mRecvRtpBufferSize; | |
273 | + | |
274 | + // 提取RTP | |
275 | + memcpy(mRecvRtpBuffer, mRecvCache + 2, mRecvRtpBufferSize); | |
276 | + memmove(mRecvCache, mRecvCache + 2 + mRecvRtpBufferSize, mRecvCacheSize); | |
277 | + | |
278 | + struct RtpHeader rtpHeader; | |
279 | + parseRtpHeader(mRecvRtpBuffer, &rtpHeader); | |
280 | + printf("get a rtp seq=%d,RtpBufferSize=%d,mRecvCacheSize=%d,marker=%d,timestamp=%d\n", | |
281 | + rtpHeader.seq, | |
282 | + mRecvRtpBufferSize, | |
283 | + mRecvCacheSize,rtpHeader.marker, rtpHeader.timestamp); | |
284 | + | |
285 | + // buffer 抛出 | |
286 | + m_buffer_cbk(m_bufferParam, mRecvRtpBuffer, mRecvRtpBufferSize, rtpHeader.timestamp); | |
287 | + | |
288 | + } else { | |
289 | + //LOGI("跳出解析:cacheSize=%d,pktSize=%d", cacheSize, pktSize); | |
290 | + break; | |
291 | + } | |
292 | + } else { | |
293 | + //LOGI("跳出解析:缓冲数据未发现完整数据包"); | |
294 | + break; | |
295 | + } | |
296 | + } | |
297 | +} | |
298 | + | |
299 | +int RTPReceiver2::allocRtpPort() { | |
300 | + | |
301 | + WebsocketClient* pServer = WebsocketClient::getInstance(); | |
302 | + int MIN_RTP_PORT = pServer->GetMinRtpPort() ; | |
303 | + int MAX_RTP_PORT = pServer->GetMaxRtpPort(); | |
304 | + | |
305 | + int s_rtpPort = MIN_RTP_PORT; | |
306 | + | |
307 | + srand((unsigned int)time(NULL)); | |
308 | + s_rtpPort = MIN_RTP_PORT + (rand() % MIN_RTP_PORT); | |
309 | + | |
310 | + if (s_rtpPort % 2) | |
311 | + ++s_rtpPort; | |
312 | + | |
313 | + int count = 0; | |
314 | + | |
315 | + while (true) | |
316 | + { | |
317 | + if (s_rtpPort >= MAX_RTP_PORT) { | |
318 | + s_rtpPort = MIN_RTP_PORT; | |
319 | + count ++; | |
320 | + if (count > 1) { | |
321 | + LOG_ERROR("[{}] - 范围内没有可用的port", m_SipChannelId); | |
322 | + } | |
323 | + } | |
324 | + | |
325 | + int i = 0; | |
326 | + for (; i < 2; i++) { | |
327 | + sockaddr_in sRecvAddr; | |
328 | + int s = socket(AF_INET, SOCK_DGRAM, 0); | |
329 | + | |
330 | + sRecvAddr.sin_family = AF_INET; | |
331 | + sRecvAddr.sin_addr.s_addr = htonl(INADDR_ANY); | |
332 | + sRecvAddr.sin_port = htons(s_rtpPort + i); | |
333 | + | |
334 | + int nResult = bind(s, (sockaddr *)&sRecvAddr, sizeof(sRecvAddr)); | |
335 | + if (nResult != 0) { | |
336 | + break; | |
337 | + } | |
338 | + | |
339 | + nResult = close(s); | |
340 | + if (nResult != 0) { | |
341 | + LOG_ERROR("[{}] - closesocket failed : {}", m_SipChannelId, nResult); | |
342 | + break; | |
343 | + } | |
344 | + } | |
345 | + | |
346 | + if (i == 2) | |
347 | + break; | |
348 | + | |
349 | + s_rtpPort += 2; | |
350 | + } | |
351 | + | |
352 | + return s_rtpPort; | |
353 | +} | |
354 | + | |
355 | +void RTPReceiver2::RequestStreamFailed() { | |
356 | + m_bRtpExit = true; | |
357 | +} | |
0 | 358 | \ No newline at end of file | ... | ... |
src/decoder/gb28181/rtp/RTPReceiver2.h renamed to src/decoder/gb28181/rtp2/RTPReceiver2.h
... | ... | @@ -7,23 +7,35 @@ |
7 | 7 | |
8 | 8 | using namespace std; |
9 | 9 | |
10 | +typedef void(*CallBack_Stream)(void* userdata, uint8_t* buf, int buf_size, uint64_t pts); | |
10 | 11 | |
11 | -class RTPReceiver2{ | |
12 | +typedef void(*CallBack_VodFileEnd)(void* userdata); | |
13 | + | |
14 | + | |
15 | +class RTPReceiver2 { | |
12 | 16 | |
13 | 17 | public: |
14 | 18 | RTPReceiver2(); |
15 | 19 | virtual ~RTPReceiver2(); |
16 | 20 | |
17 | - int init(const char* ip, uint16_t port, bool isUdp); | |
21 | + bool Open(string channel_id, bool isUdp); | |
22 | + bool IsOpened(); | |
23 | + void Close(); | |
24 | + | |
25 | + void SetVodEndCallback(CallBack_VodFileEnd cb, void* param); | |
26 | + | |
27 | + void SetOutputCallback(CallBack_Stream cb, void* param); | |
18 | 28 | |
19 | 29 | void RequestStreamFailed(); |
20 | 30 | |
21 | 31 | int allocRtpPort(); |
22 | 32 | |
23 | -private: | |
24 | - int startUdpServer(const char* ip, uint16_t port); | |
25 | - int startTcpServer(const char* ip, uint16_t port); | |
33 | +public: | |
34 | + int udp_server(); | |
35 | + int tcp_server(); | |
26 | 36 | |
37 | +private: | |
38 | + bool start_server(string channel_id, int port, bool isUdp); | |
27 | 39 | void parseTcpData(char* recvBuf, int recvBufSize); |
28 | 40 | |
29 | 41 | public: |
... | ... | @@ -31,9 +43,24 @@ public: |
31 | 43 | uint64_t mRecvCacheSize {0}; |
32 | 44 | |
33 | 45 | uint8_t* mRecvRtpBuffer {nullptr}; // 从mRecvCache提取出来的rtp字节流 |
34 | - int16_t mRecvRtpBufferSize {0};// 从mRecvCache提取出来的rtp字节流总长度 (rtpHeader+rtpBody) | |
46 | + int16_t mRecvRtpBufferSize {0}; // 从mRecvCache提取出来的rtp字节流总长度 (rtpHeader+rtpBody) | |
35 | 47 | |
36 | 48 | bool m_bRtpExit {false}; |
49 | + | |
50 | + string m_SipChannelId; | |
51 | + int m_rtp_port{-1}; | |
52 | + | |
53 | + std::atomic_bool m_bOpened; | |
54 | + std::atomic_bool m_bAccepted; | |
55 | + std::atomic_bool m_bClosing; | |
56 | + | |
57 | + std::thread* m_server_thread{nullptr}; | |
58 | + | |
59 | + void* m_bufferParam; | |
60 | + CallBack_Stream m_buffer_cbk; // 视频流回调 | |
61 | + | |
62 | + void* m_finishParam; | |
63 | + CallBack_VodFileEnd m_finish_cbk; // 录像流结束回调 | |
37 | 64 | }; |
38 | 65 | |
39 | 66 | #endif // _RTP_RECEIVER_H_ |
40 | 67 | \ No newline at end of file | ... | ... |
src/decoder/gb28181/rtp/Rtp.cpp renamed to src/decoder/gb28181/rtp2/Rtp.cpp
src/decoder/gb28181/rtp/Rtp.h renamed to src/decoder/gb28181/rtp2/Rtp.h
src/decoder/gb28181/websocket/WebsocketClient.cpp
... | ... | @@ -191,7 +191,7 @@ int WebsocketClient::GetMaxRtpPort(){ |
191 | 191 | return mInfo.getMaxRtpPort(); |
192 | 192 | } |
193 | 193 | |
194 | -int WebsocketClient::InviteUdp(std::string sip_channel_id, int rtp_port, RTPReceiver* r) { | |
194 | +int WebsocketClient::InviteUdp(std::string sip_channel_id, int rtp_port, RTPReceiver2* r) { | |
195 | 195 | if (check_connect() < 0) { |
196 | 196 | return -1; |
197 | 197 | } |
... | ... | @@ -204,7 +204,7 @@ int WebsocketClient::InviteUdp(std::string sip_channel_id, int rtp_port, RTPRece |
204 | 204 | return 0; |
205 | 205 | } |
206 | 206 | |
207 | -int WebsocketClient::InviteTcp(std::string sip_channel_id, int rtp_port, RTPReceiver* r) { | |
207 | +int WebsocketClient::InviteTcp(std::string sip_channel_id, int rtp_port, RTPReceiver2* r) { | |
208 | 208 | if (check_connect() < 0) { |
209 | 209 | return -1; |
210 | 210 | } |
... | ... | @@ -228,7 +228,7 @@ int WebsocketClient::ByeInvite(std::string sip_channel_id, int rtp_port) { |
228 | 228 | return 0; |
229 | 229 | } |
230 | 230 | |
231 | -void WebsocketClient::cache_receiver(std::string sip_channel_id, int rtp_port, RTPReceiver* r) { | |
231 | +void WebsocketClient::cache_receiver(std::string sip_channel_id, int rtp_port, RTPReceiver2* r) { | |
232 | 232 | std::lock_guard<std::mutex> l(m_receiver_map_mtx); |
233 | 233 | string rKey = sip_channel_id + "_" + to_string(rtp_port); |
234 | 234 | m_receiver_map[rKey] = r; | ... | ... |
src/decoder/gb28181/websocket/WebsocketClient.h
... | ... | @@ -6,7 +6,7 @@ |
6 | 6 | |
7 | 7 | #include "Message/CatalogParser.h" |
8 | 8 | |
9 | -#include "../rtp/RTPReceiver.h" | |
9 | +#include "../rtp2/RTPReceiver2.h" | |
10 | 10 | |
11 | 11 | typedef websocketpp::client<websocketpp::config::asio_client> client; |
12 | 12 | typedef websocketpp::config::asio_client::message_type::ptr message_ptr; |
... | ... | @@ -32,8 +32,8 @@ public: |
32 | 32 | int GetMinRtpPort(); |
33 | 33 | int GetMaxRtpPort(); |
34 | 34 | |
35 | - int InviteUdp(std::string sip_channel_id, int rtp_port, RTPReceiver* r); | |
36 | - int InviteTcp(std::string sip_channel_id, int rtp_port, RTPReceiver* r); | |
35 | + int InviteUdp(std::string sip_channel_id, int rtp_port, RTPReceiver2* r); | |
36 | + int InviteTcp(std::string sip_channel_id, int rtp_port, RTPReceiver2* r); | |
37 | 37 | |
38 | 38 | int ByeInvite(std::string sip_channel_id, int rtp_port); |
39 | 39 | |
... | ... | @@ -56,7 +56,7 @@ private: |
56 | 56 | |
57 | 57 | int msg_parser(websocketpp::connection_hdl hdl, string msg); |
58 | 58 | |
59 | - void cache_receiver(std::string sip_channel_id, int rtp_port, RTPReceiver* r); | |
59 | + void cache_receiver(std::string sip_channel_id, int rtp_port, RTPReceiver2* r); | |
60 | 60 | |
61 | 61 | void response_invite_failed(std::string rKey); |
62 | 62 | |
... | ... | @@ -70,6 +70,6 @@ private: |
70 | 70 | |
71 | 71 | bool mbClosed{false}; |
72 | 72 | |
73 | - std::map<string, RTPReceiver*> m_receiver_map; | |
73 | + std::map<string, RTPReceiver2*> m_receiver_map; | |
74 | 74 | std::mutex m_receiver_map_mtx; |
75 | 75 | }; |
76 | 76 | \ No newline at end of file | ... | ... |
src/decoder/interface/AbstractDecoder.h
src/decoder/interface/DecoderManager.cpp
... | ... | @@ -7,7 +7,7 @@ |
7 | 7 | |
8 | 8 | #ifdef USE_DVPP |
9 | 9 | #include "../dvpp/DvppDecoderApi.h" |
10 | -#include "../gb28181/DvppGB28181Decoder.h" | |
10 | +#include "../gb28181/DvppGB28181Decoder2.h" | |
11 | 11 | #endif |
12 | 12 | |
13 | 13 | #include "logger.hpp" |
... | ... | @@ -61,7 +61,7 @@ AbstractDecoder* DecoderManager::createDecoder(MgrDecConfig config){ |
61 | 61 | if(DECODER_TYPE_DVPP == config.dec_type){ |
62 | 62 | dec = new DvppDecoderApi(); |
63 | 63 | } else if(DECODER_TYPE_DVPP_GB28181 == config.dec_type){ |
64 | - dec = new DvppGB28181Decoder(); | |
64 | + dec = new DvppGB28181Decoder2(); | |
65 | 65 | } |
66 | 66 | #endif |
67 | 67 | |
... | ... | @@ -470,23 +470,6 @@ vector<string> DecoderManager::getAllDecodeName(){ |
470 | 470 | return decode_names; |
471 | 471 | } |
472 | 472 | |
473 | -int DecoderManager::getCachedQueueLength(const string name){ | |
474 | - if (name.empty()){ | |
475 | - LOG_ERROR("name 为空!"); | |
476 | - return -1; | |
477 | - } | |
478 | - | |
479 | - std::lock_guard<std::mutex> l(m_mutex); | |
480 | - | |
481 | - auto dec = decoderMap.find(name); | |
482 | - if (dec != decoderMap.end()){ | |
483 | - return dec->second->getCachedQueueLength(); | |
484 | - } | |
485 | - | |
486 | - LOG_ERROR("没有找到name为{}的解码器",name); | |
487 | - return -1; | |
488 | -} | |
489 | - | |
490 | 473 | void DecoderManager::releaseDeviceMemory(DeviceMemory* info){ |
491 | 474 | if(nullptr != info){ |
492 | 475 | delete info; | ... | ... |
src/decoder/interface/DecoderManager.h
... | ... | @@ -230,15 +230,6 @@ public: |
230 | 230 | vector<string> getAllDecodeName(); |
231 | 231 | |
232 | 232 | /************************************************** |
233 | - * 接口:getCachedQueueLength | |
234 | - * 功能:获取解码缓冲队列当前长度 | |
235 | - * 参数:const string name 解码器名称 | |
236 | - * 返回:int 解码缓冲队列当前长度 | |
237 | - * 备注: | |
238 | - **************************************************/ | |
239 | - int getCachedQueueLength(const string name); | |
240 | - | |
241 | - /************************************************** | |
242 | 233 | * 接口:releaseDeviceMemory |
243 | 234 | * 功能:释放视频快照信息 |
244 | 235 | * 参数:DeviceMemory* info 视频快照信息 | ... | ... |
src/decoder/interface/VideoTools.cpp deleted
1 | -#include "VideoTools.h" | |
2 | -#include "logger.hpp" | |
3 | - | |
4 | -extern "C" { | |
5 | - #include <libavcodec/avcodec.h> | |
6 | - #include <libavdevice/avdevice.h> | |
7 | - #include <libavformat/avformat.h> | |
8 | - #include <libavfilter/avfilter.h> | |
9 | - #include <libavutil/avutil.h> | |
10 | - #include <libavutil/pixdesc.h> | |
11 | - #include <libswscale/swscale.h> | |
12 | - #include <libavutil/imgutils.h> | |
13 | -} | |
14 | - | |
15 | -namespace VideoTools { | |
16 | - | |
17 | -FFImgInfo* snapshot(const string& uri){ | |
18 | - if (uri.empty()){ | |
19 | - return nullptr; | |
20 | - } | |
21 | - | |
22 | - AVFormatContext* ifmt_ctx = nullptr; | |
23 | - AVCodecContext* codec_ctx = nullptr; | |
24 | - AVCodec* codec = nullptr; | |
25 | - AVPacket* pkt = nullptr; | |
26 | - AVFrame *frame = nullptr; | |
27 | - AVFrame *pFrameRGB = nullptr; | |
28 | - int video_index = -1; | |
29 | - AVStream* st = nullptr; | |
30 | - SwsContext *img_convert_ctx = nullptr; | |
31 | - uint8_t *buffer = nullptr; | |
32 | - int numBytes = 0; | |
33 | - int index = 0; | |
34 | - | |
35 | - FFImgInfo* imgInfo = nullptr; | |
36 | - | |
37 | - //av_register_all(); | |
38 | - avformat_network_init(); | |
39 | - | |
40 | - // 参数设置 | |
41 | - AVDictionary *options = nullptr; | |
42 | - av_dict_set( &options, "bufsize", "655360", 0 ); | |
43 | - av_dict_set( &options, "rtsp_transport", "tcp", 0 ); | |
44 | - av_dict_set( &options, "stimeout", "30000000", 0 ); // 单位为 百万分之一秒 | |
45 | - | |
46 | - ///打开输入的流 | |
47 | - int ret = avformat_open_input(&ifmt_ctx, uri.c_str(), nullptr, &options); | |
48 | - if (ret != 0){ | |
49 | - printf("Couldn't open input stream.\n"); | |
50 | - goto end_flag ; | |
51 | - } | |
52 | - | |
53 | - //查找流信息 | |
54 | - if (avformat_find_stream_info(ifmt_ctx, nullptr) < 0){ | |
55 | - printf("Couldn't find stream information.\n"); | |
56 | - goto end_flag ; | |
57 | - } | |
58 | - | |
59 | - //找到视频流索引 | |
60 | - video_index = av_find_best_stream(ifmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, nullptr, 0); | |
61 | - | |
62 | - st = ifmt_ctx->streams[video_index]; | |
63 | - | |
64 | - //找到解码器 | |
65 | - codec = avcodec_find_decoder(st->codecpar->codec_id); | |
66 | - if (!codec){ | |
67 | - fprintf(stderr, "Codec not found\n"); | |
68 | - goto end_flag ; | |
69 | - } | |
70 | - | |
71 | - //申请AVCodecContext | |
72 | - codec_ctx = avcodec_alloc_context3(codec); | |
73 | - if (!codec_ctx){ | |
74 | - goto end_flag ; | |
75 | - } | |
76 | - | |
77 | - avcodec_parameters_to_context(codec_ctx, ifmt_ctx->streams[video_index]->codecpar); | |
78 | - | |
79 | - //打开解码器 | |
80 | - if ((ret = avcodec_open2(codec_ctx, codec, nullptr) < 0)){ | |
81 | - goto end_flag ; | |
82 | - } | |
83 | - | |
84 | - // 计算解码后原始数据所需缓冲区大小,并分配内存空间 Determine required buffer size and allocate buffer | |
85 | - numBytes = av_image_get_buffer_size(AV_PIX_FMT_BGR24, codec_ctx->width, codec_ctx->height, 1); | |
86 | - buffer = (uint8_t *)av_malloc(numBytes * sizeof(uint8_t)); | |
87 | - | |
88 | - pFrameRGB = av_frame_alloc(); | |
89 | - av_image_fill_arrays(pFrameRGB->data, pFrameRGB->linesize, buffer, AV_PIX_FMT_BGR24, codec_ctx->width, codec_ctx->height, 1); | |
90 | - | |
91 | - 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, | |
92 | - SWS_BICUBIC, nullptr, nullptr, nullptr); | |
93 | - | |
94 | - pkt = av_packet_alloc(); | |
95 | - frame = av_frame_alloc(); | |
96 | - while (av_read_frame(ifmt_ctx, pkt) >= 0){ | |
97 | - if (pkt->stream_index == video_index){ | |
98 | - int ret = avcodec_send_packet(codec_ctx, pkt); | |
99 | - if (ret >= 0){ | |
100 | - ret = avcodec_receive_frame(codec_ctx, frame); | |
101 | - if ((ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) || ret < 0){ | |
102 | - LOG_ERROR("Failed to receive frame: {}",ret); | |
103 | - continue; | |
104 | - } | |
105 | - | |
106 | - index ++ ; | |
107 | - | |
108 | - if (index >= 5){ | |
109 | - // 取解码出来的第三帧,应该可以一定程度优化花屏问题 | |
110 | - sws_scale(img_convert_ctx, (const unsigned char* const*)frame->data, frame->linesize, 0, codec_ctx->height, pFrameRGB->data, pFrameRGB->linesize); | |
111 | - | |
112 | - imgInfo = new FFImgInfo(); | |
113 | - imgInfo->pData = buffer; | |
114 | - imgInfo->height = codec_ctx->height; | |
115 | - imgInfo->width = codec_ctx->width; | |
116 | - | |
117 | - break; | |
118 | - } | |
119 | - } | |
120 | - } | |
121 | - av_packet_unref(pkt); | |
122 | - } | |
123 | - | |
124 | -end_flag: | |
125 | - if (codec_ctx != nullptr){ | |
126 | - avcodec_close(codec_ctx); | |
127 | - avcodec_free_context(&codec_ctx); | |
128 | - } | |
129 | - | |
130 | - if (ifmt_ctx != nullptr){ | |
131 | - avformat_close_input(&ifmt_ctx); | |
132 | - } | |
133 | - | |
134 | - if (frame != nullptr){ | |
135 | - av_frame_free(&frame); | |
136 | - } | |
137 | - | |
138 | - if (pFrameRGB != nullptr){ | |
139 | - av_frame_free(&pFrameRGB); | |
140 | - } | |
141 | - | |
142 | - if (pkt != nullptr){ | |
143 | - av_packet_free(&pkt); | |
144 | - } | |
145 | - | |
146 | - return imgInfo; | |
147 | -} | |
148 | - | |
149 | -void releaseFFImgInfo(FFImgInfo* info) { | |
150 | - if(nullptr != info){ | |
151 | - if(info->pData != nullptr){ | |
152 | - av_free(info->pData); | |
153 | - info->pData = nullptr; | |
154 | - } | |
155 | - delete info; | |
156 | - info = nullptr; | |
157 | - } | |
158 | -} | |
159 | - | |
160 | -} // namespace | |
161 | 0 | \ No newline at end of file |
src/decoder/interface/VideoTools.h deleted
1 | -#ifndef __VIDEO_TOOLS_H__ | |
2 | -#define __VIDEO_TOOLS_H__ | |
3 | - | |
4 | -#include <string> | |
5 | - | |
6 | -using namespace std; | |
7 | - | |
8 | -struct FFImgInfo{ | |
9 | - string dec_name; | |
10 | - int width; | |
11 | - int height; | |
12 | - unsigned char * pData; | |
13 | - long timestamp; | |
14 | - long index; | |
15 | -}; | |
16 | - | |
17 | -namespace VideoTools { | |
18 | - | |
19 | - FFImgInfo* snapshot(const string& uri); | |
20 | - | |
21 | - void releaseFFImgInfo(FFImgInfo* info); | |
22 | -} | |
23 | - | |
24 | - | |
25 | -#endif // __VIDEO_TOOLS_H__ | |
26 | 0 | \ No newline at end of file |