1 /*
2 * Copyright (C) 2023-2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #define MEDIA_PLUGIN
17 #define HST_LOG_TAG "FfmpegDemuxerPlugin"
18 #include <unistd.h>
19 #include <algorithm>
20 #include <malloc.h>
21 #include <string>
22 #include <sstream>
23 #include <iomanip>
24 #include <map>
25 #include <fstream>
26 #include <chrono>
27 #include <limits>
28 #include "avcodec_trace.h"
29 #include "securec.h"
30 #include "ffmpeg_format_helper.h"
31 #include "ffmpeg_utils.h"
32 #include "buffer/avbuffer.h"
33 #include "plugin/plugin_buffer.h"
34 #include "plugin/plugin_definition.h"
35 #include "common/log.h"
36 #include "meta/video_types.h"
37 #include "demuxer_log_compressor.h"
38 #include "ffmpeg_demuxer_plugin.h"
39 #include "meta/format.h"
40 #include "syspara/parameters.h"
41
42 namespace {
43 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_DOMAIN_DEMUXER, "FfmpegDemuxerPlugin" };
44 }
45
46 namespace OHOS {
47 namespace Media {
48 namespace Plugins {
49 namespace Ffmpeg {
50 const uint32_t DEFAULT_READ_SIZE = 4096;
51 const uint32_t DEFAULT_SNIFF_SIZE = 4096 * 4;
52 const int32_t MP3_PROBE_SCORE_LIMIT = 5;
53 const int32_t DEF_PROBE_SCORE_LIMIT = 50;
54 const uint32_t RANK_MAX = 100;
55 const int32_t NAL_START_CODE_SIZE = 4;
56 const uint32_t INIT_DOWNLOADS_DATA_SIZE_THRESHOLD = 2 * 1024 * 1024;
57 const int64_t LIVE_FLV_PROBE_SIZE = 100 * 1024 * 2;
58 const uint32_t DEFAULT_CACHE_LIMIT = 50 * 1024 * 1024; // 50M
59 const int64_t INIT_TIME_THRESHOLD = 1000;
60 const uint32_t ID3V2_HEADER_SIZE = 10;
61 const int32_t MS_TO_US = 1000;
62 const int32_t MS_TO_NS = 1000 * 1000;
63 const uint32_t REFERENCE_PARSER_PTS_LIST_UPPER_LIMIT = 200000;
64 const int DEFAULT_CHANNEL_CNT = 3;
65 const int FLV_READ_SIZE_LIMIT_FACTOR = 2;
66 const int FLV_READ_SIZE_LIMIT_DEFAULT = 4096 * 2160 * 3 * 2;
67 const char* PLUGIN_NAME_PREFIX = "avdemux_";
68 const char* PLUGIN_NAME_MP3 = "mp3";
69 const char* PLUGIN_NAME_MPEGPS = "mpeg";
70 const uint8_t START_CODE[] = {0x00, 0x00, 0x01};
71 const int32_t MPEGPS_START_CODE_SIZE = 4;
72 const uint8_t MPEGPS_START_CODE[] = {0x00, 0x00, 0x01, 0xBA};
73
74 // id3v2 tag position
75 const int32_t POS_0 = 0;
76 const int32_t POS_1 = 1;
77 const int32_t POS_2 = 2;
78 const int32_t POS_3 = 3;
79 const int32_t POS_4 = 4;
80 const int32_t POS_5 = 5;
81 const int32_t POS_6 = 6;
82 const int32_t POS_7 = 7;
83 const int32_t POS_8 = 8;
84 const int32_t POS_9 = 9;
85 const int32_t POS_14 = 14;
86 const int32_t POS_16 = 16;
87 const int32_t POS_21 = 21;
88 const int32_t POS_24 = 24;
89 const int32_t POS_FF = 0xff;
90 const int32_t LEN_MASK = 0x7f;
91 const int32_t TAG_MASK = 0x80;
92 const int32_t TAG_VERSION_MASK = 0x10;
93
94 const std::vector<AVCodecID> g_streamContainedXPS = {
95 AV_CODEC_ID_H264,
96 AV_CODEC_ID_HEVC,
97 AV_CODEC_ID_VVC
98 };
99 namespace {
100 std::map<std::string, std::shared_ptr<AVInputFormat>> g_pluginInputFormat;
101 std::mutex g_mtx;
102
103 int Sniff(const std::string& pluginName, std::shared_ptr<DataSource> dataSource);
104 int SniffWithSize(const std::string& pluginName, std::shared_ptr<DataSource> dataSource, int probSize);
105 int SniffMPEGPS(const std::string& pluginName, std::shared_ptr<DataSource> dataSource);
106
107 Status RegisterPlugins(const std::shared_ptr<Register>& reg);
108
109 void ReplaceDelimiter(const std::string &delmiters, char newDelimiter, std::string &str);
110
FreeAVPacket(AVPacket * pkt)111 void FreeAVPacket(AVPacket* pkt)
112 {
113 av_packet_free(&pkt);
114 pkt = nullptr;
115 }
116
117 static const std::map<SeekMode, int32_t> g_seekModeToFFmpegSeekFlags = {
118 { SeekMode::SEEK_PREVIOUS_SYNC, AVSEEK_FLAG_BACKWARD },
119 { SeekMode::SEEK_NEXT_SYNC, AVSEEK_FLAG_FRAME },
120 { SeekMode::SEEK_CLOSEST_SYNC, AVSEEK_FLAG_FRAME | AVSEEK_FLAG_BACKWARD }
121 };
122
123 static const std::map<AVCodecID, std::string> g_bitstreamFilterMap = {
124 { AV_CODEC_ID_H264, "h264_mp4toannexb" },
125 };
126
127 static const std::map<AVCodecID, VideoStreamType> g_streamParserMap = {
128 { AV_CODEC_ID_HEVC, VideoStreamType::HEVC },
129 { AV_CODEC_ID_VVC, VideoStreamType::VVC },
130 };
131
132 static const std::vector<AVMediaType> g_streamMediaTypeVec = {
133 AVMEDIA_TYPE_AUDIO,
134 AVMEDIA_TYPE_VIDEO,
135 AVMEDIA_TYPE_SUBTITLE,
136 AVMEDIA_TYPE_TIMEDMETA,
137 AVMEDIA_TYPE_AUXILIARY
138 };
139
140 static const std::unordered_map<std::string, PluginSnifferFunc> g_pluginSnifferMap = {
141 {std::string(PLUGIN_NAME_MPEGPS), SniffMPEGPS},
142 };
143
HaveValidParser(const AVCodecID codecId)144 bool HaveValidParser(const AVCodecID codecId)
145 {
146 return g_streamParserMap.count(codecId) != 0;
147 }
148
GetFileDuration(const AVFormatContext & avFormatContext)149 int64_t GetFileDuration(const AVFormatContext& avFormatContext)
150 {
151 int64_t duration = 0;
152 const AVDictionaryEntry *metaDuration = av_dict_get(avFormatContext.metadata, "DURATION", NULL, 0);
153 int64_t us;
154 if (metaDuration != nullptr && (av_parse_time(&us, metaDuration->value, 1) == 0)) {
155 if (us > duration) {
156 MEDIA_LOG_D("Get duration from file");
157 duration = us;
158 }
159 }
160
161 if (duration <= 0) {
162 for (uint32_t i = 0; i < avFormatContext.nb_streams; ++i) {
163 auto streamDuration = (ConvertTimeFromFFmpeg(avFormatContext.streams[i]->duration,
164 avFormatContext.streams[i]->time_base)) / 1000; // us
165 if (streamDuration > duration) {
166 MEDIA_LOG_D("Get duration from stream " PUBLIC_LOG_U32, i);
167 duration = streamDuration;
168 }
169 }
170 }
171 return duration;
172 }
173
GetStreamDuration(const AVStream & avStream)174 int64_t GetStreamDuration(const AVStream& avStream)
175 {
176 int64_t duration = 0;
177 const AVDictionaryEntry *metaDuration = av_dict_get(avStream.metadata, "DURATION", NULL, 0);
178 int64_t us;
179 if (metaDuration != nullptr && (av_parse_time(&us, metaDuration->value, 1) == 0)) {
180 if (us > duration) {
181 MEDIA_LOG_D("Get duration from stream");
182 duration = us;
183 }
184 }
185 return duration;
186 }
187
CheckStartTime(const AVFormatContext * formatContext,const AVStream * stream,int64_t & timeStamp,int64_t seekTime)188 bool CheckStartTime(const AVFormatContext *formatContext, const AVStream *stream, int64_t &timeStamp, int64_t seekTime)
189 {
190 int64_t startTime = 0;
191 int64_t num = 1000; // ms convert us
192 FALSE_RETURN_V_MSG_E(stream != nullptr, false, "String is nullptr");
193 if (stream->start_time != AV_NOPTS_VALUE) {
194 startTime = stream->start_time;
195 if (timeStamp > 0 && startTime > INT64_MAX - timeStamp) {
196 MEDIA_LOG_E("Seek value overflow with start time: " PUBLIC_LOG_D64 " timeStamp: " PUBLIC_LOG_D64,
197 startTime, timeStamp);
198 return false;
199 }
200 }
201 MEDIA_LOG_D("StartTime: " PUBLIC_LOG_D64, startTime);
202 int64_t fileDuration = formatContext->duration;
203 int64_t streamDuration = stream->duration;
204 if (fileDuration == AV_NOPTS_VALUE || fileDuration <= 0) {
205 fileDuration = GetFileDuration(*formatContext);
206 }
207 if (streamDuration == AV_NOPTS_VALUE || streamDuration <= 0) {
208 streamDuration = GetStreamDuration(*stream);
209 }
210 MEDIA_LOG_D("File duration=" PUBLIC_LOG_D64 ", stream duration=" PUBLIC_LOG_D64, fileDuration, streamDuration);
211 // when timestemp out of file duration, return error
212 if (fileDuration > 0 && seekTime > fileDuration / num) { // fileDuration us
213 MEDIA_LOG_E("Seek to timestamp=" PUBLIC_LOG_D64 " failed, max=" PUBLIC_LOG_D64, timeStamp, fileDuration);
214 return false;
215 }
216 // when timestemp out of stream duration, seek to end of stream
217 if (streamDuration > 0 && timeStamp > streamDuration) {
218 MEDIA_LOG_W("Out of stream, seek to " PUBLIC_LOG_D64, timeStamp);
219 timeStamp = streamDuration;
220 }
221 if (stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO || stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO ||
222 stream->codecpar->codec_type == AVMEDIA_TYPE_AUXILIARY) {
223 MEDIA_LOG_D("Reset timeStamp by start time [" PUBLIC_LOG_D64 "/" PUBLIC_LOG_D64 "]",
224 timeStamp, timeStamp + startTime);
225 timeStamp += startTime;
226 }
227 return true;
228 }
229
ConvertFlagsToFFmpeg(AVStream * avStream,int64_t ffTime,SeekMode mode,int64_t seekTime)230 int ConvertFlagsToFFmpeg(AVStream *avStream, int64_t ffTime, SeekMode mode, int64_t seekTime)
231 {
232 FALSE_RETURN_V_MSG_E(avStream != nullptr && avStream->codecpar != nullptr, -1, "AVStream is nullptr");
233 if (avStream->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE && ffTime == 0) {
234 return AVSEEK_FLAG_FRAME;
235 }
236 if (FFmpegFormatHelper::IsAudioType(*avStream) && seekTime != 0) {
237 int64_t streamDuration = avStream->duration;
238 if (streamDuration == AV_NOPTS_VALUE || streamDuration <= 0) {
239 streamDuration = GetStreamDuration(*avStream);
240 }
241 // When the seekTime is within the last 0.5s, still use BACKWARD mode to ensure consistent func behavior.
242 int64_t buffering = ConvertTimeToFFmpeg(500 * MS_TO_NS, avStream->time_base); // 0.5s
243 if (streamDuration > 0 && (streamDuration < buffering || ffTime >= streamDuration - buffering)) {
244 return AVSEEK_FLAG_BACKWARD;
245 }
246 return g_seekModeToFFmpegSeekFlags.at(mode);
247 }
248 if (!FFmpegFormatHelper::IsVideoType(*avStream) || seekTime == 0) {
249 return AVSEEK_FLAG_BACKWARD;
250 }
251 if (mode == SeekMode::SEEK_NEXT_SYNC || mode == SeekMode::SEEK_PREVIOUS_SYNC) {
252 return g_seekModeToFFmpegSeekFlags.at(mode);
253 }
254 // find closest time in next and prev
255 int keyFrameNext = av_index_search_timestamp(avStream, ffTime, AVSEEK_FLAG_FRAME);
256 FALSE_RETURN_V_MSG_E(keyFrameNext >= 0, AVSEEK_FLAG_BACKWARD, "Not next key frame");
257
258 int keyFramePrev = av_index_search_timestamp(avStream, ffTime, AVSEEK_FLAG_BACKWARD);
259 FALSE_RETURN_V_MSG_E(keyFramePrev >= 0, AVSEEK_FLAG_FRAME, "Not pre key frame");
260
261 int64_t ffTimePrev = CalculateTimeByFrameIndex(avStream, keyFramePrev);
262 int64_t ffTimeNext = CalculateTimeByFrameIndex(avStream, keyFrameNext);
263 MEDIA_LOG_D("FfTime=" PUBLIC_LOG_D64 ", ffTimePrev=" PUBLIC_LOG_D64 ", ffTimeNext=" PUBLIC_LOG_D64,
264 ffTime, ffTimePrev, ffTimeNext);
265 if (ffTimePrev == ffTimeNext || (ffTimeNext - ffTime < ffTime - ffTimePrev)) {
266 return AVSEEK_FLAG_FRAME;
267 } else {
268 return AVSEEK_FLAG_BACKWARD;
269 }
270 }
271
IsSupportedTrackType(const AVStream & avStream)272 bool IsSupportedTrackType(const AVStream& avStream)
273 {
274 return (std::find(g_streamMediaTypeVec.cbegin(), g_streamMediaTypeVec.cend(),
275 avStream.codecpar->codec_type) != g_streamMediaTypeVec.cend());
276 }
277
IsSupportedTrack(const AVStream & avStream)278 bool IsSupportedTrack(const AVStream& avStream)
279 {
280 FALSE_RETURN_V_MSG_E(avStream.codecpar != nullptr, false, "Codecpar is nullptr");
281 if (!IsSupportedTrackType(avStream)) {
282 MEDIA_LOG_E("Unsupport track type: " PUBLIC_LOG_D32, avStream.codecpar->codec_type);
283 return false;
284 }
285 if (avStream.codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
286 if (avStream.codecpar->codec_id == AV_CODEC_ID_RAWVIDEO) {
287 MEDIA_LOG_E("Unsupport raw video track");
288 return false;
289 }
290 if (FFmpegFormatHelper::IsImageTrack(avStream)) {
291 MEDIA_LOG_E("Unsupport image track");
292 return false;
293 }
294 }
295 return true;
296 }
297
IsBeginAsAnnexb(const uint8_t * sample,int32_t size)298 bool IsBeginAsAnnexb(const uint8_t *sample, int32_t size)
299 {
300 if (size < NAL_START_CODE_SIZE) {
301 return false;
302 }
303 bool hasShortStartCode = (sample[0] == 0 && sample[1] == 0 && sample[2] == 1); // 001
304 bool hasLongStartCode = (sample[0] == 0 && sample[1] == 0 && sample[2] == 0 && sample[3] == 1); // 0001
305 return hasShortStartCode || hasLongStartCode;
306 }
307
GetNaluSize(const uint8_t * nalStart)308 int32_t GetNaluSize(const uint8_t *nalStart)
309 {
310 return static_cast<int32_t>(
311 (nalStart[POS_3]) | (nalStart[POS_2] << POS_8) | (nalStart[POS_1] << POS_16) | (nalStart[POS_0] << POS_24));
312 }
313
IsHvccSyncFrame(const uint8_t * sample,int32_t size)314 bool IsHvccSyncFrame(const uint8_t *sample, int32_t size)
315 {
316 const uint8_t* nalStart = sample;
317 const uint8_t* end = nalStart + size;
318 int32_t sizeLen = NAL_START_CODE_SIZE;
319 int32_t naluSize = 0;
320 naluSize = GetNaluSize(nalStart);
321 if (naluSize <= 0 || nalStart > end - sizeLen) {
322 return false;
323 }
324 nalStart = nalStart + sizeLen;
325 while (nalStart < end) {
326 uint8_t naluType = static_cast<uint8_t>((nalStart[0] & 0x7E) >> 1);
327 if (naluType > 0x10 && naluType <= 0x17) {
328 return true;
329 }
330 if (nalStart > end - naluSize) {
331 return false;
332 }
333 nalStart = nalStart + naluSize;
334 if (nalStart > end - sizeLen) {
335 return false;
336 }
337 naluSize = GetNaluSize(nalStart);
338 if (naluSize < 0) {
339 return false;
340 }
341 nalStart = nalStart + sizeLen;
342 }
343 return false;
344 }
345
FindNalStartCode(const uint8_t * start,const uint8_t * end,int32_t & startCodeLen)346 const uint8_t* FindNalStartCode(const uint8_t *start, const uint8_t *end, int32_t &startCodeLen)
347 {
348 startCodeLen = sizeof(START_CODE);
349 auto *iter = std::search(start, end, START_CODE, START_CODE + startCodeLen);
350 if (iter != end && (iter > start && *(iter - 1) == 0x00)) {
351 ++startCodeLen;
352 return iter - 1;
353 }
354 return iter;
355 }
356
IsAnnexbSyncFrame(const uint8_t * sample,int32_t size)357 bool IsAnnexbSyncFrame(const uint8_t *sample, int32_t size)
358 {
359 const uint8_t* nalStart = sample;
360 const uint8_t* end = nalStart + size;
361 const uint8_t* nalEnd = nullptr;
362 int32_t startCodeLen = 0;
363 nalStart = FindNalStartCode(nalStart, end, startCodeLen);
364 if (nalStart > end - startCodeLen) {
365 return false;
366 }
367 nalStart = nalStart + startCodeLen;
368 while (nalStart < end) {
369 nalEnd = FindNalStartCode(nalStart, end, startCodeLen);
370 uint8_t naluType = static_cast<uint8_t>((nalStart[0] & 0x7E) >> 1);
371 if (naluType > 0x10 && naluType <= 0x17) {
372 return true;
373 }
374 if (nalEnd > end - startCodeLen) {
375 return false;
376 }
377 nalStart = nalEnd + startCodeLen;
378 }
379 return false;
380 }
381
IsHevcSyncFrame(const uint8_t * sample,int32_t size)382 bool IsHevcSyncFrame(const uint8_t *sample, int32_t size)
383 {
384 if (size < NAL_START_CODE_SIZE) {
385 return false;
386 }
387 if (IsBeginAsAnnexb(sample, size)) {
388 return IsAnnexbSyncFrame(sample, size);
389 } else {
390 return IsHvccSyncFrame(sample, size);
391 }
392 }
393
FfmpegLogPrint(void * avcl,int level,const char * fmt,va_list vl)394 void FfmpegLogPrint(void* avcl, int level, const char* fmt, va_list vl)
395 {
396 (void)avcl;
397 char buf[500] = {0}; // 500
398 int ret = vsnprintf_s(buf, sizeof(buf), sizeof(buf) - 1, fmt, vl);
399 if (ret < 0) {
400 return;
401 }
402 switch (level) {
403 case AV_LOG_WARNING:
404 MEDIA_LOG_D("[FFLogW] " PUBLIC_LOG_S, buf);
405 break;
406 case AV_LOG_ERROR:
407 MEDIA_LOG_E("[FFLogE] " PUBLIC_LOG_S, buf);
408 break;
409 case AV_LOG_FATAL:
410 MEDIA_LOG_E("[FFLogF] " PUBLIC_LOG_S, buf);
411 break;
412 case AV_LOG_PANIC:
413 MEDIA_LOG_E("[FFLogP] " PUBLIC_LOG_S, buf);
414 break;
415 case AV_LOG_INFO:
416 MEDIA_LOG_D("[FFLogI] " PUBLIC_LOG_S, buf);
417 break;
418 case AV_LOG_DEBUG:
419 MEDIA_LOG_D("[FFLogD] " PUBLIC_LOG_S, buf);
420 break;
421 default:
422 break;
423 }
424 }
425 } // namespace
426
427 std::atomic<int> FFmpegDemuxerPlugin::readatIndex_ = 0;
FFmpegDemuxerPlugin(std::string name)428 FFmpegDemuxerPlugin::FFmpegDemuxerPlugin(std::string name)
429 : DemuxerPlugin(std::move(name)),
430 seekable_(Seekable::SEEKABLE),
431 ioContext_(),
432 selectedTrackIds_(),
433 cacheQueue_("cacheQueue"),
434 parserRefIoContext_()
435 {
436 std::lock_guard<std::shared_mutex> lock(sharedMutex_);
437 MEDIA_LOG_D("In");
438 #ifndef _WIN32
439 (void)mallopt(M_SET_THREAD_CACHE, M_THREAD_CACHE_DISABLE);
440 (void)mallopt(M_DELAYED_FREE, M_DELAYED_FREE_DISABLE);
441 #endif
442 av_log_set_callback(FfmpegLogPrint);
443 #ifdef BUILD_ENG_VERSION
444 std::string dumpModeStr = OHOS::system::GetParameter("FFmpegDemuxerPlugin.dump", "0");
445 dumpMode_ = static_cast<DumpMode>(strtoul(dumpModeStr.c_str(), nullptr, 2)); // 2 is binary
446 MEDIA_LOG_D("Dump mode = %s(%lu)", dumpModeStr.c_str(), dumpMode_);
447 #endif
448 MEDIA_LOG_D("Out");
449 }
450
~FFmpegDemuxerPlugin()451 FFmpegDemuxerPlugin::~FFmpegDemuxerPlugin()
452 {
453 std::lock_guard<std::shared_mutex> lock(sharedMutex_);
454 MEDIA_LOG_D("In");
455 ReleaseFFmpegReadLoop();
456 #ifndef _WIN32
457 (void)mallopt(M_FLUSH_THREAD_CACHE, 0);
458 #endif
459 formatContext_ = nullptr;
460 pluginImpl_ = nullptr;
461 for (auto &item : avbsfContexts_) {
462 if (item.second != nullptr) {
463 item.second = nullptr;
464 }
465 }
466 streamParsers_ = nullptr;
467 referenceParser_ = nullptr;
468 parserRefCtx_ = nullptr;
469 selectedTrackIds_.clear();
470 for (auto item : videoFirstFrameMap_) {
471 if (item.second != nullptr) {
472 FreeAVPacket(item.second);
473 }
474 }
475 MEDIA_LOG_D("Out");
476 }
477
Dump(const DumpParam & dumpParam)478 void FFmpegDemuxerPlugin::Dump(const DumpParam &dumpParam)
479 {
480 std::string path;
481 switch (dumpParam.mode) {
482 case DUMP_READAT_INPUT:
483 path = "Readat_index." + std::to_string(dumpParam.index) + "_offset." + std::to_string(dumpParam.offset) +
484 "_size." + std::to_string(dumpParam.size);
485 break;
486 case DUMP_AVPACKET_OUTPUT:
487 path = "AVPacket_index." + std::to_string(dumpParam.index) + "_track." +
488 std::to_string(dumpParam.trackId) + "_pts." + std::to_string(dumpParam.pts) + "_pos." +
489 std::to_string(dumpParam.pos);
490 break;
491 case DUMP_AVBUFFER_OUTPUT:
492 path = "AVBuffer_track." + std::to_string(dumpParam.trackId) + "_index." +
493 std::to_string(dumpParam.index) + "_pts." + std::to_string(dumpParam.pts);
494 break;
495 default:
496 return;
497 }
498 std::ofstream ofs;
499 path = "/data/ff_dump/" + path;
500 ofs.open(path, std::ios::out); // | std::ios::app
501 if (ofs.is_open()) {
502 ofs.write(reinterpret_cast<char*>(dumpParam.buf), dumpParam.size);
503 ofs.close();
504 }
505 MEDIA_LOG_D("Dump path:" PUBLIC_LOG_S, path.c_str());
506 }
507
GetProbeSize(int32_t & offset,int32_t & size)508 bool FFmpegDemuxerPlugin::GetProbeSize(int32_t &offset, int32_t &size)
509 {
510 offset = 0;
511 size = 5000000; // 5000000 ff init probe size
512 return true;
513 }
514
ResetParam()515 void FFmpegDemuxerPlugin::ResetParam()
516 {
517 readatIndex_ = 0;
518 avpacketIndex_ = 0;
519 ioContext_.offset = 0;
520 ioContext_.retry = false;
521 ioContext_.eos = false;
522 ioContext_.initDownloadDataSize = 0;
523 mediaInfo_ = MediaInfo();
524 for (size_t i = 0; i < selectedTrackIds_.size(); ++i) {
525 cacheQueue_.RemoveTrackQueue(selectedTrackIds_[i]);
526 }
527 selectedTrackIds_.clear();
528 checkedTrackIds_.clear();
529 pluginImpl_.reset();
530 formatContext_.reset();
531
532 streamParsers_.reset();
533 for (auto item : avbsfContexts_) {
534 item.second.reset();
535 }
536 trackMtx_.clear();
537 trackDfxInfoMap_.clear();
538 }
539
Reset()540 Status FFmpegDemuxerPlugin::Reset()
541 {
542 std::lock_guard<std::shared_mutex> lock(sharedMutex_);
543 MEDIA_LOG_D("In");
544 ReleaseFFmpegReadLoop();
545 ResetParam();
546 return Status::OK;
547 }
548
InitBitStreamContext(const AVStream & avStream)549 void FFmpegDemuxerPlugin::InitBitStreamContext(const AVStream& avStream)
550 {
551 FALSE_RETURN_MSG(avStream.codecpar != nullptr, "Codecpar is nullptr");
552 AVCodecID codecID = avStream.codecpar->codec_id;
553 MEDIA_LOG_D("For track " PUBLIC_LOG_D32, avStream.index);
554 FALSE_RETURN_MSG(g_bitstreamFilterMap.count(codecID) != 0, "Can not match any BitStreamContext");
555 const AVBitStreamFilter* avBitStreamFilter = av_bsf_get_by_name(g_bitstreamFilterMap.at(codecID).c_str());
556
557 FALSE_RETURN_MSG((avBitStreamFilter != nullptr), "Call av_bsf_get_by_name failed for" PUBLIC_LOG_S,
558 g_bitstreamFilterMap.at(codecID).c_str());
559
560 if (avbsfContexts_.count(avStream.index) <= 0 || !avbsfContexts_[avStream.index]) {
561 AVBSFContext* avbsfContext {nullptr};
562 int ret = av_bsf_alloc(avBitStreamFilter, &avbsfContext);
563 FALSE_RETURN_MSG((ret >= 0 && avbsfContext != nullptr),
564 "Call av_bsf_alloc failed, err:" PUBLIC_LOG_S, AVStrError(ret).c_str());
565
566 ret = avcodec_parameters_copy(avbsfContext->par_in, avStream.codecpar);
567 FALSE_RETURN_MSG((ret >= 0), "Call avcodec_parameters_copy failed, err:" PUBLIC_LOG_S, AVStrError(ret).c_str());
568
569 ret = av_bsf_init(avbsfContext);
570 FALSE_RETURN_MSG((ret >= 0), "Call av_bsf_init failed, err:" PUBLIC_LOG_S, AVStrError(ret).c_str());
571
572 avbsfContexts_[avStream.index] = std::shared_ptr<AVBSFContext>(avbsfContext, [](AVBSFContext* ptr) {
573 if (ptr) {
574 av_bsf_free(&ptr);
575 }
576 });
577 }
578 FALSE_RETURN_MSG(avbsfContexts_[avStream.index] != nullptr,
579 "Stream " PUBLIC_LOG_S " will not be converted to annexb", g_bitstreamFilterMap.at(codecID).c_str());
580 MEDIA_LOG_D("Track " PUBLIC_LOG_D32 " will convert to annexb", avStream.index);
581 }
582
ConvertAvcToAnnexb(AVPacket & pkt)583 Status FFmpegDemuxerPlugin::ConvertAvcToAnnexb(AVPacket& pkt)
584 {
585 int32_t trackId = pkt.stream_index;
586 int ret = av_bsf_send_packet(avbsfContexts_[trackId].get(), &pkt);
587 FALSE_RETURN_V_MSG_E(ret >= 0, Status::ERROR_UNKNOWN,
588 "Call av_bsf_send_packet failed, err:" PUBLIC_LOG_S, AVStrError(ret).c_str());
589 av_packet_unref(&pkt);
590
591 ret = av_bsf_receive_packet(avbsfContexts_[trackId].get(), &pkt);
592 FALSE_RETURN_V_MSG_E(ret >= 0, Status::ERROR_PACKET_CONVERT_FAILED,
593 "Call av_bsf_receive_packet failed, err:" PUBLIC_LOG_S, AVStrError(ret).c_str());
594 return Status::OK;
595 }
596
ConvertHevcToAnnexb(AVPacket & pkt,std::shared_ptr<SamplePacket> samplePacket)597 Status FFmpegDemuxerPlugin::ConvertHevcToAnnexb(AVPacket& pkt, std::shared_ptr<SamplePacket> samplePacket)
598 {
599 size_t cencInfoSize = 0;
600 uint8_t *cencInfo = av_packet_get_side_data(samplePacket->pkts[0], AV_PKT_DATA_ENCRYPTION_INFO, &cencInfoSize);
601 streamParsers_->ConvertPacketToAnnexb(pkt.stream_index, &(pkt.data), pkt.size, cencInfo, cencInfoSize, false);
602 if (NeedCombineFrame(samplePacket->pkts[0]->stream_index) &&
603 streamParsers_->IsSyncFrame(pkt.stream_index, pkt.data, pkt.size)) {
604 pkt.flags = static_cast<int32_t>(static_cast<uint32_t>(pkt.flags) | static_cast<uint32_t>(AV_PKT_FLAG_KEY));
605 }
606 return Status::OK;
607 }
608
ConvertVvcToAnnexb(AVPacket & pkt,std::shared_ptr<SamplePacket> samplePacket)609 Status FFmpegDemuxerPlugin::ConvertVvcToAnnexb(AVPacket& pkt, std::shared_ptr<SamplePacket> samplePacket)
610 {
611 streamParsers_->ConvertPacketToAnnexb(pkt.stream_index, &(pkt.data), pkt.size, nullptr, 0, false);
612 return Status::OK;
613 }
614
WriteBuffer(std::shared_ptr<AVBuffer> outBuffer,const uint8_t * writeData,uint32_t writeSize)615 Status FFmpegDemuxerPlugin::WriteBuffer(
616 std::shared_ptr<AVBuffer> outBuffer, const uint8_t *writeData, uint32_t writeSize)
617 {
618 FALSE_RETURN_V_MSG_E(outBuffer != nullptr, Status::ERROR_NULL_POINTER, "Buffer is nullptr");
619 if (writeData != nullptr && writeSize > 0) {
620 FALSE_RETURN_V_MSG_E(outBuffer->memory_ != nullptr, Status::ERROR_NULL_POINTER, "Memory is nullptr");
621 int32_t ret = outBuffer->memory_->Write(writeData, writeSize, 0);
622 FALSE_RETURN_V_MSG_E(ret >= 0, Status::ERROR_INVALID_OPERATION, "Memory write failed");
623 }
624
625 MEDIA_LOG_D("CurrentBuffer: [" PUBLIC_LOG_D64 "/" PUBLIC_LOG_D64 "/" PUBLIC_LOG_U32 "]",
626 outBuffer->pts_, outBuffer->duration_, outBuffer->flag_);
627 return Status::OK;
628 }
629
SetDrmCencInfo(std::shared_ptr<AVBuffer> sample,std::shared_ptr<SamplePacket> samplePacket)630 Status FFmpegDemuxerPlugin::SetDrmCencInfo(
631 std::shared_ptr<AVBuffer> sample, std::shared_ptr<SamplePacket> samplePacket)
632 {
633 FALSE_RETURN_V_MSG_E(sample != nullptr && sample->memory_ != nullptr, Status::ERROR_INVALID_OPERATION,
634 "Sample is nullptr");
635 FALSE_RETURN_V_MSG_E((samplePacket != nullptr && samplePacket->pkts.size() > 0), Status::ERROR_INVALID_OPERATION,
636 "Packet is nullptr");
637 FALSE_RETURN_V_MSG_E((samplePacket->pkts[0] != nullptr && samplePacket->pkts[0]->size >= 0),
638 Status::ERROR_INVALID_OPERATION, "Packet empty");
639
640 size_t cencInfoSize = 0;
641 MetaDrmCencInfo *cencInfo = (MetaDrmCencInfo *)av_packet_get_side_data(samplePacket->pkts[0],
642 AV_PKT_DATA_ENCRYPTION_INFO, &cencInfoSize);
643 if ((cencInfo != nullptr) && (cencInfoSize != 0)) {
644 std::vector<uint8_t> drmCencVec(reinterpret_cast<uint8_t *>(cencInfo),
645 (reinterpret_cast<uint8_t *>(cencInfo)) + sizeof(MetaDrmCencInfo));
646 sample->meta_->SetData(Media::Tag::DRM_CENC_INFO, std::move(drmCencVec));
647 }
648 return Status::OK;
649 }
650
NeedCombineFrame(uint32_t trackId)651 bool FFmpegDemuxerPlugin::NeedCombineFrame(uint32_t trackId)
652 {
653 FALSE_RETURN_V_MSG_E(formatContext_ != nullptr, false, "AVFormatContext is nullptr");
654 return (fileType_ == FileType::MPEGTS && formatContext_->streams[trackId]->codecpar->codec_id == AV_CODEC_ID_HEVC);
655 }
656
CombinePackets(std::shared_ptr<SamplePacket> samplePacket)657 AVPacket* FFmpegDemuxerPlugin::CombinePackets(std::shared_ptr<SamplePacket> samplePacket)
658 {
659 AVPacket *tempPkt = nullptr;
660 if (NeedCombineFrame(samplePacket->pkts[0]->stream_index) && samplePacket->pkts.size() > 1) {
661 int totalSize = 0;
662 for (auto pkt : samplePacket->pkts) {
663 FALSE_RETURN_V_MSG_E(pkt != nullptr, nullptr, "AVPacket is nullptr");
664 totalSize += pkt->size;
665 }
666 tempPkt = av_packet_alloc();
667 FALSE_RETURN_V_MSG_E(tempPkt != nullptr, nullptr, "Temp packet is nullptr");
668 int ret = av_new_packet(tempPkt, totalSize);
669 FALSE_RETURN_V_MSG_E(ret >= 0, nullptr, "Call av_new_packet failed");
670 av_packet_copy_props(tempPkt, samplePacket->pkts[0]);
671 int offset = 0;
672 bool copySuccess = true;
673 for (auto pkt : samplePacket->pkts) {
674 if (pkt == nullptr || tempPkt == nullptr || tempPkt->data == nullptr || pkt->data == nullptr) {
675 copySuccess = false;
676 MEDIA_LOG_E("Cache packet or data is nullptr");
677 break;
678 }
679 if (offset < 0 || pkt->size < 0 || offset > INT_MAX - pkt->size || offset + pkt->size > totalSize) {
680 copySuccess = false;
681 MEDIA_LOG_E("Memcpy param invalid: totalSize=" PUBLIC_LOG_D32 ", offset=" PUBLIC_LOG_D32 ", pkt->size="
682 PUBLIC_LOG_D32, totalSize, offset, pkt->size);
683 break;
684 }
685 ret = memcpy_s(tempPkt->data + offset, tempPkt->size - offset, pkt->data, pkt->size);
686 if (ret != EOK) {
687 copySuccess = false;
688 MEDIA_LOG_E("Memcpy failed, ret:" PUBLIC_LOG_D32, ret);
689 break;
690 }
691 offset += pkt->size;
692 }
693 if (!copySuccess) {
694 FreeAVPacket(tempPkt);
695 return nullptr;
696 }
697 tempPkt->size = totalSize;
698 MEDIA_LOG_D("Combine " PUBLIC_LOG_ZU " packets, total size=" PUBLIC_LOG_D32,
699 samplePacket->pkts.size(), totalSize);
700 } else {
701 tempPkt = samplePacket->pkts[0];
702 }
703 return tempPkt;
704 }
705
ConvertPacketToAnnexb(std::shared_ptr<AVBuffer> sample,AVPacket * srcAVPacket,std::shared_ptr<SamplePacket> dstSamplePacket)706 Status FFmpegDemuxerPlugin::ConvertPacketToAnnexb(std::shared_ptr<AVBuffer> sample, AVPacket* srcAVPacket,
707 std::shared_ptr<SamplePacket> dstSamplePacket)
708 {
709 Status ret = Status::OK;
710 if (dstSamplePacket->isAnnexb) {
711 MEDIA_LOG_D("Has converted");
712 return ret;
713 }
714 auto codecId = formatContext_->streams[srcAVPacket->stream_index]->codecpar->codec_id;
715 if (codecId == AV_CODEC_ID_HEVC && streamParsers_ != nullptr &&
716 streamParsers_->ParserIsInited(srcAVPacket->stream_index)) {
717 ret = ConvertHevcToAnnexb(*srcAVPacket, dstSamplePacket);
718 SetDropTag(*srcAVPacket, sample, AV_CODEC_ID_HEVC);
719 } else if (codecId == AV_CODEC_ID_VVC && streamParsers_ != nullptr &&
720 streamParsers_->ParserIsInited(srcAVPacket->stream_index)) {
721 ret = ConvertVvcToAnnexb(*srcAVPacket, dstSamplePacket);
722 } else if (codecId == AV_CODEC_ID_H264 &&
723 avbsfContexts_.count(srcAVPacket->stream_index) > 0 && avbsfContexts_[srcAVPacket->stream_index] != nullptr) {
724 ret = ConvertAvcToAnnexb(*srcAVPacket);
725 SetDropTag(*srcAVPacket, sample, AV_CODEC_ID_H264);
726 }
727 if (ret != Status::OK) {
728 cacheQueue_.Pop(dstSamplePacket->pkts[0]->stream_index);
729 if (ioContext_.retry) {
730 ioContext_.retry = false;
731 formatContext_->pb->eof_reached = 0;
732 formatContext_->pb->error = 0;
733 return Status::ERROR_AGAIN;
734 }
735 }
736 dstSamplePacket->isAnnexb = true;
737 return ret;
738 }
739
VideoFirstFrameValid(uint32_t trackIndex)740 bool FFmpegDemuxerPlugin::VideoFirstFrameValid(uint32_t trackIndex)
741 {
742 return videoFirstFrameMap_.count(trackIndex) > 0 && videoFirstFrameMap_[trackIndex] != nullptr;
743 }
744
WriteBufferAttr(std::shared_ptr<AVBuffer> sample,std::shared_ptr<SamplePacket> samplePacket)745 void FFmpegDemuxerPlugin::WriteBufferAttr(std::shared_ptr<AVBuffer> sample, std::shared_ptr<SamplePacket> samplePacket)
746 {
747 AVStream *avStream = formatContext_->streams[samplePacket->pkts[0]->stream_index];
748 if (samplePacket->pkts[0]->pts != AV_NOPTS_VALUE) {
749 sample->pts_ = AvTime2Us(ConvertTimeFromFFmpeg(samplePacket->pkts[0]->pts, avStream->time_base));
750 }
751 // durantion dts
752 if (samplePacket->pkts[0]->duration != AV_NOPTS_VALUE) {
753 int64_t duration = AvTime2Us(ConvertTimeFromFFmpeg(samplePacket->pkts[0]->duration, avStream->time_base));
754 sample->duration_ = duration;
755 sample->meta_->SetData(Media::Tag::BUFFER_DURATION, duration);
756 }
757 if (samplePacket->pkts[0]->dts != AV_NOPTS_VALUE) {
758 int64_t dts = AvTime2Us(ConvertTimeFromFFmpeg(samplePacket->pkts[0]->dts, avStream->time_base));
759 sample->dts_ = dts;
760 sample->meta_->SetData(Media::Tag::BUFFER_DECODING_TIMESTAMP, dts);
761 }
762
763 if (FFmpegFormatHelper::IsVideoType(*avStream) && avStream->codecpar->codec_id != AV_CODEC_ID_H264 &&
764 VideoFirstFrameValid(avStream->index) &&
765 samplePacket->pkts[0]->dts == videoFirstFrameMap_[avStream->index]->dts) {
766 if (streamParsers_ != nullptr) {
767 streamParsers_->ResetXPSSendStatus(avStream->index);
768 }
769 }
770 }
771
BufferIsValid(std::shared_ptr<AVBuffer> sample,std::shared_ptr<SamplePacket> samplePacket)772 Status FFmpegDemuxerPlugin::BufferIsValid(std::shared_ptr<AVBuffer> sample, std::shared_ptr<SamplePacket> samplePacket)
773 {
774 FALSE_RETURN_V_MSG_E(samplePacket != nullptr && samplePacket->pkts.size() > 0 &&
775 samplePacket->pkts[0] != nullptr && samplePacket->pkts[0]->size >= 0,
776 Status::ERROR_INVALID_OPERATION, "Input packet is nullptr or empty");
777 FALSE_RETURN_V_MSG_E(static_cast<uint32_t>(samplePacket->pkts[0]->stream_index) < formatContext_->nb_streams,
778 Status::ERROR_INVALID_OPERATION, "FormatContext state error");
779 FALSE_RETURN_V_MSG_E(formatContext_->streams[samplePacket->pkts[0]->stream_index] != nullptr,
780 Status::ERROR_INVALID_OPERATION, "Stream state error");
781 MEDIA_LOG_D("Convert packet info for track " PUBLIC_LOG_D32, samplePacket->pkts[0]->stream_index);
782 FALSE_RETURN_V_MSG_E(sample != nullptr && sample->memory_ != nullptr && sample->meta_ != nullptr,
783 Status::ERROR_INVALID_OPERATION, "Input sample is nullptr");
784 FALSE_RETURN_V_MSG_E(sample->memory_->GetCapacity() >= 0, Status::ERROR_INVALID_DATA,
785 "Invalid capability[%{public}d]", sample->memory_->GetCapacity());
786 return Status::OK;
787 }
788
UpdateLastPacketInfo(int32_t trackId,int64_t pts,int64_t pos,int64_t duration)789 void FFmpegDemuxerPlugin::UpdateLastPacketInfo(int32_t trackId, int64_t pts, int64_t pos, int64_t duration)
790 {
791 trackDfxInfoMap_[trackId].lastPts = pts;
792 trackDfxInfoMap_[trackId].lastDuration = duration;
793 trackDfxInfoMap_[trackId].lastPos = pos;
794 }
795
ConvertAVPacketToSample(std::shared_ptr<AVBuffer> sample,std::shared_ptr<SamplePacket> samplePacket)796 Status FFmpegDemuxerPlugin::ConvertAVPacketToSample(
797 std::shared_ptr<AVBuffer> sample, std::shared_ptr<SamplePacket> samplePacket)
798 {
799 Status bufferIsValid = BufferIsValid(sample, samplePacket);
800 FALSE_RETURN_V_MSG_E(bufferIsValid == Status::OK, bufferIsValid, "AVBuffer or packet is invalid");
801 WriteBufferAttr(sample, samplePacket);
802
803 // convert
804 AVPacket *tempPkt = CombinePackets(samplePacket);
805 FALSE_RETURN_V_MSG_E(tempPkt != nullptr, Status::ERROR_INVALID_OPERATION, "Temp packet is empty");
806 if (cacheQueue_.ResetInfo(samplePacket) == false) {
807 MEDIA_LOG_D("Reset info failed");
808 }
809 Status ret = ConvertPacketToAnnexb(sample, tempPkt, samplePacket);
810 if (ret != Status::OK && tempPkt->size != samplePacket->pkts[0]->size) {
811 FreeAVPacket(tempPkt);
812 }
813 FALSE_RETURN_V_MSG_E(ret == Status::OK, ret, "Convert annexb failed");
814 if (cacheQueue_.SetInfo(samplePacket) == false) {
815 MEDIA_LOG_D("Set info failed");
816 }
817
818 // flag\copy
819 FALSE_RETURN_V_MSG_E(tempPkt->size >= 0 && static_cast<uint32_t>(tempPkt->size) >= samplePacket->offset,
820 Status::ERROR_INVALID_DATA, "Invalid size[%{public}d] offset[%{public}u]", tempPkt->size, samplePacket->offset);
821 uint32_t remainSize = static_cast<uint32_t>(tempPkt->size) - samplePacket->offset;
822 uint32_t capability = static_cast<uint32_t>(sample->memory_->GetCapacity());
823 uint32_t copySize = remainSize < capability ? remainSize : capability;
824 MEDIA_LOG_D("Convert size [" PUBLIC_LOG_D32 "/" PUBLIC_LOG_U32 "/" PUBLIC_LOG_U32 "/" PUBLIC_LOG_U32 "]",
825 tempPkt->size, remainSize, copySize, samplePacket->offset);
826 SetDrmCencInfo(sample, samplePacket);
827
828 sample->flag_ = ConvertFlagsFromFFmpeg(*tempPkt, (copySize != static_cast<uint32_t>(tempPkt->size)));
829 ret = WriteBuffer(sample, tempPkt->data + samplePacket->offset, copySize);
830 if (ret != Status::OK && tempPkt->size != samplePacket->pkts[0]->size) {
831 FreeAVPacket(tempPkt);
832 }
833 FALSE_RETURN_V_MSG_E(ret == Status::OK, ret, "Write buffer failed");
834
835 if (!samplePacket->isEOS) {
836 UpdateLastPacketInfo(tempPkt->stream_index, sample->pts_, tempPkt->pos, sample->duration_);
837 }
838 #ifdef BUILD_ENG_VERSION
839 DumpParam dumpParam {DumpMode(DUMP_AVBUFFER_OUTPUT & dumpMode_), tempPkt->data + samplePacket->offset,
840 tempPkt->stream_index, -1, copySize, trackDfxInfoMap_[tempPkt->stream_index].frameIndex++, tempPkt->pts, -1};
841 Dump(dumpParam);
842 #endif
843 if (tempPkt != nullptr && tempPkt->size != samplePacket->pkts[0]->size) {
844 FreeAVPacket(tempPkt);
845 }
846
847 if (copySize < remainSize) {
848 FALSE_RETURN_V_MSG_E(samplePacket->offset <= UINT32_MAX - copySize, Status::ERROR_INVALID_DATA,
849 "Invalid offset[%{public}u] copySize[%{public}u]", samplePacket->offset, copySize);
850 samplePacket->offset += copySize;
851 MEDIA_LOG_D("Buffer is not enough, next buffer to copy remain data");
852 return Status::ERROR_NOT_ENOUGH_DATA;
853 }
854 return Status::OK;
855 }
856
PushEOSToAllCache()857 Status FFmpegDemuxerPlugin::PushEOSToAllCache()
858 {
859 Status ret = Status::OK;
860 for (size_t i = 0; i < selectedTrackIds_.size(); ++i) {
861 auto streamIndex = selectedTrackIds_[i];
862 MEDIA_LOG_I("Track " PUBLIC_LOG_D32, streamIndex);
863 std::shared_ptr<SamplePacket> eosSample = std::make_shared<SamplePacket>();
864 eosSample->isEOS = true;
865 cacheQueue_.Push(streamIndex, eosSample);
866 ret = CheckCacheDataLimit(streamIndex);
867 }
868 return ret;
869 }
870
WebvttPktProcess(AVPacket * pkt)871 bool FFmpegDemuxerPlugin::WebvttPktProcess(AVPacket *pkt)
872 {
873 auto trackId = pkt->stream_index;
874 if (pkt->size > 0) { // vttc
875 return false;
876 } else { // vtte
877 if (cacheQueue_.HasCache(trackId)) {
878 std::shared_ptr<SamplePacket> cacheSamplePacket = cacheQueue_.Back(static_cast<uint32_t>(trackId));
879 if (cacheSamplePacket != nullptr && cacheSamplePacket->pkts.size() > 0 &&
880 cacheSamplePacket->pkts[0] != nullptr && cacheSamplePacket->pkts[0]->duration == 0 &&
881 pkt->pts != AV_NOPTS_VALUE && cacheSamplePacket->pkts[0]->pts != AV_NOPTS_VALUE) {
882 cacheSamplePacket->pkts[0]->duration = pkt->pts - cacheSamplePacket->pkts[0]->pts;
883 }
884 }
885 }
886 FreeAVPacket(pkt);
887 return true;
888 }
889
IsWebvttMP4(const AVStream * avStream)890 bool FFmpegDemuxerPlugin::IsWebvttMP4(const AVStream *avStream)
891 {
892 return (avStream->codecpar->codec_id == AV_CODEC_ID_WEBVTT && FFmpegFormatHelper::IsMpeg4File(fileType_));
893 }
894
WebvttMP4EOSProcess(const AVPacket * pkt)895 void FFmpegDemuxerPlugin::WebvttMP4EOSProcess(const AVPacket *pkt)
896 {
897 if (pkt != nullptr) {
898 auto trackId = pkt->stream_index;
899 AVStream *avStream = formatContext_->streams[trackId];
900 if (IsWebvttMP4(avStream) && pkt->size == 0 && cacheQueue_.HasCache(trackId)) {
901 std::shared_ptr<SamplePacket> cacheSamplePacket = cacheQueue_.Back(static_cast<uint32_t>(trackId));
902 if (cacheSamplePacket != nullptr && cacheSamplePacket->pkts.size() > 0 &&
903 cacheSamplePacket->pkts[0] != nullptr && cacheSamplePacket->pkts[0]->duration == 0) {
904 cacheSamplePacket->pkts[0]->duration =
905 formatContext_->streams[pkt->stream_index]->duration - cacheSamplePacket->pkts[0]->pts;
906 }
907 }
908 }
909 }
910
ResetContext()911 void FFmpegDemuxerPlugin::ResetContext()
912 {
913 formatContext_->pb->eof_reached = 0;
914 formatContext_->pb->error = 0;
915 ioContext_.retry = false;
916 }
917
SelectedVideo()918 bool FFmpegDemuxerPlugin::SelectedVideo()
919 {
920 for (uint32_t index : selectedTrackIds_) {
921 FALSE_RETURN_V_NOLOG(
922 formatContext_ != nullptr &&
923 index < formatContext_->nb_streams &&
924 formatContext_->streams[index] != nullptr &&
925 formatContext_->streams[index]->codecpar != nullptr, false);
926
927 if (formatContext_->streams[index]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
928 return true;
929 }
930 }
931 return false;
932 }
933
NeedDropAfterSeek(uint32_t trackId,int64_t pts)934 bool FFmpegDemuxerPlugin::NeedDropAfterSeek(uint32_t trackId, int64_t pts)
935 {
936 FALSE_RETURN_V_NOLOG(seekTime_ != AV_NOPTS_VALUE && seekMode_ == SeekMode::SEEK_NEXT_SYNC, false);
937 FALSE_RETURN_V_NOLOG(formatContext_ != nullptr && trackId < formatContext_->nb_streams, false);
938 FALSE_RETURN_V_NOLOG(fileType_ != FileType::OGG && fileType_ != FileType::UNKNOW, false);
939 AVStream *avStream = formatContext_->streams[trackId];
940 FALSE_RETURN_V_NOLOG(avStream != nullptr && avStream->codecpar != nullptr, false);
941 FALSE_RETURN_V_NOLOG(avStream->start_time != AV_NOPTS_VALUE, false);
942 if (avStream->start_time < 0) {
943 FALSE_RETURN_V_NOLOG(pts <= INT64_MAX + avStream->start_time, false);
944 } else if (avStream->start_time > 0) {
945 FALSE_RETURN_V_NOLOG(pts >= INT64_MIN + avStream->start_time, false);
946 }
947 if (!SelectedVideo() && FFmpegFormatHelper::IsAudioType(*avStream) && // audio seek
948 AvTime2Us(ConvertTimeFromFFmpeg(pts - avStream->start_time, avStream->time_base)) < seekTime_ * MS_TO_US) {
949 MEDIA_LOG_W("Seek frame behind time, drop");
950 return true;
951 }
952 seekTime_ = AV_NOPTS_VALUE;
953 return false;
954 }
955
AVReadFrameLimit(AVPacket * pkt)956 int FFmpegDemuxerPlugin::AVReadFrameLimit(AVPacket *pkt)
957 {
958 if (!ioContext_.isLimitType) {
959 return av_read_frame(formatContext_.get(), pkt);
960 }
961
962 ioContext_.isLimit = true;
963 int ffmpegRet = av_read_frame(formatContext_.get(), pkt);
964 ioContext_.isLimit = false;
965 ioContext_.readSizeCnt = 0;
966 return ffmpegRet;
967 }
968
ReadPacketToCacheQueue(const uint32_t readId)969 Status FFmpegDemuxerPlugin::ReadPacketToCacheQueue(const uint32_t readId)
970 {
971 std::lock_guard<std::mutex> lock(mutex_);
972 AVPacket *pkt = nullptr;
973 bool continueRead = true;
974 Status ret = Status::OK;
975 while (continueRead) {
976 FALSE_RETURN_V(!isInterruptNeeded_.load(), Status::ERROR_WRONG_STATE);
977 if (pkt == nullptr) {
978 pkt = av_packet_alloc();
979 FALSE_RETURN_V_MSG_E(pkt != nullptr, Status::ERROR_NULL_POINTER, "Call av_packet_alloc failed");
980 }
981 std::unique_lock<std::mutex> sLock(syncMutex_);
982 int ffmpegRet = AVReadFrameLimit(pkt);
983 sLock.unlock();
984 if (ffmpegRet == AVERROR_EOF) { // eos
985 WebvttMP4EOSProcess(pkt);
986 FreeAVPacket(pkt);
987 ret = PushEOSToAllCache();
988 FALSE_RETURN_V_MSG_E(ret == Status::OK, ret, "Push eos failed");
989 return Status::END_OF_STREAM;
990 }
991 if (ffmpegRet < 0) { // fail
992 FreeAVPacket(pkt);
993 MEDIA_LOG_E("Call av_read_frame failed:" PUBLIC_LOG_S ", retry: " PUBLIC_LOG_D32,
994 AVStrError(ffmpegRet).c_str(), int(ioContext_.retry));
995 if (ioContext_.retry) {
996 ResetContext();
997 return Status::ERROR_AGAIN;
998 }
999 return Status::ERROR_UNKNOWN;
1000 }
1001 auto trackId = pkt->stream_index;
1002 if (!TrackIsSelected(trackId) || NeedDropAfterSeek(trackId, pkt->pts)) {
1003 av_packet_unref(pkt);
1004 continue;
1005 }
1006 AVStream *avStream = formatContext_->streams[trackId];
1007 if (IsWebvttMP4(avStream) && WebvttPktProcess(pkt)) {
1008 break;
1009 } else if (!IsWebvttMP4(avStream) && (!NeedCombineFrame(readId) ||
1010 (cacheQueue_.HasCache(static_cast<uint32_t>(trackId)) && IsBeginAsAnnexb(pkt->data, pkt->size)))) {
1011 continueRead = false;
1012 }
1013 ret = AddPacketToCacheQueue(pkt);
1014 FALSE_RETURN_V_MSG_E(ret == Status::OK, ret, "Add cache failed");
1015 pkt = nullptr;
1016 }
1017 return ret;
1018 }
1019
SetEosSample(std::shared_ptr<AVBuffer> sample)1020 Status FFmpegDemuxerPlugin::SetEosSample(std::shared_ptr<AVBuffer> sample)
1021 {
1022 MEDIA_LOG_D("In");
1023 sample->pts_ = 0;
1024 sample->flag_ = (uint32_t)(AVBufferFlag::EOS);
1025 Status ret = WriteBuffer(sample, nullptr, 0);
1026 FALSE_RETURN_V_MSG_E(ret == Status::OK, ret, "Write buffer failed");
1027 MEDIA_LOG_I("Out");
1028 return Status::OK;
1029 }
1030
Start()1031 Status FFmpegDemuxerPlugin::Start()
1032 {
1033 return Status::OK;
1034 }
1035
Stop()1036 Status FFmpegDemuxerPlugin::Stop()
1037 {
1038 return Status::OK;
1039 }
1040
1041 // Write packet unimplemented, return 0
AVWritePacket(void * opaque,uint8_t * buf,int bufSize)1042 int FFmpegDemuxerPlugin::AVWritePacket(void* opaque, uint8_t* buf, int bufSize)
1043 {
1044 (void)opaque;
1045 (void)buf;
1046 (void)bufSize;
1047 return 0;
1048 }
1049
CheckContextIsValid(void * opaque,int & bufSize)1050 int FFmpegDemuxerPlugin::CheckContextIsValid(void* opaque, int &bufSize)
1051 {
1052 int ret = -1;
1053 auto ioContext = static_cast<IOContext*>(opaque);
1054 FALSE_RETURN_V_MSG_E(ioContext != nullptr, ret, "IOContext is nullptr");
1055 FALSE_RETURN_V_MSG_E(ioContext->dataSource != nullptr, ret, "DataSource is nullptr");
1056 FALSE_RETURN_V_MSG_E(ioContext->offset <= INT64_MAX - static_cast<int64_t>(bufSize), ret, "Offset invalid");
1057
1058 if (ioContext->dataSource->IsDash() && ioContext->eos == true) {
1059 MEDIA_LOG_I("Read eos");
1060 return AVERROR_EOF;
1061 }
1062
1063 MEDIA_LOG_D("Offset: " PUBLIC_LOG_D64 ", totalSize: " PUBLIC_LOG_U64, ioContext->offset, ioContext->fileSize);
1064 if (ioContext->fileSize > 0) {
1065 FALSE_RETURN_V_MSG_E(static_cast<uint64_t>(ioContext->offset) <= ioContext->fileSize, ret, "Out of file size");
1066 if (static_cast<size_t>(ioContext->offset + bufSize) > ioContext->fileSize) {
1067 bufSize = static_cast<int64_t>(ioContext->fileSize) - ioContext->offset;
1068 }
1069 }
1070
1071 if (ioContext->isLimit) {
1072 if (bufSize > ioContext->sizeLimit - ioContext->readSizeCnt) {
1073 MEDIA_LOG_E("Read limit cur: " PUBLIC_LOG_D32 ", limit: " PUBLIC_LOG_D32 ", read: " PUBLIC_LOG_D32,
1074 ioContext->readSizeCnt, ioContext->sizeLimit, bufSize);
1075 return ret;
1076 }
1077 ioContext->readSizeCnt += bufSize;
1078 }
1079 return 0;
1080 }
1081
AVSeek(void * opaque,int64_t offset,int whence)1082 int64_t FFmpegDemuxerPlugin::AVSeek(void* opaque, int64_t offset, int whence)
1083 {
1084 auto ioContext = static_cast<IOContext*>(opaque);
1085 uint64_t newPos = 0;
1086 FALSE_RETURN_V_MSG_E(ioContext != nullptr, newPos, "IOContext is nullptr");
1087 switch (whence) {
1088 case SEEK_SET:
1089 newPos = static_cast<uint64_t>(offset);
1090 ioContext->offset = newPos;
1091 MEDIA_LOG_D("Whence: " PUBLIC_LOG_D32 ", pos = " PUBLIC_LOG_D64 ", newPos = " PUBLIC_LOG_U64,
1092 whence, offset, newPos);
1093 break;
1094 case SEEK_CUR:
1095 newPos = ioContext->offset + offset;
1096 MEDIA_LOG_D("Whence: " PUBLIC_LOG_D32 ", pos = " PUBLIC_LOG_D64 ", newPos = " PUBLIC_LOG_U64,
1097 whence, offset, newPos);
1098 break;
1099 case SEEK_END:
1100 case AVSEEK_SIZE: {
1101 FALSE_RETURN_V_MSG_E(ioContext->dataSource != nullptr, newPos, "DataSource is nullptr");
1102 if (ioContext->dataSource->IsDash()) {
1103 return -1;
1104 }
1105 uint64_t mediaDataSize = 0;
1106 if (ioContext->dataSource->GetSize(mediaDataSize) == Status::OK && (mediaDataSize > 0)) {
1107 newPos = mediaDataSize + offset;
1108 MEDIA_LOG_D("Whence: " PUBLIC_LOG_D32 ", pos = " PUBLIC_LOG_D64 ", newPos = " PUBLIC_LOG_U64,
1109 whence, offset, newPos);
1110 }
1111 break;
1112 }
1113 default:
1114 MEDIA_LOG_E("Unexpected whence " PUBLIC_LOG_D32, whence);
1115 break;
1116 }
1117 if (whence != AVSEEK_SIZE) {
1118 ioContext->offset = newPos;
1119 }
1120 MEDIA_LOG_D("Current offset: " PUBLIC_LOG_D64 ", new pos: " PUBLIC_LOG_U64, ioContext->offset, newPos);
1121 return newPos;
1122 }
1123
AllocAVIOContext(int flags,IOContext * ioContext)1124 AVIOContext* FFmpegDemuxerPlugin::AllocAVIOContext(int flags, IOContext *ioContext)
1125 {
1126 auto buffer = static_cast<unsigned char*>(av_malloc(DEFAULT_READ_SIZE));
1127 FALSE_RETURN_V_MSG_E(buffer != nullptr, nullptr, "Call av_malloc failed");
1128
1129 AVIOContext* avioContext = avio_alloc_context(
1130 buffer, DEFAULT_READ_SIZE,
1131 static_cast<int>(static_cast<uint32_t>(flags) & static_cast<uint32_t>(AVIO_FLAG_WRITE)),
1132 static_cast<void*>(ioContext),
1133 AVReadPacket, AVWritePacket, AVSeek);
1134 if (avioContext == nullptr) {
1135 MEDIA_LOG_E("Call avio_alloc_context failed");
1136 av_free(buffer);
1137 return nullptr;
1138 }
1139 avioContext->seekable = (seekable_ == Seekable::SEEKABLE) ? AVIO_SEEKABLE_NORMAL : 0;
1140 if (!(static_cast<uint32_t>(flags) & static_cast<uint32_t>(AVIO_FLAG_WRITE))) {
1141 avioContext->buf_ptr = avioContext->buf_end;
1142 avioContext->write_flag = 0;
1143 }
1144 return avioContext;
1145 }
1146
FreeContext(AVFormatContext * formatContext,AVIOContext * avioContext)1147 void FreeContext(AVFormatContext* formatContext, AVIOContext* avioContext)
1148 {
1149 if (formatContext) {
1150 avformat_close_input(&formatContext);
1151 }
1152 if (avioContext) {
1153 if (avioContext->buffer) {
1154 av_freep(&(avioContext->buffer));
1155 }
1156 avio_context_free(&avioContext);
1157 }
1158 }
1159
ParseHeader(AVFormatContext * formatContext,std::shared_ptr<AVInputFormat> pluginImpl,AVDictionary ** options)1160 int32_t ParseHeader(AVFormatContext* formatContext, std::shared_ptr<AVInputFormat> pluginImpl, AVDictionary **options)
1161 {
1162 FALSE_RETURN_V_MSG_E(formatContext && pluginImpl, -1, "AVFormatContext is nullptr");
1163 MediaAVCodec::AVCodecTrace trace("ffmpeg_init");
1164
1165 AVIOContext* avioContext = formatContext->pb;
1166 auto begin = std::chrono::steady_clock::now();
1167 int ret = avformat_open_input(&formatContext, nullptr, pluginImpl.get(), options);
1168 if (ret < 0) {
1169 FreeContext(formatContext, avioContext);
1170 MEDIA_LOG_E("Call avformat_open_input failed by " PUBLIC_LOG_S ", err:" PUBLIC_LOG_S,
1171 pluginImpl->name, AVStrError(ret).c_str());
1172 return ret;
1173 }
1174
1175 auto open = std::chrono::steady_clock::now();
1176 if (FFmpegFormatHelper::GetFileTypeByName(*formatContext) == FileType::FLV) { // Fix init live-flv-source too slow
1177 formatContext->probesize = LIVE_FLV_PROBE_SIZE;
1178 }
1179
1180 ret = avformat_find_stream_info(formatContext, NULL);
1181 auto parse = std::chrono::steady_clock::now();
1182 int64_t openSpend = static_cast<int64_t>(
1183 std::chrono::duration_cast<std::chrono::milliseconds>(open - begin).count());
1184 int64_t parseSpend = static_cast<int64_t>(
1185 std::chrono::duration_cast<std::chrono::milliseconds>(parse - open).count());
1186 if ((parseSpend < 0) || (openSpend > INT64_MAX - parseSpend) || (openSpend + parseSpend > INIT_TIME_THRESHOLD)) {
1187 MEDIA_LOG_W("Spend [" PUBLIC_LOG_D64 "/" PUBLIC_LOG_D64 "]", openSpend, parseSpend);
1188 }
1189 if (ret < 0) {
1190 FreeContext(formatContext, avioContext);
1191 MEDIA_LOG_E("Parse stream info failed by " PUBLIC_LOG_S ", err:" PUBLIC_LOG_S,
1192 pluginImpl->name, AVStrError(ret).c_str());
1193 return ret;
1194 }
1195 return 0;
1196 }
1197
InitAVFormatContext(IOContext * ioContext)1198 std::shared_ptr<AVFormatContext> FFmpegDemuxerPlugin::InitAVFormatContext(IOContext *ioContext)
1199 {
1200 AVFormatContext* formatContext = avformat_alloc_context();
1201 FALSE_RETURN_V_MSG_E(formatContext != nullptr, nullptr, "AVFormatContext is nullptr");
1202
1203 formatContext->pb = AllocAVIOContext(AVIO_FLAG_READ, ioContext);
1204 if (formatContext->pb == nullptr) {
1205 FreeContext(formatContext, nullptr);
1206 return nullptr;
1207 }
1208
1209 formatContext->flags = static_cast<uint32_t>(formatContext->flags) | static_cast<uint32_t>(AVFMT_FLAG_CUSTOM_IO);
1210 if (std::string(pluginImpl_->name) == PLUGIN_NAME_MP3) {
1211 formatContext->flags =
1212 static_cast<uint32_t>(formatContext->flags) | static_cast<uint32_t>(AVFMT_FLAG_FAST_SEEK);
1213 }
1214 AVDictionary *options = nullptr;
1215 if (ioContext_.dataSource->IsDash()) {
1216 av_dict_set(&options, "use_tfdt", "true", 0);
1217 }
1218
1219 int ret = ParseHeader(formatContext, pluginImpl_, &options);
1220 av_dict_free(&options);
1221 FALSE_RETURN_V_MSG_E(ret >= 0, nullptr, "ParseHeader failed");
1222
1223 std::shared_ptr<AVFormatContext> retFormatContext =
1224 std::shared_ptr<AVFormatContext>(formatContext, [](AVFormatContext *ptr) {
1225 if (ptr) {
1226 auto ctx = ptr->pb;
1227 avformat_close_input(&ptr);
1228 if (ctx) {
1229 ctx->opaque = nullptr;
1230 av_freep(&(ctx->buffer));
1231 av_opt_free(ctx);
1232 avio_context_free(&ctx);
1233 ctx = nullptr;
1234 }
1235 }
1236 });
1237 return retFormatContext;
1238 }
1239
NotifyInitializationCompleted()1240 void FFmpegDemuxerPlugin::NotifyInitializationCompleted()
1241 {
1242 ioContext_.initCompleted = true;
1243 if (ioContext_.initDownloadDataSize >= INIT_DOWNLOADS_DATA_SIZE_THRESHOLD) {
1244 MEDIA_LOG_I("Large init size %{public}u", ioContext_.initDownloadDataSize);
1245 }
1246 }
1247
InitIoContextInDemuxer(const std::shared_ptr<DataSource> & source)1248 void FFmpegDemuxerPlugin::InitIoContextInDemuxer(const std::shared_ptr<DataSource>& source)
1249 {
1250 ioContext_.dataSource = source;
1251 ioContext_.offset = 0;
1252 ioContext_.eos = false;
1253 ioContext_.dumpMode = dumpMode_;
1254 seekable_ = ioContext_.dataSource->IsDash() ? Plugins::Seekable::UNSEEKABLE : source->GetSeekable();
1255 if (seekable_ == Plugins::Seekable::SEEKABLE) {
1256 ioContext_.dataSource->GetSize(ioContext_.fileSize);
1257 } else {
1258 ioContext_.fileSize = -1;
1259 }
1260 MEDIA_LOG_I("FileSize: " PUBLIC_LOG_U64 ", seekable: " PUBLIC_LOG_D32, ioContext_.fileSize, seekable_);
1261 }
1262
SetDataSource(const std::shared_ptr<DataSource> & source)1263 Status FFmpegDemuxerPlugin::SetDataSource(const std::shared_ptr<DataSource>& source)
1264 {
1265 std::lock_guard<std::shared_mutex> lock(sharedMutex_);
1266 FALSE_RETURN_V_MSG_E(formatContext_ == nullptr, Status::ERROR_WRONG_STATE,
1267 "AVFormatContext has been initialized");
1268 FALSE_RETURN_V_MSG_E(source != nullptr, Status::ERROR_INVALID_PARAMETER, "DataSource is nullptr");
1269 if (ioContext_.invokerType != InvokerType::INIT) {
1270 std::lock_guard<std::mutex> initLock(ioContext_.invokerTypeMutex);
1271 ioContext_.invokerType = InvokerType::INIT;
1272 }
1273 InitIoContextInDemuxer(source);
1274 {
1275 std::lock_guard<std::mutex> glock(g_mtx);
1276 pluginImpl_ = g_pluginInputFormat[pluginName_];
1277 }
1278 FALSE_RETURN_V_MSG_E(pluginImpl_ != nullptr, Status::ERROR_UNSUPPORTED_FORMAT, "No match inputformat");
1279 formatContext_ = InitAVFormatContext(&ioContext_);
1280 if (formatContext_ == nullptr) {
1281 if (ioContext_.retry) {
1282 MEDIA_LOG_E("SetDataSource failed cause not enough data");
1283 return Status::ERROR_NOT_ENOUGH_DATA;
1284 }
1285 MEDIA_LOG_E("AVFormatContext is nullptr");
1286 return Status::ERROR_UNKNOWN;
1287 }
1288 fileType_ = FFmpegFormatHelper::GetFileTypeByName(*formatContext_);
1289 InitParser();
1290
1291 // parse media info
1292 GetMediaInfo();
1293
1294 SetAVReadFrameLimit();
1295
1296 // check param
1297 if (ioContext_.retry && !HasCodecParameters()) {
1298 ResetParam();
1299 MEDIA_LOG_E("SetDataSource failed cause not enough data");
1300 return Status::ERROR_NOT_ENOUGH_DATA;
1301 }
1302 NotifyInitializationCompleted();
1303 MEDIA_LOG_I("Out");
1304 cachelimitSize_ = DEFAULT_CACHE_LIMIT;
1305 if (ioContext_.initErrorAgain == true && formatContext_->pb->error == -1) { // -1 means error_again during init
1306 MEDIA_LOG_E("Initialization error_again occurred");
1307 ResetContext();
1308 ioContext_.initErrorAgain = false;
1309 }
1310 return Status::OK;
1311 }
1312
CheckProbScore(const std::string & pluginName,const int32_t probScore)1313 static bool CheckProbScore(const std::string& pluginName, const int32_t probScore)
1314 {
1315 if (probScore >= DEF_PROBE_SCORE_LIMIT) {
1316 return true;
1317 }
1318
1319 std::string pluginType = pluginName.substr(std::string(PLUGIN_NAME_PREFIX).size());
1320 if (StartWith(pluginType.c_str(), PLUGIN_NAME_MP3) && probScore > MP3_PROBE_SCORE_LIMIT) {
1321 return true;
1322 }
1323
1324 return false;
1325 }
1326
SetDataSourceWithProbSize(const std::shared_ptr<DataSource> & source,const int32_t probSize)1327 Status FFmpegDemuxerPlugin::SetDataSourceWithProbSize(const std::shared_ptr<DataSource>& source,
1328 const int32_t probSize)
1329 {
1330 std::unique_lock<std::shared_mutex> lock(sharedMutex_);
1331 FALSE_RETURN_V_MSG_E(formatContext_ == nullptr, Status::ERROR_WRONG_STATE,
1332 "AVFormatContext has been initialized");
1333 FALSE_RETURN_V_MSG_E(source != nullptr, Status::ERROR_INVALID_PARAMETER, "DataSource is nullptr");
1334 FALSE_RETURN_V_MSG_E(probSize >= 0, Status::ERROR_INVALID_PARAMETER, "probSize is invalid");
1335
1336 int32_t probScore = SniffWithSize(pluginName_, source, probSize);
1337 FALSE_RETURN_V_MSG_E(CheckProbScore(pluginName_, probScore), Status::ERROR_INVALID_PARAMETER,
1338 "source and inputformat mismatch");
1339 lock.unlock();
1340
1341 return SetDataSource(source);
1342 }
1343
HasCodecParameters()1344 bool FFmpegDemuxerPlugin::HasCodecParameters()
1345 {
1346 int32_t param;
1347 FALSE_RETURN_V_MSG_E(static_cast<size_t>(formatContext_->nb_streams) == mediaInfo_.tracks.size(), false,
1348 "mediaInfo is error");
1349 for (uint32_t i = 0; i < formatContext_->nb_streams; i++) {
1350 auto avStream = formatContext_->streams[i];
1351 FALSE_RETURN_V_MSG_E(avStream != nullptr && avStream->codecpar != nullptr, false, "AVStream is nullptr");
1352 Meta &format = mediaInfo_.tracks[i];
1353 bool flag = !HaveValidParser(avStream->codecpar->codec_id) ||
1354 (HaveValidParser(avStream->codecpar->codec_id) && streamParsers_ != nullptr);
1355 if (FFmpegFormatHelper::IsAudioType(*avStream)) {
1356 FALSE_RETURN_V_MSG_E(format.GetData(Tag::AUDIO_CHANNEL_COUNT, param), false,
1357 "unspecified channel_count");
1358 FALSE_RETURN_V_MSG_E(format.GetData(Tag::AUDIO_SAMPLE_RATE, param), false, "unspecified sample_rate");
1359 } else if (FFmpegFormatHelper::IsVideoType(*avStream)) {
1360 FALSE_RETURN_V_MSG_E(flag && format.GetData(Tag::VIDEO_WIDTH, param), false, "unspecified width");
1361 FALSE_RETURN_V_MSG_E(flag && format.GetData(Tag::VIDEO_HEIGHT, param), false, "unspecified height");
1362 }
1363 }
1364 return true;
1365 }
1366
InitParser()1367 void FFmpegDemuxerPlugin::InitParser()
1368 {
1369 FALSE_RETURN_MSG(formatContext_ != nullptr, "AVFormatContext is nullptr");
1370 ParserBoxInfo();
1371 streamParsers_ = std::make_shared<MultiStreamParserManager>();
1372 for (uint32_t trackIndex = 0; trackIndex < formatContext_->nb_streams; ++trackIndex) {
1373 if (g_bitstreamFilterMap.count(formatContext_->streams[trackIndex]->codecpar->codec_id) != 0) {
1374 InitBitStreamContext(*(formatContext_->streams[trackIndex]));
1375 continue;
1376 }
1377 if (HaveValidParser(formatContext_->streams[trackIndex]->codecpar->codec_id) && streamParsers_ != nullptr) {
1378 Status ret = streamParsers_->Create(
1379 trackIndex, g_streamParserMap.at(formatContext_->streams[trackIndex]->codecpar->codec_id));
1380 if (ret != Status::OK) {
1381 MEDIA_LOG_W("Init failed");
1382 } else {
1383 MEDIA_LOG_D("Track " PUBLIC_LOG_D32 " will be converted", trackIndex);
1384 }
1385 }
1386 }
1387 }
1388
GetMediaInfo(MediaInfo & mediaInfo)1389 Status FFmpegDemuxerPlugin::GetMediaInfo(MediaInfo& mediaInfo)
1390 {
1391 std::lock_guard<std::shared_mutex> lock(sharedMutex_);
1392 FALSE_RETURN_V_MSG_E(formatContext_ != nullptr, Status::ERROR_NULL_POINTER, "AVFormatContext is nullptr");
1393 mediaInfo = mediaInfo_;
1394 return Status::OK;
1395 }
1396
SetAVReadFrameLimit()1397 Status FFmpegDemuxerPlugin::SetAVReadFrameLimit()
1398 {
1399 FALSE_RETURN_V_MSG_E(formatContext_ != nullptr, Status::ERROR_NULL_POINTER, "AVFormatContext is nullptr");
1400 if (fileType_ != FileType::FLV) {
1401 return Status::OK;
1402 }
1403
1404 ioContext_.isLimitType = true;
1405 ioContext_.sizeLimit = FLV_READ_SIZE_LIMIT_DEFAULT;
1406 FALSE_RETURN_V_MSG_E(static_cast<size_t>(formatContext_->nb_streams) == mediaInfo_.tracks.size(), Status::OK,
1407 "mediaInfo size is error");
1408 for (uint32_t trackIndex = 0; trackIndex < formatContext_->nb_streams; ++trackIndex) {
1409 if (formatContext_->streams[trackIndex] == nullptr) {
1410 MEDIA_LOG_W("Track " PUBLIC_LOG_U32 " info is nullptr", trackIndex);
1411 continue;
1412 }
1413 if (FFmpegFormatHelper::IsVideoType(*(formatContext_->streams[trackIndex]))) {
1414 int width = 0;
1415 int height = 0;
1416 Meta &format = mediaInfo_.tracks[trackIndex];
1417 format.GetData(Tag::VIDEO_WIDTH, width);
1418 format.GetData(Tag::VIDEO_HEIGHT, height);
1419 if (width * height > 0) {
1420 int32_t limitSize = width * height * DEFAULT_CHANNEL_CNT * FLV_READ_SIZE_LIMIT_FACTOR;
1421 ioContext_.sizeLimit = std::max(ioContext_.sizeLimit, limitSize);
1422 MEDIA_LOG_D("Track " PUBLIC_LOG_U32 " hei:" PUBLIC_LOG_D32 ", wid:" PUBLIC_LOG_D32
1423 " limit " PUBLIC_LOG_D32, trackIndex, height, width, limitSize);
1424 }
1425 }
1426 }
1427 return Status::OK;
1428 }
1429
UpdateReferenceIds()1430 void FFmpegDemuxerPlugin::UpdateReferenceIds()
1431 {
1432 for (uint32_t trackIndex = 0; trackIndex < formatContext_->nb_streams; ++trackIndex) {
1433 if (trackIndex >= mediaInfo_.tracks.size()) {
1434 break;
1435 }
1436 Meta meta = mediaInfo_.tracks[trackIndex];
1437 std::vector<int32_t> referenceIds;
1438 meta.Get<Tag::REFERENCE_TRACK_IDS>(referenceIds);
1439 for (auto id : referenceIds) {
1440 if (referenceIdsMap_.count(id) == 0) {
1441 referenceIdsMap_[id] = std::vector<int32_t>();
1442 }
1443 if (!std::any_of(referenceIdsMap_[id].begin(), referenceIdsMap_[id].end(),
1444 [trackIndex](int32_t i) { return static_cast<uint32_t>(i) == trackIndex; })) {
1445 referenceIdsMap_[id].push_back(trackIndex);
1446 }
1447
1448 if (referenceIdsMap_.count(trackIndex) == 0) {
1449 referenceIdsMap_[trackIndex] = std::vector<int32_t>();
1450 }
1451 if (!std::any_of(referenceIdsMap_[trackIndex].begin(), referenceIdsMap_[trackIndex].end(),
1452 [id](int32_t i) { return i == id; })) {
1453 referenceIdsMap_[trackIndex].push_back(id);
1454 }
1455 }
1456 }
1457 for (auto item : referenceIdsMap_) {
1458 if (item.second.size() == 0 || static_cast<size_t>(item.first) >= mediaInfo_.tracks.size()) {
1459 continue;
1460 }
1461 for (auto id : item.second) {
1462 MEDIA_LOG_D("Track " PUBLIC_LOG_D32 " ref " PUBLIC_LOG_D32, item.first, id);
1463 }
1464 mediaInfo_.tracks[item.first].Set<Tag::REFERENCE_TRACK_IDS>(item.second);
1465 }
1466 }
1467
GetStreamInitialParams()1468 void FFmpegDemuxerPlugin::GetStreamInitialParams()
1469 {
1470 FALSE_RETURN_MSG_W(formatContext_ != nullptr, "AVFormatContext is nullptr");
1471 for (uint32_t trackIndex = 0; trackIndex < formatContext_->nb_streams; ++trackIndex) {
1472 auto stream = formatContext_->streams[trackIndex];
1473 if (stream == nullptr) {
1474 continue;
1475 }
1476 Meta format;
1477 int64_t bitRate = static_cast<int64_t>(stream->codecpar->bit_rate);
1478 if (bitRate > 0) {
1479 format.Set<Tag::MEDIA_BITRATE>(bitRate);
1480 } else {
1481 MEDIA_LOG_D("Track " PUBLIC_LOG_D32 " bitrate parse failed", trackIndex);
1482 }
1483 streamInitialParam_[trackIndex] = format;
1484 }
1485 }
1486
SetStreamInitialParams(uint32_t trackId,Meta & format)1487 void FFmpegDemuxerPlugin::SetStreamInitialParams(uint32_t trackId, Meta &format)
1488 {
1489 FALSE_RETURN_MSG_W(streamInitialParam_.count(trackId) > 0, "TrackId is invalid");
1490 int64_t bitRate = 0;
1491 bool ret = streamInitialParam_[trackId].GetData(Tag::MEDIA_BITRATE, bitRate);
1492 if (!ret || bitRate <= 0) {
1493 MEDIA_LOG_W("Track " PUBLIC_LOG_D32 " has no bitrate", trackId);
1494 } else {
1495 format.Set<Tag::MEDIA_BITRATE>(bitRate);
1496 }
1497 }
1498
GetMediaInfo()1499 Status FFmpegDemuxerPlugin::GetMediaInfo()
1500 {
1501 MediaAVCodec::AVCodecTrace trace("FFmpegDemuxerPlugin::GetMediaInfo");
1502 GetStreamInitialParams();
1503 Status ret = ParseVideoFirstFrames();
1504 FALSE_RETURN_V_MSG_E(ret == Status::OK, ret, "Parse video info failed");
1505
1506 FFmpegFormatHelper::ParseMediaInfo(*formatContext_, mediaInfo_.general);
1507 DemuxerLogCompressor::StringifyMeta(mediaInfo_.general, -1); // source meta
1508 for (uint32_t trackId = 0; trackId < formatContext_->nb_streams; ++trackId) {
1509 Meta meta;
1510 auto avStream = formatContext_->streams[trackId];
1511 if (avStream == nullptr) {
1512 MEDIA_LOG_W("Track " PUBLIC_LOG_D32 " info is nullptr", trackId);
1513 mediaInfo_.tracks.push_back(meta);
1514 continue;
1515 }
1516 FFmpegFormatHelper::ParseTrackInfo(*avStream, meta, *formatContext_);
1517 if (avStream->codecpar->codec_id == AV_CODEC_ID_HEVC) {
1518 if (streamParsers_ != nullptr && streamParsers_->ParserIsInited(trackId) && VideoFirstFrameValid(trackId)) {
1519 auto firstFrame = videoFirstFrameMap_[trackId];
1520 streamParsers_->ConvertPacketToAnnexb(
1521 trackId, &(firstFrame->data), firstFrame->size, nullptr, 0, false);
1522 streamParsers_->ParseAnnexbExtraData(trackId, firstFrame->data, firstFrame->size);
1523 // Parser only sends xps info when first call ConvertPacketToAnnexb
1524 // readSample will call ConvertPacketToAnnexb again, so rest here
1525 streamParsers_->ResetXPSSendStatus(trackId);
1526 ParseHEVCMetadataInfo(*avStream, meta);
1527 } else {
1528 MEDIA_LOG_W("Parse hevc info failed");
1529 }
1530 }
1531 if (avStream->codecpar->codec_id == AV_CODEC_ID_HEVC ||
1532 avStream->codecpar->codec_id == AV_CODEC_ID_H264 ||
1533 avStream->codecpar->codec_id == AV_CODEC_ID_VVC) {
1534 ConvertCsdToAnnexb(*avStream, meta);
1535 }
1536 SetStreamInitialParams(trackId, meta);
1537 mediaInfo_.tracks.push_back(meta);
1538 DemuxerLogCompressor::StringifyMeta(meta, trackId);
1539 }
1540 UpdateReferenceIds();
1541 return Status::OK;
1542 }
1543
GetUserMeta(std::shared_ptr<Meta> meta)1544 Status FFmpegDemuxerPlugin::GetUserMeta(std::shared_ptr<Meta> meta)
1545 {
1546 MediaAVCodec::AVCodecTrace trace("FFmpegDemuxerPlugin::GetUserMeta");
1547 std::lock_guard<std::shared_mutex> lock(sharedMutex_);
1548 FALSE_RETURN_V_MSG_E(formatContext_ != nullptr, Status::ERROR_NULL_POINTER, "AVFormatContext is nullptr");
1549 FALSE_RETURN_V_MSG_E(meta != nullptr, Status::ERROR_NULL_POINTER, "Meta is nullptr");
1550
1551 FFmpegFormatHelper::ParseUserMeta(*formatContext_, meta);
1552 return Status::OK;
1553 }
1554
ParseDrmInfo(const MetaDrmInfo * const metaDrmInfo,size_t drmInfoSize,std::multimap<std::string,std::vector<uint8_t>> & drmInfo)1555 void FFmpegDemuxerPlugin::ParseDrmInfo(const MetaDrmInfo *const metaDrmInfo, size_t drmInfoSize,
1556 std::multimap<std::string, std::vector<uint8_t>>& drmInfo)
1557 {
1558 MEDIA_LOG_D("In");
1559 size_t infoCount = drmInfoSize / sizeof(MetaDrmInfo);
1560 for (size_t index = 0; index < infoCount; index++) {
1561 std::stringstream ssConverter;
1562 std::string uuid;
1563 for (uint32_t i = 0; i < metaDrmInfo[index].uuidLen; i++) {
1564 int32_t singleUuid = static_cast<int32_t>(metaDrmInfo[index].uuid[i]);
1565 ssConverter << std::hex << std::setfill('0') << std::setw(2) << singleUuid; // 2:w
1566 uuid = ssConverter.str();
1567 }
1568 drmInfo.insert({ uuid, std::vector<uint8_t>(metaDrmInfo[index].pssh,
1569 metaDrmInfo[index].pssh + metaDrmInfo[index].psshLen) });
1570 }
1571 }
1572
GetDrmInfo(std::multimap<std::string,std::vector<uint8_t>> & drmInfo)1573 Status FFmpegDemuxerPlugin::GetDrmInfo(std::multimap<std::string, std::vector<uint8_t>>& drmInfo)
1574 {
1575 MEDIA_LOG_D("In");
1576 std::lock_guard<std::shared_mutex> lock(sharedMutex_);
1577 FALSE_RETURN_V_MSG_E(formatContext_ != nullptr, Status::ERROR_NULL_POINTER, "AVFormatContext is nullptr");
1578
1579 for (uint32_t trackIndex = 0; trackIndex < formatContext_->nb_streams; ++trackIndex) {
1580 Meta meta;
1581 AVStream *avStream = formatContext_->streams[trackIndex];
1582 if (avStream == nullptr) {
1583 MEDIA_LOG_W("Track " PUBLIC_LOG_D32 " is nullptr", trackIndex);
1584 continue;
1585 }
1586 MEDIA_LOG_D("GetDrmInfo by stream side data");
1587 size_t drmInfoSize = 0;
1588 MetaDrmInfo *tmpDrmInfo = (MetaDrmInfo *)av_stream_get_side_data(avStream,
1589 AV_PKT_DATA_ENCRYPTION_INIT_INFO, &drmInfoSize);
1590 if (tmpDrmInfo != nullptr && drmInfoSize != 0) {
1591 ParseDrmInfo(tmpDrmInfo, drmInfoSize, drmInfo);
1592 }
1593 }
1594 return Status::OK;
1595 }
1596
ConvertCsdToAnnexb(const AVStream & avStream,Meta & format)1597 void FFmpegDemuxerPlugin::ConvertCsdToAnnexb(const AVStream& avStream, Meta &format)
1598 {
1599 uint8_t *extradata = avStream.codecpar->extradata;
1600 int32_t extradataSize = avStream.codecpar->extradata_size;
1601 if (HaveValidParser(avStream.codecpar->codec_id) && streamParsers_ != nullptr &&
1602 streamParsers_->ParserIsInited(avStream.index)) {
1603 streamParsers_->ConvertPacketToAnnexb(avStream.index, &(extradata), extradataSize, nullptr, 0, true);
1604 } else if (avStream.codecpar->codec_id == AV_CODEC_ID_H264 &&
1605 avbsfContexts_.count(avStream.index) > 0 && avbsfContexts_[avStream.index] != nullptr &&
1606 avbsfContexts_[avStream.index]->par_out->extradata != nullptr &&
1607 avbsfContexts_[avStream.index]->par_out->extradata_size > 0) {
1608 extradata = avbsfContexts_[avStream.index]->par_out->extradata;
1609 extradataSize = avbsfContexts_[avStream.index]->par_out->extradata_size;
1610 }
1611 if (extradata != nullptr && extradataSize > 0) {
1612 std::vector<uint8_t> extra(extradataSize);
1613 extra.assign(extradata, extradata + extradataSize);
1614 format.Set<Tag::MEDIA_CODEC_CONFIG>(extra);
1615 }
1616 }
1617
AddPacketToCacheQueue(AVPacket * pkt)1618 Status FFmpegDemuxerPlugin::AddPacketToCacheQueue(AVPacket *pkt)
1619 {
1620 FALSE_RETURN_V_MSG_E(pkt != nullptr, Status::ERROR_NULL_POINTER, "Pkt is nullptr");
1621 #ifdef BUILD_ENG_VERSION
1622 DumpParam dumpParam {DumpMode(DUMP_AVPACKET_OUTPUT & dumpMode_), pkt->data, pkt->stream_index, -1, pkt->size,
1623 avpacketIndex_++, pkt->pts, pkt->pos};
1624 Dump(dumpParam);
1625 #endif
1626 auto trackId = pkt->stream_index;
1627 Status ret = Status::OK;
1628 if (NeedCombineFrame(trackId) && !IsBeginAsAnnexb(pkt->data, pkt->size) && cacheQueue_.HasCache(trackId)) {
1629 std::shared_ptr<SamplePacket> cacheSamplePacket = cacheQueue_.Back(static_cast<uint32_t>(trackId));
1630 if (cacheSamplePacket != nullptr) {
1631 cacheSamplePacket->pkts.push_back(pkt);
1632 }
1633 } else {
1634 std::shared_ptr<SamplePacket> cacheSamplePacket = std::make_shared<SamplePacket>();
1635 if (cacheSamplePacket != nullptr) {
1636 cacheSamplePacket->pkts.push_back(pkt);
1637 cacheSamplePacket->offset = 0;
1638 cacheQueue_.Push(static_cast<uint32_t>(trackId), cacheSamplePacket);
1639 ret = CheckCacheDataLimit(static_cast<uint32_t>(trackId));
1640 }
1641 }
1642 return ret;
1643 }
1644
SetVideoFirstFrame(AVPacket * pkt,bool isConvert)1645 Status FFmpegDemuxerPlugin::SetVideoFirstFrame(AVPacket* pkt, bool isConvert)
1646 {
1647 auto firstFrame = av_packet_alloc();
1648 FALSE_RETURN_V_MSG_E(firstFrame != nullptr, Status::ERROR_NULL_POINTER, "Call av_packet_alloc failed");
1649 int32_t avRet = av_new_packet(firstFrame, pkt->size);
1650 if (avRet < 0) {
1651 MEDIA_LOG_E("Call av_new_packet failed");
1652 FreeAVPacket(firstFrame);
1653 return Status::ERROR_INVALID_DATA;
1654 }
1655 avRet = av_packet_copy_props(firstFrame, pkt);
1656 if (avRet < 0) {
1657 MEDIA_LOG_E("Call av_packet_copy_props failed");
1658 FreeAVPacket(firstFrame);
1659 return Status::ERROR_INVALID_DATA;
1660 }
1661 auto ret = memcpy_s(firstFrame->data, firstFrame->size, pkt->data, pkt->size);
1662 if (ret != EOK) {
1663 MEDIA_LOG_E("Memcpy failed, ret:" PUBLIC_LOG_D32, ret);
1664 FreeAVPacket(firstFrame);
1665 return Status::ERROR_INVALID_DATA;
1666 }
1667 if (firstFrame->data == nullptr) {
1668 MEDIA_LOG_E("Get first frame failed");
1669 FreeAVPacket(firstFrame);
1670 return Status::ERROR_WRONG_STATE;
1671 }
1672 if (isConvert) {
1673 bool convertRet = streamParsers_->ConvertExtraDataToAnnexb(pkt->stream_index,
1674 formatContext_->streams[pkt->stream_index]->codecpar->extradata,
1675 formatContext_->streams[pkt->stream_index]->codecpar->extradata_size);
1676 if (!convertRet) {
1677 MEDIA_LOG_E("ConvertExtraDataToAnnexb failed:" PUBLIC_LOG_D32, pkt->stream_index);
1678 FreeAVPacket(firstFrame);
1679 return Status::ERROR_INVALID_DATA;
1680 }
1681 }
1682 videoFirstFrameMap_[pkt->stream_index] = firstFrame;
1683 if (pkt->pts != AV_NOPTS_VALUE && pkt->dts != AV_NOPTS_VALUE && pkt->pts >= 0 && pkt->dts >= 0) {
1684 seekCalibMap_[pkt->stream_index] = pkt->pts - pkt->dts;
1685 }
1686 return Status::OK;
1687 }
1688
IsSyncFrameCheckNeeded(std::shared_ptr<AVFormatContext> formatContext)1689 static bool IsSyncFrameCheckNeeded(std::shared_ptr<AVFormatContext> formatContext)
1690 {
1691 FALSE_RETURN_V_MSG_E(formatContext != nullptr, false, "AVFormatContext is nullptr");
1692 FileType fileType = FFmpegFormatHelper::GetFileTypeByName(*formatContext);
1693 if (fileType == FileType::MPEGTS || fileType == FileType::MPEGPS) {
1694 return false;
1695 }
1696 return true;
1697 }
1698
AllSupportTrackFramesReady()1699 bool FFmpegDemuxerPlugin::AllSupportTrackFramesReady()
1700 {
1701 for (uint32_t trackIndex = 0; trackIndex < formatContext_->nb_streams; ++trackIndex) {
1702 AVStream* stream = formatContext_->streams[trackIndex];
1703 if (stream == nullptr || stream->codecpar == nullptr || !IsSupportedTrackType(*stream)) {
1704 continue;
1705 }
1706 if (!TrackIsChecked(trackIndex)) {
1707 return false;
1708 }
1709 }
1710 return true;
1711 }
1712
AllVideoFirstFramesReady()1713 bool FFmpegDemuxerPlugin::AllVideoFirstFramesReady()
1714 {
1715 for (uint32_t trackIndex = 0; trackIndex < formatContext_->nb_streams; ++trackIndex) {
1716 AVStream* stream = formatContext_->streams[trackIndex];
1717 if (stream == nullptr || stream->codecpar == nullptr || !FFmpegFormatHelper::IsVideoType(*stream)) {
1718 continue;
1719 }
1720 if (!TrackIsChecked(trackIndex)) {
1721 return false;
1722 }
1723 }
1724 return true;
1725 }
1726
1727 /*
1728 return true:
1729 unsupport track
1730 support track:
1731 packet with key FLAG
1732 packet without key FLAG:
1733 HEVC + TS/PS file
1734 HEVC + IsHevcSyncFrame pass
1735 return false:
1736 support track + without key FLAG + not hevc track
1737 support track + without key FLAG + hevc track + not ts/ps + IsHevcSyncFrame fail
1738 */
IsSyncFrame(AVStream * stream,AVPacket * pkt,std::shared_ptr<AVFormatContext> formatContext)1739 static bool IsSyncFrame(AVStream *stream, AVPacket *pkt, std::shared_ptr<AVFormatContext> formatContext)
1740 {
1741 FALSE_RETURN_V_MSG_E(stream != nullptr && stream->codecpar != nullptr, false, "stream is nullptr");
1742 FALSE_RETURN_V_MSG_E(pkt != nullptr, false, "pkt is nullptr");
1743 FALSE_RETURN_V_MSG_E(formatContext != nullptr, false, "AVFormatContext is nullptr");
1744 if (!FFmpegFormatHelper::IsValidCodecId(stream->codecpar->codec_id)) {
1745 return true;
1746 }
1747 return (static_cast<uint32_t>(pkt->flags) & static_cast<uint32_t>(AV_PKT_FLAG_KEY) ||
1748 (stream->codecpar->codec_id == AV_CODEC_ID_HEVC &&
1749 (!IsSyncFrameCheckNeeded(formatContext) || IsHevcSyncFrame(pkt->data, pkt->size))));
1750 }
1751
ParseVideoFirstFrames()1752 Status FFmpegDemuxerPlugin::ParseVideoFirstFrames()
1753 {
1754 FALSE_RETURN_V_MSG_E(formatContext_ != nullptr, Status::ERROR_NULL_POINTER, "AVFormatContext is nullptr");
1755 FALSE_RETURN_V_MSG_E(streamParsers_ != nullptr, Status::ERROR_NULL_POINTER, "StreamParser is nullptr");
1756 AVPacket *pkt = nullptr;
1757 Status ret = Status::OK;
1758 bool extraType = false;
1759 if (fileType_ == FileType::MPEGTS || FFmpegFormatHelper::IsMpeg4File(fileType_) || fileType_ == FileType::FLV) {
1760 extraType = true;
1761 }
1762 // Finish for extraType: get all support stream
1763 // Finish: read all video or init all parser
1764 while ((extraType && !AllSupportTrackFramesReady()) ||
1765 (!extraType && !AllVideoFirstFramesReady() && !streamParsers_->AllParserInited())) {
1766 FALSE_RETURN_V_MSG_E(!isInterruptNeeded_.load(), Status::ERROR_WRONG_STATE, "ParseVideoFirstFrames interrupt");
1767 if (pkt == nullptr) {
1768 pkt = av_packet_alloc();
1769 FALSE_RETURN_V_MSG_E(pkt != nullptr, Status::ERROR_NULL_POINTER, "Call av_packet_alloc failed");
1770 }
1771 std::unique_lock<std::mutex> sLock(syncMutex_);
1772 int ffmpegRet = av_read_frame(formatContext_.get(), pkt);
1773 sLock.unlock();
1774 if (ffmpegRet < 0) {
1775 MEDIA_LOG_E("Call av_read_frame failed, ret:" PUBLIC_LOG_D32, ffmpegRet);
1776 FreeAVPacket(pkt);
1777 break;
1778 }
1779 int32_t trackId = pkt->stream_index;
1780 auto stream = formatContext_->streams[trackId];
1781 FALSE_RETURN_V_MSG_E(stream != nullptr && stream->codecpar != nullptr, Status::ERROR_NULL_POINTER,
1782 "Stream " PUBLIC_LOG_D32 " is invalid", trackId);
1783 ret = AddPacketToCacheQueue(pkt);
1784 FALSE_RETURN_V_MSG_E(ret == Status::OK, ret, "Add to cache failed");
1785 bool isSpecialStreamType = (stream->codecpar->codec_id == AV_CODEC_ID_VVC);
1786 if (!isSpecialStreamType && (TrackIsChecked(trackId) || !IsSyncFrame(stream, pkt, formatContext_))) {
1787 pkt = nullptr;
1788 continue;
1789 }
1790 checkedTrackIds_.push_back(trackId);
1791 if (streamParsers_->ParserIsCreated(trackId) && !streamParsers_->ParserIsInited(trackId)) {
1792 ret = SetVideoFirstFrame(pkt);
1793 } else if (extraType && FFmpegFormatHelper::IsVideoType(*stream)) {
1794 ret = SetVideoFirstFrame(pkt, false);
1795 }
1796 if (ret != Status::OK) {
1797 pkt = nullptr;
1798 MEDIA_LOG_E("Set first frame failed, track " PUBLIC_LOG_D32, trackId);
1799 return ret;
1800 }
1801 pkt = nullptr;
1802 }
1803 return ret;
1804 }
1805
ParseHEVCMetadataInfo(const AVStream & avStream,Meta & format)1806 void FFmpegDemuxerPlugin::ParseHEVCMetadataInfo(const AVStream& avStream, Meta& format)
1807 {
1808 HevcParseFormat parse;
1809 parse.isHdrVivid = streamParsers_->IsHdrVivid(avStream.index);
1810 parse.colorRange = streamParsers_->GetColorRange(avStream.index);
1811 parse.colorPrimaries = streamParsers_->GetColorPrimaries(avStream.index);
1812 parse.colorTransfer = streamParsers_->GetColorTransfer(avStream.index);
1813 parse.colorMatrixCoeff = streamParsers_->GetColorMatrixCoeff(avStream.index);
1814 parse.profile = streamParsers_->GetProfileIdc(avStream.index);
1815 parse.level = streamParsers_->GetLevelIdc(avStream.index);
1816 parse.chromaLocation = streamParsers_->GetChromaLocation(avStream.index);
1817 parse.picWidInLumaSamples = streamParsers_->GetPicWidInLumaSamples(avStream.index);
1818 parse.picHetInLumaSamples = streamParsers_->GetPicHetInLumaSamples(avStream.index);
1819
1820 FFmpegFormatHelper::ParseHevcInfo(*formatContext_, parse, format);
1821 }
1822
TrackIsSelected(const uint32_t trackId)1823 bool FFmpegDemuxerPlugin::TrackIsSelected(const uint32_t trackId)
1824 {
1825 return std::any_of(selectedTrackIds_.begin(), selectedTrackIds_.end(),
1826 [trackId](uint32_t id) { return id == trackId; });
1827 }
1828
TrackIsChecked(const uint32_t trackId)1829 bool FFmpegDemuxerPlugin::TrackIsChecked(const uint32_t trackId)
1830 {
1831 return std::any_of(checkedTrackIds_.begin(), checkedTrackIds_.end(),
1832 [trackId](uint32_t id) { return id == trackId; });
1833 }
1834
SelectTrack(uint32_t trackId)1835 Status FFmpegDemuxerPlugin::SelectTrack(uint32_t trackId)
1836 {
1837 std::lock_guard<std::shared_mutex> lock(sharedMutex_);
1838 MEDIA_LOG_I("Select " PUBLIC_LOG_D32, trackId);
1839 FALSE_RETURN_V_MSG_E(formatContext_ != nullptr, Status::ERROR_NULL_POINTER, "AVFormatContext is nullptr");
1840 if (trackId >= static_cast<uint32_t>(formatContext_.get()->nb_streams)) {
1841 MEDIA_LOG_E("Track is invalid, just have " PUBLIC_LOG_D32 " tracks in file", formatContext_.get()->nb_streams);
1842 return Status::ERROR_INVALID_PARAMETER;
1843 }
1844
1845 AVStream* avStream = formatContext_->streams[trackId];
1846 FALSE_RETURN_V_MSG_E(avStream != nullptr, Status::ERROR_NULL_POINTER, "AVStream is nullptr");
1847 if (!IsSupportedTrack(*avStream)) {
1848 MEDIA_LOG_E("Track type is unsupport");
1849 return Status::ERROR_INVALID_PARAMETER;
1850 }
1851
1852 if (!TrackIsSelected(trackId)) {
1853 selectedTrackIds_.push_back(trackId);
1854 trackMtx_[trackId] = std::make_shared<std::mutex>();
1855 trackDfxInfoMap_[trackId] = {0, -1, -1, -1, false};
1856 return cacheQueue_.AddTrackQueue(trackId);
1857 } else {
1858 MEDIA_LOG_W("Track " PUBLIC_LOG_U32 " has been selected", trackId);
1859 }
1860 return Status::OK;
1861 }
1862
UnselectTrack(uint32_t trackId)1863 Status FFmpegDemuxerPlugin::UnselectTrack(uint32_t trackId)
1864 {
1865 std::lock_guard<std::shared_mutex> lock(sharedMutex_);
1866 MEDIA_LOG_I("Unselect " PUBLIC_LOG_D32, trackId);
1867 FALSE_RETURN_V_MSG_E(formatContext_ != nullptr, Status::ERROR_NULL_POINTER, "AVFormatContext is nullptr");
1868 auto index = std::find_if(selectedTrackIds_.begin(), selectedTrackIds_.end(),
1869 [trackId](uint32_t selectedId) {return trackId == selectedId; });
1870 if (index != selectedTrackIds_.end()) {
1871 selectedTrackIds_.erase(index);
1872 trackMtx_.erase(trackId);
1873 trackDfxInfoMap_.erase(trackId);
1874 return cacheQueue_.RemoveTrackQueue(trackId);
1875 } else {
1876 MEDIA_LOG_W("Track " PUBLIC_LOG_U32 " is not in selected list", trackId);
1877 }
1878 return Status::OK;
1879 }
1880
SelectSeekTrack() const1881 int FFmpegDemuxerPlugin::SelectSeekTrack() const
1882 {
1883 int trackIndex = static_cast<int>(selectedTrackIds_[0]);
1884 for (size_t i = 1; i < selectedTrackIds_.size(); i++) {
1885 int idx = static_cast<int>(selectedTrackIds_[i]);
1886 if (formatContext_->streams[idx]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
1887 return idx;
1888 }
1889 }
1890 return trackIndex;
1891 }
1892
CheckSeekParams(int64_t seekTime,SeekMode mode) const1893 Status FFmpegDemuxerPlugin::CheckSeekParams(int64_t seekTime, SeekMode mode) const
1894 {
1895 FALSE_RETURN_V_MSG_E(formatContext_ != nullptr, Status::ERROR_NULL_POINTER, "AVFormatContext is nullptr");
1896 FALSE_RETURN_V_MSG_E(!selectedTrackIds_.empty(), Status::ERROR_INVALID_OPERATION, "No track has been selected");
1897 FALSE_RETURN_V_MSG_E(seekTime >= 0 && seekTime <= INT64_MAX / MS_TO_NS, Status::ERROR_INVALID_PARAMETER,
1898 "Seek time " PUBLIC_LOG_D64 " is not supported", seekTime);
1899 FALSE_RETURN_V_MSG_E(g_seekModeToFFmpegSeekFlags.count(mode) != 0, Status::ERROR_INVALID_PARAMETER,
1900 "Seek mode " PUBLIC_LOG_U32 " is not supported", static_cast<uint32_t>(mode));
1901 return Status::OK;
1902 }
1903
SyncSeekThread()1904 void FFmpegDemuxerPlugin::SyncSeekThread()
1905 {
1906 if (ioContext_.invokerType != InvokerType::SEEK) {
1907 std::lock_guard<std::mutex> seekLock(ioContext_.invokerTypeMutex);
1908 ioContext_.invokerType = InvokerType::SEEK;
1909 }
1910 if (readThread_ != nullptr && threadState_ == READING) {
1911 MEDIA_LOG_I("Seek notify read thread to stop");
1912 std::unique_lock<std::mutex> waitLock(seekWaitMutex_);
1913 ioContext_.readCbReady = true;
1914 readCbCv_.notify_all();
1915 seekWaitCv_.wait(waitLock, [this] { return threadState_ == WAITING || threadState_ == NOT_STARTED; });
1916 }
1917 }
1918
IsUseFirstFrameDts(int trackIndex,int64_t seekTime)1919 bool FFmpegDemuxerPlugin::IsUseFirstFrameDts(int trackIndex, int64_t seekTime)
1920 {
1921 if (seekTime == 0 &&
1922 (fileType_ == FileType::MPEGTS || FFmpegFormatHelper::IsMpeg4File(fileType_)) &&
1923 FFmpegFormatHelper::IsVideoType(*(formatContext_->streams[trackIndex])) &&
1924 VideoFirstFrameValid(trackIndex)) {
1925 return true;
1926 }
1927 return false;
1928 }
1929
DoSeekInternal(int trackIndex,int64_t seekTime,int64_t ffTime,SeekMode mode,int64_t & realSeekTime)1930 Status FFmpegDemuxerPlugin::DoSeekInternal(int trackIndex, int64_t seekTime, int64_t ffTime,
1931 SeekMode mode, int64_t& realSeekTime)
1932 {
1933 auto avStream = formatContext_->streams[trackIndex];
1934 FALSE_RETURN_V_MSG_E(avStream != nullptr, Status::ERROR_NULL_POINTER, "AVStream is nullptr");
1935 realSeekTime = ConvertTimeFromFFmpeg(ffTime, avStream->time_base);
1936 int flag = ConvertFlagsToFFmpeg(avStream, ffTime, mode, seekTime);
1937 MEDIA_LOG_I("Time [" PUBLIC_LOG_U64 "/" PUBLIC_LOG_U64 "/" PUBLIC_LOG_D64 "] flag ["
1938 PUBLIC_LOG_D32 "/" PUBLIC_LOG_D32 "]",
1939 seekTime, ffTime, realSeekTime, static_cast<int32_t>(mode), flag);
1940 if (flag == AVSEEK_FLAG_FRAME && FFmpegFormatHelper::IsMpeg4File(fileType_)) {
1941 int keyFrameNext = av_index_search_timestamp(avStream, ffTime, AVSEEK_FLAG_FRAME);
1942 FALSE_RETURN_V_MSG_E(keyFrameNext >= 0, Status::ERROR_OUT_OF_RANGE,
1943 "Seek failed, err: Not next key frame");
1944 }
1945 std::unique_lock<std::mutex> sLock(syncMutex_);
1946 auto ret = av_seek_frame(formatContext_.get(), trackIndex, ffTime, flag);
1947 sLock.unlock();
1948 formatContext_->pb->error = 0;
1949 FALSE_RETURN_V_MSG_E(ret >= 0, Status::ERROR_UNKNOWN,
1950 "Call av_seek_frame failed, err: " PUBLIC_LOG_S, AVStrError(ret).c_str());
1951 if (readLoopStatus_ != Status::OK) {
1952 MEDIA_LOG_E("Read loop status is not OK, release thread");
1953 ReleaseFFmpegReadLoop();
1954 }
1955 for (size_t i = 0; i < selectedTrackIds_.size(); ++i) {
1956 cacheQueue_.RemoveTrackQueue(selectedTrackIds_[i]);
1957 cacheQueue_.AddTrackQueue(selectedTrackIds_[i]);
1958 }
1959 seekTime_ = seekTime;
1960 seekMode_ = flag == AVSEEK_FLAG_BACKWARD ? SeekMode::SEEK_PREVIOUS_SYNC : mode;
1961 return Status::OK;
1962 }
1963
IsEnableSeekTimeCalib(const std::shared_ptr<AVFormatContext> & formatContext)1964 static bool IsEnableSeekTimeCalib(const std::shared_ptr<AVFormatContext> &formatContext)
1965 {
1966 FALSE_RETURN_V_MSG_E(formatContext != nullptr, false, "AVFormatContext is nullptr");
1967 if (FileType::FLV == FFmpegFormatHelper::GetFileTypeByName(*formatContext)) {
1968 return true;
1969 }
1970 return false;
1971 }
1972
SeekTo(int32_t trackId,int64_t seekTime,SeekMode mode,int64_t & realSeekTime)1973 Status FFmpegDemuxerPlugin::SeekTo(int32_t trackId, int64_t seekTime, SeekMode mode, int64_t& realSeekTime)
1974 {
1975 (void) trackId;
1976 std::lock_guard<std::shared_mutex> lock(sharedMutex_);
1977 MediaAVCodec::AVCodecTrace trace("SeekTo");
1978
1979 Status check = CheckSeekParams(seekTime, mode);
1980 FALSE_RETURN_V_MSG_E(check == Status::OK, check, "CheckSeekParams failed");
1981 if (readThread_ != nullptr) {
1982 SyncSeekThread();
1983 }
1984 int trackIndex = SelectSeekTrack();
1985 MEDIA_LOG_D("Seek based on track " PUBLIC_LOG_D32, trackIndex);
1986
1987 auto avStream = formatContext_->streams[trackIndex];
1988 FALSE_RETURN_V_MSG_E(avStream != nullptr, Status::ERROR_NULL_POINTER, "AVStream is nullptr");
1989 int64_t ffTime = ConvertTimeToFFmpeg(seekTime * MS_TO_NS, avStream->time_base);
1990 if (!CheckStartTime(formatContext_.get(), avStream, ffTime, seekTime)) {
1991 MEDIA_LOG_E("Get start time from track " PUBLIC_LOG_D32 " failed", trackIndex);
1992 return Status::ERROR_INVALID_OPERATION;
1993 }
1994
1995 if (IsEnableSeekTimeCalib(formatContext_) && seekCalibMap_.count(trackIndex) > 0) {
1996 int64_t calibTime = ffTime - seekCalibMap_[trackIndex];
1997 auto ret = DoSeekInternal(trackIndex, seekTime, calibTime, mode, realSeekTime);
1998 if (ret == Status::OK) {
1999 return ret;
2000 }
2001 MEDIA_LOG_E("Seek using calibTime " PUBLIC_LOG_D64 " failed", calibTime);
2002 }
2003
2004 if (IsUseFirstFrameDts(trackIndex, seekTime)) {
2005 ffTime = videoFirstFrameMap_[trackIndex]->dts;
2006 }
2007
2008 return DoSeekInternal(trackIndex, seekTime, ffTime, mode, realSeekTime);
2009 }
2010
Flush()2011 Status FFmpegDemuxerPlugin::Flush()
2012 {
2013 Status ret = Status::OK;
2014 std::lock_guard<std::shared_mutex> lock(sharedMutex_);
2015 MEDIA_LOG_I("In");
2016 if (ioContext_.invokerType != InvokerType::FLUSH) {
2017 std::lock_guard<std::mutex> seekLock(ioContext_.invokerTypeMutex);
2018 ioContext_.invokerType = InvokerType::FLUSH;
2019 }
2020 for (size_t i = 0; i < selectedTrackIds_.size(); ++i) {
2021 ret = cacheQueue_.RemoveTrackQueue(selectedTrackIds_[i]);
2022 ret = cacheQueue_.AddTrackQueue(selectedTrackIds_[i]);
2023 }
2024 if (formatContext_) {
2025 std::unique_lock<std::mutex> sLock(syncMutex_);
2026 avio_flush(formatContext_.get()->pb);
2027 avformat_flush(formatContext_.get());
2028 sLock.unlock();
2029 }
2030 return ret;
2031 }
2032
ResetEosStatus()2033 void FFmpegDemuxerPlugin::ResetEosStatus()
2034 {
2035 MEDIA_LOG_I("In");
2036 if (formatContext_ != nullptr && formatContext_->pb != nullptr) {
2037 formatContext_->pb->eof_reached = 0;
2038 formatContext_->pb->error = 0;
2039 }
2040 }
2041
DumpPacketInfo(int32_t trackId,Stage stage)2042 void FFmpegDemuxerPlugin::DumpPacketInfo(int32_t trackId, Stage stage)
2043 {
2044 if (trackDfxInfoMap_.count(trackId) <= 0) {
2045 return;
2046 }
2047 if (stage == Stage::FIRST_READ && !trackDfxInfoMap_[trackId].dumpFirstInfo) {
2048 MEDIA_LOG_I("Info Track[" PUBLIC_LOG_D32 "] [first] [" PUBLIC_LOG_D64 "/" PUBLIC_LOG_D64 "/" PUBLIC_LOG_D64 "]",
2049 trackId, trackDfxInfoMap_[trackId].lastPts,
2050 trackDfxInfoMap_[trackId].lastDuration, trackDfxInfoMap_[trackId].lastPos);
2051 trackDfxInfoMap_[trackId].dumpFirstInfo = true;
2052 } else if (stage == Stage::FILE_END) {
2053 MEDIA_LOG_I("Info Track[" PUBLIC_LOG_D32 "] [eos] [" PUBLIC_LOG_D64 "/" PUBLIC_LOG_D64 "/" PUBLIC_LOG_D64 "]",
2054 trackId, trackDfxInfoMap_[trackId].lastPts,
2055 trackDfxInfoMap_[trackId].lastDuration, trackDfxInfoMap_[trackId].lastPos);
2056 }
2057 }
2058
ClearUnselectTrackCache()2059 void FFmpegDemuxerPlugin::ClearUnselectTrackCache()
2060 {
2061 for (uint32_t trackIndex = 0; trackIndex < formatContext_->nb_streams; ++trackIndex) {
2062 if (TrackIsSelected(trackIndex)) {
2063 continue;
2064 }
2065 trackMtx_.erase(trackIndex);
2066 trackDfxInfoMap_.erase(trackIndex);
2067 if (cacheQueue_.RemoveTrackQueue(trackIndex) != Status::OK) {
2068 MEDIA_LOG_W("Reset track cache failed: " PUBLIC_LOG_U32, trackIndex);
2069 }
2070 }
2071 }
2072
FrameReady(Status ret)2073 bool FFmpegDemuxerPlugin::FrameReady(Status ret)
2074 {
2075 if (ret == Status::END_OF_STREAM) {
2076 MEDIA_LOG_D("Read to end");
2077 return true;
2078 }
2079 FALSE_RETURN_V_MSG_E(ret != Status::ERROR_UNKNOWN, false, "Read from ffmpeg failed");
2080 FALSE_RETURN_V_MSG_E(ret != Status::ERROR_AGAIN, false, "Read from ffmpeg failed, retry");
2081 FALSE_RETURN_V_MSG_E(ret != Status::ERROR_NO_MEMORY, false, "Cache size out of limit");
2082 FALSE_RETURN_V_MSG_E(ret != Status::ERROR_WRONG_STATE, false, "Read from ffmpeg failed interrupt");
2083 return true;
2084 }
2085
ReadSample(uint32_t trackId,std::shared_ptr<AVBuffer> sample)2086 Status FFmpegDemuxerPlugin::ReadSample(uint32_t trackId, std::shared_ptr<AVBuffer> sample)
2087 {
2088 std::shared_lock<std::shared_mutex> lock(sharedMutex_);
2089 MediaAVCodec::AVCodecTrace trace("ReadSample");
2090 MEDIA_LOG_D("In");
2091 FALSE_RETURN_V_MSG_E(formatContext_ != nullptr, Status::ERROR_NULL_POINTER, "AVFormatContext is nullptr");
2092 FALSE_RETURN_V_MSG_E(!selectedTrackIds_.empty(), Status::ERROR_INVALID_OPERATION, "No track has been selected");
2093 FALSE_RETURN_V_MSG_E(TrackIsSelected(trackId), Status::ERROR_INVALID_PARAMETER, "Track has not been selected");
2094 FALSE_RETURN_V_MSG_E(sample != nullptr && sample->memory_ != nullptr, Status::ERROR_INVALID_PARAMETER,
2095 "AVBuffer or memory is nullptr");
2096 FALSE_RETURN_V_MSG_E(readModeMap_.find(1) == readModeMap_.end(), Status::ERROR_INVALID_OPERATION,
2097 "Cannot use sync and async Read together");
2098 if (needClear_) {
2099 ClearUnselectTrackCache();
2100 needClear_ = false;
2101 }
2102 readModeMap_[0] = 1;
2103 Status ret;
2104 if (NeedCombineFrame(trackId) && cacheQueue_.GetCacheSize(trackId) == 1) {
2105 ret = ReadPacketToCacheQueue(trackId);
2106 }
2107 while (!cacheQueue_.HasCache(trackId)) {
2108 FALSE_RETURN_V_MSG_E(!isInterruptNeeded_.load(), Status::ERROR_WRONG_STATE, " ReadSample interrupt");
2109 ret = ReadPacketToCacheQueue(trackId);
2110 bool frameReady = FrameReady(ret);
2111 FALSE_RETURN_V_MSG_E(frameReady, ret, "Read from ffmpeg failed");
2112 }
2113 std::lock_guard<std::mutex> lockTrack(*trackMtx_[trackId].get());
2114 auto samplePacket = cacheQueue_.Front(trackId);
2115 FALSE_RETURN_V_MSG_E(samplePacket != nullptr, Status::ERROR_NULL_POINTER, "Cache packet is nullptr");
2116 if (samplePacket->isEOS) {
2117 ret = SetEosSample(sample);
2118 if (ret == Status::OK) {
2119 DumpPacketInfo(trackId, Stage::FILE_END);
2120 cacheQueue_.Pop(trackId);
2121 }
2122 return ret;
2123 }
2124 ret = ConvertAVPacketToSample(sample, samplePacket);
2125 DumpPacketInfo(trackId, Stage::FIRST_READ);
2126 if (ret == Status::ERROR_NOT_ENOUGH_DATA) {
2127 return Status::OK;
2128 } else if (ret == Status::OK) {
2129 MEDIA_LOG_D("All partial sample has been copied");
2130 cacheQueue_.Pop(trackId);
2131 }
2132 return ret;
2133 }
2134
GetNextSampleSize(uint32_t trackId,int32_t & size)2135 Status FFmpegDemuxerPlugin::GetNextSampleSize(uint32_t trackId, int32_t& size)
2136 {
2137 std::shared_lock<std::shared_mutex> lock(sharedMutex_);
2138 MediaAVCodec::AVCodecTrace trace("GetNextSampleSize");
2139 MEDIA_LOG_D("In, track " PUBLIC_LOG_D32, trackId);
2140 FALSE_RETURN_V_MSG_E(formatContext_ != nullptr, Status::ERROR_UNKNOWN, "AVFormatContext is nullptr");
2141 FALSE_RETURN_V_MSG_E(TrackIsSelected(trackId), Status::ERROR_UNKNOWN, "Track has not been selected");
2142 FALSE_RETURN_V_MSG_E(readModeMap_.find(1) == readModeMap_.end(), Status::ERROR_INVALID_OPERATION,
2143 "Cannot use sync and async Read together");
2144 readModeMap_[0] = 1;
2145 Status ret;
2146 if (NeedCombineFrame(trackId) && cacheQueue_.GetCacheSize(trackId) == 1) {
2147 ret = ReadPacketToCacheQueue(trackId);
2148 }
2149 while (!cacheQueue_.HasCache(trackId)) {
2150 ret = ReadPacketToCacheQueue(trackId);
2151 bool frameReady = FrameReady(ret);
2152 FALSE_RETURN_V_MSG_E(frameReady, ret, "Read from ffmpeg failed");
2153 }
2154 std::shared_ptr<SamplePacket> samplePacket = cacheQueue_.Front(trackId);
2155 FALSE_RETURN_V_MSG_E(samplePacket != nullptr, Status::ERROR_UNKNOWN, "Cache sample is nullptr");
2156 if (samplePacket->isEOS) {
2157 MEDIA_LOG_I("Track " PUBLIC_LOG_D32 " eos", trackId);
2158 return Status::END_OF_STREAM;
2159 }
2160 FALSE_RETURN_V_MSG_E(samplePacket->pkts.size() > 0, Status::ERROR_UNKNOWN, "Cache sample is empty");
2161 int totalSize = 0;
2162 for (auto pkt : samplePacket->pkts) {
2163 FALSE_RETURN_V_MSG_E(pkt != nullptr, Status::ERROR_UNKNOWN, "Packet in sample is nullptr");
2164 totalSize += pkt->size;
2165 }
2166
2167 FALSE_RETURN_V_MSG_E(trackId < formatContext_->nb_streams, Status::ERROR_UNKNOWN, "Track is out of range");
2168 AVStream* avStream = formatContext_->streams[trackId];
2169 FALSE_RETURN_V_MSG_E(avStream != nullptr && avStream->codecpar != nullptr,
2170 Status::ERROR_UNKNOWN, "AVStream is nullptr");
2171 if ((std::count(g_streamContainedXPS.begin(), g_streamContainedXPS.end(), avStream->codecpar->codec_id) > 0) &&
2172 static_cast<uint32_t>(samplePacket->pkts[0]->flags) & static_cast<uint32_t>(AV_PKT_FLAG_KEY)) {
2173 totalSize += avStream->codecpar->extradata_size;
2174 }
2175 size = totalSize;
2176 return Status::OK;
2177 }
2178
InitPTSandIndexConvert()2179 void FFmpegDemuxerPlugin::InitPTSandIndexConvert()
2180 {
2181 indexToRelativePTSFrameCount_ = 0; // init IndexToRelativePTSFrameCount_
2182 relativePTSToIndexPosition_ = 0; // init RelativePTSToIndexPosition_
2183 indexToRelativePTSMaxHeap_ = std::priority_queue<int64_t>(); // init IndexToRelativePTSMaxHeap_
2184 relativePTSToIndexPTSMin_ = INT64_MAX;
2185 relativePTSToIndexPTSMax_ = INT64_MIN;
2186 relativePTSToIndexRightDiff_ = INT64_MAX;
2187 relativePTSToIndexLeftDiff_ = INT64_MAX;
2188 relativePTSToIndexTempDiff_ = INT64_MAX;
2189 }
2190
GetIndexByRelativePresentationTimeUs(const uint32_t trackIndex,const uint64_t relativePresentationTimeUs,uint32_t & index)2191 Status FFmpegDemuxerPlugin::GetIndexByRelativePresentationTimeUs(const uint32_t trackIndex,
2192 const uint64_t relativePresentationTimeUs, uint32_t &index)
2193 {
2194 FALSE_RETURN_V_MSG_E(formatContext_ != nullptr, Status::ERROR_NULL_POINTER, "AVFormatContext is nullptr");
2195
2196 FALSE_RETURN_V_MSG_E(FFmpegFormatHelper::IsMpeg4File(fileType_),
2197 Status::ERROR_MISMATCHED_TYPE, "FileType is not MP4");
2198
2199 FALSE_RETURN_V_MSG_E(trackIndex < formatContext_->nb_streams, Status::ERROR_INVALID_DATA, "Track is out of range");
2200 bool frameCheck = IsLessMaxReferenceParserFrames(trackIndex);
2201 FALSE_RETURN_V_MSG_E(frameCheck, Status::ERROR_INVALID_DATA, "Frame count exceeds limit");
2202
2203 InitPTSandIndexConvert();
2204
2205 auto avStream = formatContext_->streams[trackIndex];
2206 FALSE_RETURN_V_MSG_E(avStream != nullptr, Status::ERROR_NULL_POINTER, "AVStream is nullptr");
2207
2208 Status ret = GetPresentationTimeUsFromFfmpegMOV(GET_FIRST_PTS, trackIndex,
2209 static_cast<int64_t>(relativePresentationTimeUs), index);
2210 FALSE_RETURN_V_MSG_E(ret == Status::OK, Status::ERROR_UNKNOWN, "Get pts failed");
2211
2212 int64_t absolutePTS = static_cast<int64_t>(relativePresentationTimeUs) + absolutePTSIndexZero_;
2213
2214 ret = GetPresentationTimeUsFromFfmpegMOV(RELATIVEPTS_TO_INDEX, trackIndex,
2215 absolutePTS, index);
2216 FALSE_RETURN_V_MSG_E(ret == Status::OK, Status::ERROR_UNKNOWN, "Get pts failed");
2217
2218 if (absolutePTS < relativePTSToIndexPTSMin_ || absolutePTS > relativePTSToIndexPTSMax_) {
2219 MEDIA_LOG_E("Pts is out of range");
2220 return Status::ERROR_INVALID_DATA;
2221 }
2222
2223 if (relativePTSToIndexLeftDiff_ == 0 || relativePTSToIndexRightDiff_ == 0) {
2224 index = relativePTSToIndexPosition_;
2225 } else {
2226 index = relativePTSToIndexLeftDiff_ < relativePTSToIndexRightDiff_ ?
2227 relativePTSToIndexPosition_ - 1 : relativePTSToIndexPosition_;
2228 }
2229 return Status::OK;
2230 }
2231
GetRelativePresentationTimeUsByIndex(const uint32_t trackIndex,const uint32_t index,uint64_t & relativePresentationTimeUs)2232 Status FFmpegDemuxerPlugin::GetRelativePresentationTimeUsByIndex(const uint32_t trackIndex,
2233 const uint32_t index, uint64_t &relativePresentationTimeUs)
2234 {
2235 FALSE_RETURN_V_MSG_E(formatContext_ != nullptr, Status::ERROR_NULL_POINTER, "AVFormatContext is nullptr");
2236 FALSE_RETURN_V_MSG_E(index < UINT32_MAX, Status::ERROR_INVALID_DATA, "Index is out of range");
2237 FALSE_RETURN_V_MSG_E(FFmpegFormatHelper::IsMpeg4File(fileType_),
2238 Status::ERROR_MISMATCHED_TYPE, "FileType is not MP4");
2239
2240 FALSE_RETURN_V_MSG_E(trackIndex < formatContext_->nb_streams, Status::ERROR_INVALID_DATA, "Track is out of range");
2241 bool frameCheck = IsLessMaxReferenceParserFrames(trackIndex);
2242 FALSE_RETURN_V_MSG_E(frameCheck, Status::ERROR_INVALID_DATA, "Frame count exceeds limit");
2243
2244 InitPTSandIndexConvert();
2245
2246 auto avStream = formatContext_->streams[trackIndex];
2247 FALSE_RETURN_V_MSG_E(avStream != nullptr, Status::ERROR_NULL_POINTER, "AVStream is nullptr");
2248
2249 Status ret = GetPresentationTimeUsFromFfmpegMOV(GET_FIRST_PTS, trackIndex,
2250 static_cast<int64_t>(relativePresentationTimeUs), index);
2251 FALSE_RETURN_V_MSG_E(ret == Status::OK, Status::ERROR_UNKNOWN, "Get pts failed");
2252
2253 ret = GetPresentationTimeUsFromFfmpegMOV(INDEX_TO_RELATIVEPTS, trackIndex,
2254 static_cast<int64_t>(relativePresentationTimeUs), index);
2255 FALSE_RETURN_V_MSG_E(ret == Status::OK, Status::ERROR_UNKNOWN, "Get pts failed");
2256
2257 if (index + 1 > indexToRelativePTSFrameCount_) {
2258 MEDIA_LOG_E("Index is out of range");
2259 return Status::ERROR_INVALID_DATA;
2260 }
2261
2262 int64_t relativepts = indexToRelativePTSMaxHeap_.top() - absolutePTSIndexZero_;
2263 FALSE_RETURN_V_MSG_E(relativepts >= 0, Status::ERROR_INVALID_DATA, "Existence of calculation results less than 0");
2264 relativePresentationTimeUs = static_cast<uint64_t>(relativepts);
2265
2266 return Status::OK;
2267 }
2268
PTSAndIndexConvertSttsAndCttsProcess(IndexAndPTSConvertMode mode,const AVStream * avStream,int64_t absolutePTS,uint32_t index)2269 Status FFmpegDemuxerPlugin::PTSAndIndexConvertSttsAndCttsProcess(IndexAndPTSConvertMode mode,
2270 const AVStream* avStream, int64_t absolutePTS, uint32_t index)
2271 {
2272 uint32_t sttsIndex = 0;
2273 uint32_t cttsIndex = 0;
2274 int64_t pts = 0; // init pts
2275 int64_t dts = 0; // init dts
2276 ptsCnt_ = 0;
2277 int32_t sttsCurNum = static_cast<int32_t>(avStream->stts_data[sttsIndex].count);
2278 int32_t cttsCurNum = static_cast<int32_t>(avStream->ctts_data[cttsIndex].count);
2279 while (sttsIndex < avStream->stts_count && cttsIndex < avStream->ctts_count &&
2280 cttsCurNum >= 0 && sttsCurNum >= 0) {
2281 if (cttsCurNum == 0) {
2282 cttsIndex++;
2283 if (cttsIndex >= avStream->ctts_count) {
2284 break;
2285 }
2286 cttsCurNum = static_cast<int32_t>(avStream->ctts_data[cttsIndex].count);
2287 }
2288 cttsCurNum--;
2289 if ((INT64_MAX / 1000 / 1000) < // 1000 is used for converting pts to us
2290 ((dts + static_cast<int64_t>(avStream->ctts_data[cttsIndex].duration)) /
2291 static_cast<int64_t>(avStream->time_scale))) {
2292 MEDIA_LOG_E("pts overflow");
2293 return Status::ERROR_INVALID_DATA;
2294 }
2295 double timeScaleRate = static_cast<double>(MS_TO_NS) / static_cast<double>(avStream->time_scale);
2296 double ptsTemp = static_cast<double>(dts) + static_cast<double>(avStream->ctts_data[cttsIndex].duration);
2297 pts = static_cast<int64_t>(ptsTemp * timeScaleRate);
2298 if (mode == GET_ALL_FRAME_PTS) {
2299 if (ptsCnt_ >= REFERENCE_PARSER_PTS_LIST_UPPER_LIMIT) {
2300 MEDIA_LOG_I("PTS cnt has reached the maximum limit");
2301 break;
2302 }
2303 ptsCnt_++;
2304 }
2305 PTSAndIndexConvertSwitchProcess(mode, pts, absolutePTS, index, static_cast<int64_t>(dts * timeScaleRate));
2306 sttsCurNum--;
2307 if ((INT64_MAX - dts) < (static_cast<int64_t>(avStream->stts_data[sttsIndex].duration))) {
2308 MEDIA_LOG_E("dts overflow");
2309 return Status::ERROR_INVALID_DATA;
2310 }
2311 dts += static_cast<int64_t>(avStream->stts_data[sttsIndex].duration);
2312 if (sttsCurNum == 0) {
2313 sttsIndex++;
2314 sttsCurNum = sttsIndex < avStream->stts_count ?
2315 static_cast<int32_t>(avStream->stts_data[sttsIndex].count) : 0;
2316 }
2317 }
2318 return Status::OK;
2319 }
2320
PTSAndIndexConvertOnlySttsProcess(IndexAndPTSConvertMode mode,const AVStream * avStream,int64_t absolutePTS,uint32_t index)2321 Status FFmpegDemuxerPlugin::PTSAndIndexConvertOnlySttsProcess(IndexAndPTSConvertMode mode,
2322 const AVStream* avStream, int64_t absolutePTS, uint32_t index)
2323 {
2324 uint32_t sttsIndex = 0;
2325 int64_t pts = 0; // init pts
2326 int64_t dts = 0; // init dts
2327 ptsCnt_ = 0;
2328 int32_t sttsCurNum = static_cast<int32_t>(avStream->stts_data[sttsIndex].count);
2329 while (sttsIndex < avStream->stts_count && sttsCurNum >= 0) {
2330 if ((INT64_MAX / 1000 / 1000) < // 1000 is used for converting pts to us
2331 (dts / static_cast<int64_t>(avStream->time_scale))) {
2332 MEDIA_LOG_E("pts overflow");
2333 return Status::ERROR_INVALID_DATA;
2334 }
2335 double timeScaleRate = static_cast<double>(MS_TO_NS) / static_cast<double>(avStream->time_scale);
2336 double ptsTemp = static_cast<double>(dts);
2337 pts = static_cast<int64_t>(ptsTemp * timeScaleRate);
2338 if (mode == GET_ALL_FRAME_PTS) {
2339 if (ptsCnt_ >= REFERENCE_PARSER_PTS_LIST_UPPER_LIMIT) {
2340 MEDIA_LOG_I("PTS cnt has reached the maximum limit");
2341 break;
2342 }
2343 ptsCnt_++;
2344 }
2345 PTSAndIndexConvertSwitchProcess(mode, pts, absolutePTS, index, pts);
2346 sttsCurNum--;
2347 if ((INT64_MAX - dts) < (static_cast<int64_t>(avStream->stts_data[sttsIndex].duration))) {
2348 MEDIA_LOG_E("dts overflow");
2349 return Status::ERROR_INVALID_DATA;
2350 }
2351 dts += static_cast<int64_t>(avStream->stts_data[sttsIndex].duration);
2352 if (sttsCurNum == 0) {
2353 sttsIndex++;
2354 sttsCurNum = sttsIndex < avStream->stts_count ?
2355 static_cast<int32_t>(avStream->stts_data[sttsIndex].count) : 0;
2356 }
2357 }
2358 return Status::OK;
2359 }
2360
GetPresentationTimeUsFromFfmpegMOV(IndexAndPTSConvertMode mode,uint32_t trackIndex,int64_t absolutePTS,uint32_t index)2361 Status FFmpegDemuxerPlugin::GetPresentationTimeUsFromFfmpegMOV(IndexAndPTSConvertMode mode,
2362 uint32_t trackIndex, int64_t absolutePTS, uint32_t index)
2363 {
2364 auto avStream = formatContext_->streams[trackIndex];
2365 FALSE_RETURN_V_MSG_E(avStream != nullptr, Status::ERROR_NULL_POINTER, "AVStream is nullptr");
2366 FALSE_RETURN_V_MSG_E(avStream->stts_data != nullptr && avStream->stts_count != 0,
2367 Status::ERROR_NULL_POINTER, "AVStream->stts_data is empty");
2368 FALSE_RETURN_V_MSG_E(avStream->time_scale != 0, Status::ERROR_INVALID_DATA, "AVStream->time_scale is zero");
2369 return avStream->ctts_data == nullptr ?
2370 PTSAndIndexConvertOnlySttsProcess(mode, avStream, absolutePTS, index) :
2371 PTSAndIndexConvertSttsAndCttsProcess(mode, avStream, absolutePTS, index);
2372 }
2373
PTSAndIndexConvertSwitchProcess(IndexAndPTSConvertMode mode,int64_t pts,int64_t absolutePTS,uint32_t index,int64_t dts)2374 void FFmpegDemuxerPlugin::PTSAndIndexConvertSwitchProcess(IndexAndPTSConvertMode mode,
2375 int64_t pts, int64_t absolutePTS, uint32_t index, int64_t dts)
2376 {
2377 switch (mode) {
2378 case GET_FIRST_PTS:
2379 absolutePTSIndexZero_ = pts < absolutePTSIndexZero_ ? pts : absolutePTSIndexZero_;
2380 break;
2381 case INDEX_TO_RELATIVEPTS:
2382 IndexToRelativePTSProcess(pts, index);
2383 break;
2384 case RELATIVEPTS_TO_INDEX:
2385 RelativePTSToIndexProcess(pts, absolutePTS);
2386 break;
2387 case GET_ALL_FRAME_PTS:
2388 if (dts == 0L) {
2389 minPts_ = pts;
2390 MEDIA_LOG_I("minPts=" PUBLIC_LOG_D64, minPts_);
2391 }
2392 MEDIA_LOG_D("dts " PUBLIC_LOG_D64 ", pts " PUBLIC_LOG_D64 ", frameId " PUBLIC_LOG_ZU,
2393 dts - minPts_, pts - minPts_, pts2DtsMap_.size());
2394 pts2DtsMap_.emplace(pts - minPts_, dts - minPts_);
2395 break;
2396 default:
2397 MEDIA_LOG_E("Wrong mode");
2398 break;
2399 }
2400 }
2401
IndexToRelativePTSProcess(int64_t pts,uint32_t index)2402 void FFmpegDemuxerPlugin::IndexToRelativePTSProcess(int64_t pts, uint32_t index)
2403 {
2404 if (indexToRelativePTSMaxHeap_.size() < index + 1) {
2405 indexToRelativePTSMaxHeap_.push(pts);
2406 } else {
2407 if (pts < indexToRelativePTSMaxHeap_.top()) {
2408 indexToRelativePTSMaxHeap_.pop();
2409 indexToRelativePTSMaxHeap_.push(pts);
2410 }
2411 }
2412 indexToRelativePTSFrameCount_++;
2413 }
2414
RelativePTSToIndexProcess(int64_t pts,int64_t absolutePTS)2415 void FFmpegDemuxerPlugin::RelativePTSToIndexProcess(int64_t pts, int64_t absolutePTS)
2416 {
2417 if (relativePTSToIndexPTSMin_ > pts) {
2418 relativePTSToIndexPTSMin_ = pts;
2419 }
2420 if (relativePTSToIndexPTSMax_ < pts) {
2421 relativePTSToIndexPTSMax_ = pts;
2422 }
2423 relativePTSToIndexTempDiff_ = abs(pts - absolutePTS);
2424 if (pts < absolutePTS && relativePTSToIndexTempDiff_ < relativePTSToIndexLeftDiff_) {
2425 relativePTSToIndexLeftDiff_ = relativePTSToIndexTempDiff_;
2426 }
2427 if (pts >= absolutePTS && relativePTSToIndexTempDiff_ < relativePTSToIndexRightDiff_) {
2428 relativePTSToIndexRightDiff_ = relativePTSToIndexTempDiff_;
2429 }
2430 if (pts < absolutePTS) {
2431 relativePTSToIndexPosition_++;
2432 }
2433 }
2434
CheckCacheDataLimit(uint32_t trackId)2435 Status FFmpegDemuxerPlugin::CheckCacheDataLimit(uint32_t trackId)
2436 {
2437 if (!outOfLimit_) {
2438 auto cacheDataSize = cacheQueue_.GetCacheDataSize(trackId);
2439 if (cacheDataSize > cachelimitSize_) {
2440 MEDIA_LOG_W("Track " PUBLIC_LOG_U32 " cache out of limit: " PUBLIC_LOG_U32 "/" PUBLIC_LOG_U32 ", by user "
2441 PUBLIC_LOG_D32, trackId, cacheDataSize, cachelimitSize_, static_cast<int32_t>(setLimitByUser));
2442 outOfLimit_ = true;
2443 }
2444 }
2445 return Status::OK;
2446 }
2447
SetCacheLimit(uint32_t limitSize)2448 void FFmpegDemuxerPlugin::SetCacheLimit(uint32_t limitSize)
2449 {
2450 setLimitByUser = true;
2451 cachelimitSize_ = limitSize;
2452 }
2453
GetCurrentCacheSize(uint32_t trackId,uint32_t & size)2454 Status FFmpegDemuxerPlugin::GetCurrentCacheSize(uint32_t trackId, uint32_t& size)
2455 {
2456 MEDIA_LOG_D("TrackId " PUBLIC_LOG_U32, trackId);
2457 FALSE_RETURN_V_MSG_E(formatContext_ != nullptr, Status::ERROR_NULL_POINTER, "AVFormatContext is nullptr");
2458 FALSE_RETURN_V_MSG_E(!selectedTrackIds_.empty(), Status::ERROR_INVALID_OPERATION, "No track has been selected");
2459 FALSE_RETURN_V_MSG_E(TrackIsSelected(trackId), Status::ERROR_INVALID_PARAMETER, "Track has not been selected");
2460 uint32_t dataSize = cacheQueue_.GetCacheDataSize(trackId);
2461 FALSE_RETURN_V_MSG_E(dataSize < UINT32_MAX, Status::ERROR_WRONG_STATE, "CacheSize is invalid");
2462 size = dataSize;
2463 return Status::OK;
2464 }
2465
SetInterruptState(bool isInterruptNeeded)2466 void FFmpegDemuxerPlugin::SetInterruptState(bool isInterruptNeeded)
2467 {
2468 MEDIA_LOG_I("SetInterruptState %{public}d", isInterruptNeeded);
2469 isInterruptNeeded_ = isInterruptNeeded;
2470 }
2471
2472 namespace { // plugin set
2473
IsStartWithID3(const uint8_t * buf,const char * tagName)2474 int IsStartWithID3(const uint8_t *buf, const char *tagName)
2475 {
2476 return buf[POS_0] == tagName[POS_0] &&
2477 buf[POS_1] == tagName[POS_1] &&
2478 buf[POS_2] == tagName[POS_2] &&
2479 buf[POS_3] != POS_FF &&
2480 buf[POS_4] != POS_FF &&
2481 (buf[POS_6] & TAG_MASK) == 0 &&
2482 (buf[POS_7] & TAG_MASK) == 0 &&
2483 (buf[POS_8] & TAG_MASK) == 0 &&
2484 (buf[POS_9] & TAG_MASK) == 0;
2485 }
2486
GetID3TagLen(const uint8_t * buf)2487 int GetID3TagLen(const uint8_t *buf)
2488 {
2489 int32_t len = ((buf[POS_6] & LEN_MASK) << POS_21) + ((buf[POS_7] & LEN_MASK) << POS_14) +
2490 ((buf[POS_8] & LEN_MASK) << POS_7) + (buf[POS_9] & LEN_MASK) +
2491 static_cast<int32_t>(ID3V2_HEADER_SIZE);
2492 if (buf[POS_5] & TAG_VERSION_MASK) {
2493 len += static_cast<int32_t>(ID3V2_HEADER_SIZE);
2494 }
2495 return len;
2496 }
2497
GetConfidence(std::shared_ptr<AVInputFormat> plugin,const std::string & pluginName,std::shared_ptr<DataSource> dataSource,size_t & getData,size_t bufferSize)2498 int32_t GetConfidence(std::shared_ptr<AVInputFormat> plugin, const std::string& pluginName,
2499 std::shared_ptr<DataSource> dataSource, size_t &getData, size_t bufferSize)
2500 {
2501 uint64_t fileSize = 0;
2502 Status getFileSize = dataSource->GetSize(fileSize);
2503 if (getFileSize == Status::OK) {
2504 bufferSize = (bufferSize < fileSize) ? bufferSize : fileSize;
2505 }
2506 std::vector<uint8_t> buff(bufferSize + AVPROBE_PADDING_SIZE); // fix ffmpeg probe crash, refer to tools/probetest.c
2507 auto bufferInfo = std::make_shared<Buffer>();
2508 auto bufData = bufferInfo->WrapMemory(buff.data(), bufferSize, bufferSize);
2509 FALSE_RETURN_V_MSG_E(bufferInfo->GetMemory() != nullptr, -1,
2510 "Alloc buffer failed for " PUBLIC_LOG_S, pluginName.c_str());
2511 Status ret = Status::OK;
2512 {
2513 std::string traceName = "Sniff_" + pluginName + "_Readat";
2514 MediaAVCodec::AVCodecTrace trace(traceName.c_str());
2515 ret = dataSource->ReadAt(0, bufferInfo, bufferSize);
2516 }
2517 FALSE_RETURN_V_MSG_E(ret == Status::OK, -1, "Read probe data failed for " PUBLIC_LOG_S, pluginName.c_str());
2518 getData = bufferInfo->GetMemory()->GetSize();
2519 FALSE_RETURN_V_MSG_E(getData > 0, -1, "No data for sniff " PUBLIC_LOG_S, pluginName.c_str());
2520 if (getFileSize == Status::OK && getData > ID3V2_HEADER_SIZE && IsStartWithID3(buff.data(), "ID3")) {
2521 int32_t id3Len = GetID3TagLen(buff.data());
2522 // id3 tag length is out of file, or file just contains id3 tag, no valid data.
2523 FALSE_RETURN_V_MSG_E(id3Len >= 0 && static_cast<uint64_t>(id3Len) < fileSize, -1,
2524 "File data error for " PUBLIC_LOG_S, pluginName.c_str());
2525 if (id3Len > 0) {
2526 uint64_t remainSize = fileSize - static_cast<uint64_t>(id3Len);
2527 bufferSize = (bufferSize < remainSize) ? bufferSize : remainSize;
2528 int resetRet = memset_s(buff.data(), bufferSize, 0, bufferSize);
2529 FALSE_RETURN_V_MSG_E(resetRet == EOK, -1, "Reset buff failed for " PUBLIC_LOG_S, pluginName.c_str());
2530 ret = dataSource->ReadAt(id3Len, bufferInfo, bufferSize);
2531 FALSE_RETURN_V_MSG_E(ret == Status::OK, -1, "Read probe data failed for " PUBLIC_LOG_S, pluginName.c_str());
2532 getData = bufferInfo->GetMemory()->GetSize();
2533 FALSE_RETURN_V_MSG_E(getData > 0, -1, "No data for sniff " PUBLIC_LOG_S, pluginName.c_str());
2534 }
2535 }
2536 AVProbeData probeData{"", buff.data(), static_cast<int32_t>(getData), ""};
2537 return plugin->read_probe(&probeData);
2538 }
2539
Sniff(const std::string & pluginName,std::shared_ptr<DataSource> dataSource)2540 int Sniff(const std::string& pluginName, std::shared_ptr<DataSource> dataSource)
2541 {
2542 FALSE_RETURN_V_MSG_E(!pluginName.empty(), 0, "Plugin name is empty");
2543 FALSE_RETURN_V_MSG_E(dataSource != nullptr, 0, "DataSource is nullptr");
2544 return SniffWithSize(pluginName, dataSource, DEFAULT_SNIFF_SIZE);
2545 }
2546
SniffWithSize(const std::string & pluginName,std::shared_ptr<DataSource> dataSource,int probSize)2547 int SniffWithSize(const std::string& pluginName, std::shared_ptr<DataSource> dataSource, int probSize)
2548 {
2549 FALSE_RETURN_V_MSG_E(!pluginName.empty(), 0, "Plugin name is empty");
2550 FALSE_RETURN_V_MSG_E(dataSource != nullptr, 0, "DataSource is nullptr");
2551 std::shared_ptr<AVInputFormat> plugin;
2552 {
2553 std::lock_guard<std::mutex> lock(g_mtx);
2554 plugin = g_pluginInputFormat[pluginName];
2555 }
2556 FALSE_RETURN_V_MSG_E((plugin != nullptr && plugin->read_probe), 0,
2557 "Get plugin for " PUBLIC_LOG_S " failed", pluginName.c_str());
2558 size_t getData = 0;
2559 int confidence = GetConfidence(plugin, pluginName, dataSource, getData, probSize);
2560 if (confidence < 0) {
2561 return 0;
2562 }
2563 if (StartWith(plugin->name, PLUGIN_NAME_MP3) && confidence > 0 && confidence <= MP3_PROBE_SCORE_LIMIT) {
2564 MEDIA_LOG_W("Score " PUBLIC_LOG_D32 " is too low", confidence);
2565 confidence = 0;
2566 }
2567 if (getData < DEFAULT_SNIFF_SIZE || confidence > 0) {
2568 MEDIA_LOG_I("Sniff:" PUBLIC_LOG_S "[" PUBLIC_LOG_ZU "/" PUBLIC_LOG_D32 "]", plugin->name, getData, confidence);
2569 }
2570 return confidence;
2571 }
2572
CheckMPEGPSStartCode(std::shared_ptr<DataSource> & dataSource)2573 bool CheckMPEGPSStartCode(std::shared_ptr<DataSource> &dataSource)
2574 {
2575 FALSE_RETURN_V_MSG_E(dataSource != nullptr, false, "DataSource is nullptr");
2576 std::vector<uint8_t> buff(MPEGPS_START_CODE_SIZE);
2577 auto bufferInfo = std::make_shared<Buffer>();
2578 auto bufData = bufferInfo->WrapMemory(buff.data(), MPEGPS_START_CODE_SIZE, MPEGPS_START_CODE_SIZE);
2579 FALSE_RETURN_V_MSG_E(bufferInfo->GetMemory() != nullptr, false, "Alloc buffer failed");
2580
2581 auto ret = dataSource->ReadAt(0, bufferInfo, MPEGPS_START_CODE_SIZE);
2582 FALSE_RETURN_V_MSG_E(ret == Status::OK, false, "Read data failed");
2583 for (int32_t i = 0; i < MPEGPS_START_CODE_SIZE; i++) {
2584 if (buff[i] != MPEGPS_START_CODE[i]) {
2585 return false;
2586 }
2587 }
2588 return true;
2589 }
2590
SniffMPEGPS(const std::string & pluginName,std::shared_ptr<DataSource> dataSource)2591 int SniffMPEGPS(const std::string& pluginName, std::shared_ptr<DataSource> dataSource)
2592 {
2593 FALSE_RETURN_V_MSG_E(!pluginName.empty(), 0, "Plugin name is empty");
2594 FALSE_RETURN_V_MSG_E(dataSource != nullptr, 0, "DataSource is nullptr");
2595 int32_t psScore = SniffWithSize(pluginName, dataSource, DEFAULT_SNIFF_SIZE);
2596 if (psScore >= DEF_PROBE_SCORE_LIMIT) {
2597 std::string mp3PluginName = std::string(PLUGIN_NAME_PREFIX) + std::string(PLUGIN_NAME_MP3);
2598 int32_t mp3Score = SniffWithSize(mp3PluginName, dataSource, DEFAULT_SNIFF_SIZE);
2599 if (mp3Score >= DEF_PROBE_SCORE_LIMIT && !CheckMPEGPSStartCode(dataSource)) {
2600 return 0;
2601 }
2602 }
2603 return psScore;
2604 }
2605
FindSniffer(const std::string & pluginName)2606 static PluginSnifferFunc FindSniffer(const std::string& pluginName)
2607 {
2608 if (g_pluginSnifferMap.find(pluginName) != g_pluginSnifferMap.end()) {
2609 return g_pluginSnifferMap.at(pluginName);
2610 }
2611
2612 return Sniff;
2613 }
2614
ReplaceDelimiter(const std::string & delmiters,char newDelimiter,std::string & str)2615 void ReplaceDelimiter(const std::string& delmiters, char newDelimiter, std::string& str)
2616 {
2617 MEDIA_LOG_D("Reset from [" PUBLIC_LOG_S "]", str.c_str());
2618 for (auto it = str.begin(); it != str.end(); ++it) {
2619 if (delmiters.find(newDelimiter) != std::string::npos) {
2620 *it = newDelimiter;
2621 }
2622 }
2623 MEDIA_LOG_D("Reset to [" PUBLIC_LOG_S "]", str.c_str());
2624 };
2625
RegisterPlugins(const std::shared_ptr<Register> & reg)2626 Status RegisterPlugins(const std::shared_ptr<Register>& reg)
2627 {
2628 MEDIA_LOG_I("In");
2629 FALSE_RETURN_V_MSG_E(reg != nullptr, Status::ERROR_INVALID_PARAMETER, "Register is nullptr");
2630 std::lock_guard<std::mutex> lock(g_mtx);
2631 const AVInputFormat* plugin = nullptr;
2632 void* i = nullptr;
2633 while ((plugin = av_demuxer_iterate(&i))) {
2634 if (plugin == nullptr) {
2635 continue;
2636 }
2637 MEDIA_LOG_D("Check ffmpeg demuxer " PUBLIC_LOG_S "[" PUBLIC_LOG_S "]", plugin->name, plugin->long_name);
2638 std::string pluginName = "avdemux_" + std::string(plugin->name);
2639 ReplaceDelimiter(".,|-<> ", '_', pluginName);
2640
2641 DemuxerPluginDef regInfo;
2642 regInfo.name = pluginName;
2643 regInfo.description = "ffmpeg demuxer plugin";
2644 regInfo.rank = RANK_MAX;
2645 regInfo.AddExtensions(SplitString(plugin->extensions, ','));
2646 g_pluginInputFormat[pluginName] =
2647 std::shared_ptr<AVInputFormat>(const_cast<AVInputFormat*>(plugin), [](void*) {});
2648 auto func = [](const std::string& name) -> std::shared_ptr<DemuxerPlugin> {
2649 return std::make_shared<FFmpegDemuxerPlugin>(name);
2650 };
2651 regInfo.SetCreator(func);
2652 regInfo.SetSniffer(FindSniffer(plugin->name));
2653 auto ret = reg->AddPlugin(regInfo);
2654 if (ret != Status::OK) {
2655 MEDIA_LOG_E("Add plugin failed, err=" PUBLIC_LOG_D32, static_cast<int>(ret));
2656 } else {
2657 MEDIA_LOG_D("Add plugin " PUBLIC_LOG_S, pluginName.c_str());
2658 }
2659 }
2660 FALSE_RETURN_V_MSG_E(!g_pluginInputFormat.empty(), Status::ERROR_UNKNOWN, "Can not load any ffmpeg demuxer");
2661 return Status::OK;
2662 }
2663 } // namespace
__anon8e4663700e02null2664 PLUGIN_DEFINITION(FFmpegDemuxer, LicenseType::LGPL, RegisterPlugins, [] {});
2665 } // namespace Ffmpeg
2666 } // namespace Plugins
2667 } // namespace Media
2668 } // namespace OHOS
2669