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,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 | video_index = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &decoder, 0); | 178 | video_index = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &decoder, 0); |
179 | if (video_index < 0) { | 179 | if (video_index < 0) { |
180 | LOG_ERROR("[{}]- Cannot find a video stream in the input file!", m_dec_name); | 180 | LOG_ERROR("[{}]- Cannot find a video stream in the input file!", m_dec_name); |
@@ -480,10 +480,6 @@ DeviceMemory* DvppDecoder::snapshot(){ | @@ -480,10 +480,6 @@ DeviceMemory* DvppDecoder::snapshot(){ | ||
480 | return snapshot_mem; | 480 | return snapshot_mem; |
481 | } | 481 | } |
482 | 482 | ||
483 | -int DvppDecoder::getCachedQueueLength(){ | ||
484 | - return 0; | ||
485 | -} | ||
486 | - | ||
487 | void DvppDecoder::release_ffmpeg() { | 483 | void DvppDecoder::release_ffmpeg() { |
488 | m_dec_keyframe = false; | 484 | m_dec_keyframe = false; |
489 | if(h264bsfc){ | 485 | if(h264bsfc){ |
src/decoder/dvpp/DvppDecoder.h
@@ -56,8 +56,6 @@ public: | @@ -56,8 +56,6 @@ public: | ||
56 | void setPostDecArg(const void* postDecArg); | 56 | void setPostDecArg(const void* postDecArg); |
57 | void setFinishedDecArg(const void* finishedDecArg); | 57 | void setFinishedDecArg(const void* finishedDecArg); |
58 | 58 | ||
59 | - int getCachedQueueLength(); | ||
60 | - | ||
61 | void doRecode(RecoderInfo& recoderInfo); | 59 | void doRecode(RecoderInfo& recoderInfo); |
62 | 60 | ||
63 | void set_mq_callback(mq_callback_t cb); | 61 | void set_mq_callback(mq_callback_t cb); |
src/decoder/dvpp/DvppDecoderApi.cpp
@@ -100,13 +100,6 @@ float DvppDecoderApi::fps(){ | @@ -100,13 +100,6 @@ float DvppDecoderApi::fps(){ | ||
100 | return 0.0; | 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 | void DvppDecoderApi::setName(string nm){ | 103 | void DvppDecoderApi::setName(string nm){ |
111 | if(m_pDecoder != nullptr){ | 104 | if(m_pDecoder != nullptr){ |
112 | return m_pDecoder->setName(nm); | 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 | \ No newline at end of file | 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 | \ No newline at end of file | 158 | \ No newline at end of file |
src/decoder/dvpp/DvppStreamDecoder.cpp
@@ -668,6 +668,16 @@ void DvppStreamDecoder::Close() { | @@ -668,6 +668,16 @@ void DvppStreamDecoder::Close() { | ||
668 | decode_finished_cbk(m_finishedDecArg); | 668 | decode_finished_cbk(m_finishedDecArg); |
669 | decode_finished_cbk = nullptr; | 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 | void DvppStreamDecoder::doRecode(RecoderInfo& recoderInfo) { | 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,10 +134,17 @@ bool FFRecoder::init(AVStream* stream, AVCodecContext* avctx, const char* outfil | ||
134 | return false; | 134 | return false; |
135 | } | 135 | } |
136 | 136 | ||
137 | - avcodec_copy_context(codec_ctx_, avctx); | ||
138 | - codec_ctx_->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; | ||
139 | m_inStream = stream; | 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 | // [2] 创建输出上下文 | 148 | // [2] 创建输出上下文 |
142 | avformat_alloc_output_context2(&fmt_ctx_, nullptr, nullptr, outfile_name); | 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,8 +161,8 @@ bool FFRecoder::init(AVStream* stream, AVCodecContext* avctx, const char* outfil | ||
154 | 161 | ||
155 | codec_ctx_->time_base = out_stream_->time_base; | 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 | // av_dump_format(fmt_ctx_, out_stream_->id, outfile_name, 1); | 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,8 +182,7 @@ bool FFRecoder::init(AVStream* stream, AVCodecContext* avctx, const char* outfil | ||
175 | void FFRecoder::release() { | 182 | void FFRecoder::release() { |
176 | av_write_trailer(fmt_ctx_); | 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 | av_freep(&fmt_ctx_->streams[0]); | 186 | av_freep(&fmt_ctx_->streams[0]); |
181 | 187 | ||
182 | avio_close(fmt_ctx_->pb); | 188 | avio_close(fmt_ctx_->pb); |
src/decoder/dvpp/depend_headers.h
@@ -27,9 +27,10 @@ extern "C" { | @@ -27,9 +27,10 @@ extern "C" { | ||
27 | #include "libavutil/samplefmt.h" | 27 | #include "libavutil/samplefmt.h" |
28 | #include "libavformat/avformat.h" | 28 | #include "libavformat/avformat.h" |
29 | #include "libavcodec/avcodec.h" | 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,10 +373,6 @@ bool DvppGB28181Decoder::isSurport(FFDecConfig& cfg){ | ||
373 | return true; | 373 | return true; |
374 | } | 374 | } |
375 | 375 | ||
376 | -int DvppGB28181Decoder::getCachedQueueLength(){ | ||
377 | - return m_rtpPtr->GetPsFrameListSize(); | ||
378 | -} | ||
379 | - | ||
380 | DeviceMemory* DvppGB28181Decoder::snapshot() { | 376 | DeviceMemory* DvppGB28181Decoder::snapshot() { |
381 | 377 | ||
382 | DeviceMemory* snapshot_mem = nullptr; | 378 | DeviceMemory* snapshot_mem = nullptr; |
src/decoder/gb28181/DvppGB28181Decoder.h
@@ -42,8 +42,6 @@ public: | @@ -42,8 +42,6 @@ public: | ||
42 | 42 | ||
43 | bool isSurport(FFDecConfig& cfg); | 43 | bool isSurport(FFDecConfig& cfg); |
44 | 44 | ||
45 | - int getCachedQueueLength(); | ||
46 | - | ||
47 | float fps(); | 45 | float fps(); |
48 | 46 | ||
49 | DECODER_TYPE getDecoderType(){ return DECODER_TYPE_DVPP_GB28181; } | 47 | DECODER_TYPE getDecoderType(){ return DECODER_TYPE_DVPP_GB28181; } |
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 | \ No newline at end of file | 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 | \ No newline at end of file | 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 | \ No newline at end of file | 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 | \ No newline at end of file | 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 | \ No newline at end of file | 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,23 +7,35 @@ | ||
7 | 7 | ||
8 | using namespace std; | 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 | public: | 17 | public: |
14 | RTPReceiver2(); | 18 | RTPReceiver2(); |
15 | virtual ~RTPReceiver2(); | 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 | void RequestStreamFailed(); | 29 | void RequestStreamFailed(); |
20 | 30 | ||
21 | int allocRtpPort(); | 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 | void parseTcpData(char* recvBuf, int recvBufSize); | 39 | void parseTcpData(char* recvBuf, int recvBufSize); |
28 | 40 | ||
29 | public: | 41 | public: |
@@ -31,9 +43,24 @@ public: | @@ -31,9 +43,24 @@ public: | ||
31 | uint64_t mRecvCacheSize {0}; | 43 | uint64_t mRecvCacheSize {0}; |
32 | 44 | ||
33 | uint8_t* mRecvRtpBuffer {nullptr}; // 从mRecvCache提取出来的rtp字节流 | 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 | bool m_bRtpExit {false}; | 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 | #endif // _RTP_RECEIVER_H_ | 66 | #endif // _RTP_RECEIVER_H_ |
40 | \ No newline at end of file | 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,7 +191,7 @@ int WebsocketClient::GetMaxRtpPort(){ | ||
191 | return mInfo.getMaxRtpPort(); | 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 | if (check_connect() < 0) { | 195 | if (check_connect() < 0) { |
196 | return -1; | 196 | return -1; |
197 | } | 197 | } |
@@ -204,7 +204,7 @@ int WebsocketClient::InviteUdp(std::string sip_channel_id, int rtp_port, RTPRece | @@ -204,7 +204,7 @@ int WebsocketClient::InviteUdp(std::string sip_channel_id, int rtp_port, RTPRece | ||
204 | return 0; | 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 | if (check_connect() < 0) { | 208 | if (check_connect() < 0) { |
209 | return -1; | 209 | return -1; |
210 | } | 210 | } |
@@ -228,7 +228,7 @@ int WebsocketClient::ByeInvite(std::string sip_channel_id, int rtp_port) { | @@ -228,7 +228,7 @@ int WebsocketClient::ByeInvite(std::string sip_channel_id, int rtp_port) { | ||
228 | return 0; | 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 | std::lock_guard<std::mutex> l(m_receiver_map_mtx); | 232 | std::lock_guard<std::mutex> l(m_receiver_map_mtx); |
233 | string rKey = sip_channel_id + "_" + to_string(rtp_port); | 233 | string rKey = sip_channel_id + "_" + to_string(rtp_port); |
234 | m_receiver_map[rKey] = r; | 234 | m_receiver_map[rKey] = r; |
src/decoder/gb28181/websocket/WebsocketClient.h
@@ -6,7 +6,7 @@ | @@ -6,7 +6,7 @@ | ||
6 | 6 | ||
7 | #include "Message/CatalogParser.h" | 7 | #include "Message/CatalogParser.h" |
8 | 8 | ||
9 | -#include "../rtp/RTPReceiver.h" | 9 | +#include "../rtp2/RTPReceiver2.h" |
10 | 10 | ||
11 | typedef websocketpp::client<websocketpp::config::asio_client> client; | 11 | typedef websocketpp::client<websocketpp::config::asio_client> client; |
12 | typedef websocketpp::config::asio_client::message_type::ptr message_ptr; | 12 | typedef websocketpp::config::asio_client::message_type::ptr message_ptr; |
@@ -32,8 +32,8 @@ public: | @@ -32,8 +32,8 @@ public: | ||
32 | int GetMinRtpPort(); | 32 | int GetMinRtpPort(); |
33 | int GetMaxRtpPort(); | 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 | int ByeInvite(std::string sip_channel_id, int rtp_port); | 38 | int ByeInvite(std::string sip_channel_id, int rtp_port); |
39 | 39 | ||
@@ -56,7 +56,7 @@ private: | @@ -56,7 +56,7 @@ private: | ||
56 | 56 | ||
57 | int msg_parser(websocketpp::connection_hdl hdl, string msg); | 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 | void response_invite_failed(std::string rKey); | 61 | void response_invite_failed(std::string rKey); |
62 | 62 | ||
@@ -70,6 +70,6 @@ private: | @@ -70,6 +70,6 @@ private: | ||
70 | 70 | ||
71 | bool mbClosed{false}; | 71 | bool mbClosed{false}; |
72 | 72 | ||
73 | - std::map<string, RTPReceiver*> m_receiver_map; | 73 | + std::map<string, RTPReceiver2*> m_receiver_map; |
74 | std::mutex m_receiver_map_mtx; | 74 | std::mutex m_receiver_map_mtx; |
75 | }; | 75 | }; |
76 | \ No newline at end of file | 76 | \ No newline at end of file |
src/decoder/interface/AbstractDecoder.h
@@ -27,8 +27,6 @@ public: | @@ -27,8 +27,6 @@ public: | ||
27 | virtual bool getOutResolution( int &width, int &height ) = 0; | 27 | virtual bool getOutResolution( int &width, int &height ) = 0; |
28 | 28 | ||
29 | virtual bool isSurport(FFDecConfig& cfg) = 0; | 29 | virtual bool isSurport(FFDecConfig& cfg) = 0; |
30 | - | ||
31 | - virtual int getCachedQueueLength() = 0; | ||
32 | 30 | ||
33 | virtual float fps() = 0; | 31 | virtual float fps() = 0; |
34 | 32 |
src/decoder/interface/DecoderManager.cpp
@@ -7,7 +7,7 @@ | @@ -7,7 +7,7 @@ | ||
7 | 7 | ||
8 | #ifdef USE_DVPP | 8 | #ifdef USE_DVPP |
9 | #include "../dvpp/DvppDecoderApi.h" | 9 | #include "../dvpp/DvppDecoderApi.h" |
10 | -#include "../gb28181/DvppGB28181Decoder.h" | 10 | +#include "../gb28181/DvppGB28181Decoder2.h" |
11 | #endif | 11 | #endif |
12 | 12 | ||
13 | #include "logger.hpp" | 13 | #include "logger.hpp" |
@@ -61,7 +61,7 @@ AbstractDecoder* DecoderManager::createDecoder(MgrDecConfig config){ | @@ -61,7 +61,7 @@ AbstractDecoder* DecoderManager::createDecoder(MgrDecConfig config){ | ||
61 | if(DECODER_TYPE_DVPP == config.dec_type){ | 61 | if(DECODER_TYPE_DVPP == config.dec_type){ |
62 | dec = new DvppDecoderApi(); | 62 | dec = new DvppDecoderApi(); |
63 | } else if(DECODER_TYPE_DVPP_GB28181 == config.dec_type){ | 63 | } else if(DECODER_TYPE_DVPP_GB28181 == config.dec_type){ |
64 | - dec = new DvppGB28181Decoder(); | 64 | + dec = new DvppGB28181Decoder2(); |
65 | } | 65 | } |
66 | #endif | 66 | #endif |
67 | 67 | ||
@@ -470,23 +470,6 @@ vector<string> DecoderManager::getAllDecodeName(){ | @@ -470,23 +470,6 @@ vector<string> DecoderManager::getAllDecodeName(){ | ||
470 | return decode_names; | 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 | void DecoderManager::releaseDeviceMemory(DeviceMemory* info){ | 473 | void DecoderManager::releaseDeviceMemory(DeviceMemory* info){ |
491 | if(nullptr != info){ | 474 | if(nullptr != info){ |
492 | delete info; | 475 | delete info; |
src/decoder/interface/DecoderManager.h
@@ -230,15 +230,6 @@ public: | @@ -230,15 +230,6 @@ public: | ||
230 | vector<string> getAllDecodeName(); | 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 | * 接口:releaseDeviceMemory | 233 | * 接口:releaseDeviceMemory |
243 | * 功能:释放视频快照信息 | 234 | * 功能:释放视频快照信息 |
244 | * 参数:DeviceMemory* info 视频快照信息 | 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 | \ No newline at end of file | 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 | \ No newline at end of file | 0 | \ No newline at end of file |