• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 HST_LOG_TAG "FfmpegFormatHelper"
17 
18 #include <algorithm>
19 #include <charconv>
20 #include <regex>
21 #include <iconv.h>
22 #include <sstream>
23 #include "ffmpeg_converter.h"
24 #include "meta/meta_key.h"
25 #include "meta/media_types.h"
26 #include "meta/mime_type.h"
27 #include "meta/video_types.h"
28 #include "meta/audio_types.h"
29 #include "common/log.h"
30 #include "ffmpeg_format_helper.h"
31 
32 #ifdef __cplusplus
33 extern "C" {
34 #endif
35 #include "libavutil/avutil.h"
36 #include "libavutil/display.h"
37 #ifdef __cplusplus
38 }
39 #endif
40 
41 #define DISPLAY_MATRIX_SIZE (static_cast<size_t>(9))
42 #define CONVERT_MATRIX_SIZE (static_cast<size_t>(4))
43 #define CUVA_VERSION_MAP (static_cast<uint16_t>(1))
44 #define TERMINAL_PROVIDE_CODE (static_cast<uint16_t>(4))
45 #define TERMINAL_PROVIDE_ORIENTED_CODE (static_cast<uint16_t>(5))
46 
47 namespace {
48 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_DOMAIN_DEMUXER, "FfmpegFormatHelper" };
49 }
50 
51 namespace OHOS {
52 namespace Media {
53 namespace Plugins {
54 namespace Ffmpeg {
55 const uint32_t DOUBLE_BYTES = 2;
56 const uint32_t KEY_PREFIX_LEN = 20;
57 const uint32_t VALUE_PREFIX_LEN = 8;
58 const uint32_t VALID_LOCATION_LEN = 2;
59 const int32_t VIDEO_ROTATION_360 = 360;
60 const int32_t AV3A_SAMPLE_8BITS = 8;
61 const int32_t AV3A_SAMPLE_16BITS = 16;
62 const int32_t AV3A_SAMPLE_24BITS = 24;
63 
64 const unsigned char MASK_80 = 0x80;
65 const unsigned char MASK_C0 = 0xC0;
66 const int32_t MIN_BYTES = 2;
67 const int32_t MAX_BYTES = 6;
68 
69 const int32_t INVALID_VAL = -1;
70 const int32_t POS_1 = 1;
71 const int32_t VALUE_2 = 2;
72 const int32_t VALUE_4 = 4;
73 const int32_t VALUE_10 = 10;
74 
75 static std::map<AVMediaType, MediaType> g_convertFfmpegTrackType = {
76     {AVMEDIA_TYPE_VIDEO, MediaType::VIDEO},
77     {AVMEDIA_TYPE_AUDIO, MediaType::AUDIO},
78     {AVMEDIA_TYPE_SUBTITLE, MediaType::SUBTITLE},
79     {AVMEDIA_TYPE_TIMEDMETA, MediaType::TIMEDMETA},
80     {AVMEDIA_TYPE_AUXILIARY, MediaType::AUXILIARY}
81 };
82 
83 static std::map<AVCodecID, std::string_view> g_codecIdToMime = {
84     {AV_CODEC_ID_MP1, MimeType::AUDIO_MPEG},
85     {AV_CODEC_ID_MP2, MimeType::AUDIO_MPEG},
86     {AV_CODEC_ID_MP3, MimeType::AUDIO_MPEG},
87     {AV_CODEC_ID_FLAC, MimeType::AUDIO_FLAC},
88     {AV_CODEC_ID_AAC, MimeType::AUDIO_AAC},
89     {AV_CODEC_ID_AAC_LATM, MimeType::AUDIO_AAC},
90     {AV_CODEC_ID_VORBIS, MimeType::AUDIO_VORBIS},
91     {AV_CODEC_ID_OPUS, MimeType::AUDIO_OPUS},
92     {AV_CODEC_ID_AMR_NB, MimeType::AUDIO_AMR_NB},
93     {AV_CODEC_ID_AMR_WB, MimeType::AUDIO_AMR_WB},
94     {AV_CODEC_ID_H264, MimeType::VIDEO_AVC},
95     {AV_CODEC_ID_MPEG4, MimeType::VIDEO_MPEG4},
96 #ifdef SUPPORT_CODEC_RV
97     {AV_CODEC_ID_RV30, MimeType::VIDEO_RV30},
98     {AV_CODEC_ID_RV40, MimeType::VIDEO_RV40},
99 #endif
100     {AV_CODEC_ID_MJPEG, MimeType::IMAGE_JPG},
101     {AV_CODEC_ID_PNG, MimeType::IMAGE_PNG},
102     {AV_CODEC_ID_BMP, MimeType::IMAGE_BMP},
103     {AV_CODEC_ID_H263, MimeType::VIDEO_H263},
104     {AV_CODEC_ID_MPEG2TS, MimeType::VIDEO_MPEG2},
105     {AV_CODEC_ID_MPEG2VIDEO, MimeType::VIDEO_MPEG2},
106     {AV_CODEC_ID_HEVC, MimeType::VIDEO_HEVC},
107     {AV_CODEC_ID_VVC, MimeType::VIDEO_VVC},
108     {AV_CODEC_ID_VP8, MimeType::VIDEO_VP8},
109     {AV_CODEC_ID_VP9, MimeType::VIDEO_VP9},
110     {AV_CODEC_ID_AVS3DA, MimeType::AUDIO_AVS3DA},
111     {AV_CODEC_ID_APE, MimeType::AUDIO_APE},
112     {AV_CODEC_ID_PCM_MULAW, MimeType::AUDIO_G711MU},
113     {AV_CODEC_ID_PCM_ALAW, MimeType::AUDIO_G711A},
114 #ifdef SUPPORT_CODEC_COOK
115     {AV_CODEC_ID_COOK, MimeType::AUDIO_COOK},
116 #endif
117     {AV_CODEC_ID_AC3, MimeType::AUDIO_AC3},
118     {AV_CODEC_ID_SUBRIP, MimeType::TEXT_SUBRIP},
119     {AV_CODEC_ID_WEBVTT, MimeType::TEXT_WEBVTT},
120 #ifdef SUPPORT_DEMUXER_LRC
121     {AV_CODEC_ID_TEXT, MimeType::TEXT_LRC},
122 #endif
123 #ifdef SUPPORT_DEMUXER_SAMI
124     {AV_CODEC_ID_SAMI, MimeType::TEXT_SAMI},
125 #endif
126 #ifdef SUPPORT_DEMUXER_ASS
127     {AV_CODEC_ID_ASS, MimeType::TEXT_ASS},
128 #endif
129     {AV_CODEC_ID_FFMETADATA, MimeType::TIMED_METADATA}
130 };
131 
132 static std::map<std::string, FileType> g_convertFfmpegFileType = {
133     {"mpegts", FileType::MPEGTS},
134     {"matroska,webm", FileType::MKV},
135     {"amr", FileType::AMR},
136     {"amrnb", FileType::AMR},
137     {"amrwb", FileType::AMR},
138     {"aac", FileType::AAC},
139     {"mp3", FileType::MP3},
140     {"flac", FileType::FLAC},
141     {"ogg", FileType::OGG},
142     {"wav", FileType::WAV},
143     {"flv", FileType::FLV},
144     {"avi", FileType::AVI},
145     {"mpeg", FileType::MPEGPS},
146     {"rm", FileType::RM},
147     {"ac3", FileType::AC3},
148     {"ape", FileType::APE},
149     {"srt", FileType::SRT},
150     {"webvtt", FileType::VTT},
151 #ifdef SUPPORT_DEMUXER_LRC
152     {"lrc", FileType::LRC},
153 #endif
154 #ifdef SUPPORT_DEMUXER_SAMI
155     {"sami", FileType::SAMI},
156 #endif
157 #ifdef SUPPORT_DEMUXER_ASS
158     {"ass", FileType::ASS},
159 #endif
160 };
161 
162 static std::map<std::string, TagType> g_formatToString = {
163     {"title",         Tag::MEDIA_TITLE},
164     {"artist",        Tag::MEDIA_ARTIST},
165     {"album",         Tag::MEDIA_ALBUM},
166     {"album_artist",  Tag::MEDIA_ALBUM_ARTIST},
167     {"date",          Tag::MEDIA_DATE},
168     {"comment",       Tag::MEDIA_COMMENT},
169     {"genre",         Tag::MEDIA_GENRE},
170     {"copyright",     Tag::MEDIA_COPYRIGHT},
171     {"language",      Tag::MEDIA_LANGUAGE},
172     {"description",   Tag::MEDIA_DESCRIPTION},
173     {"lyrics",        Tag::MEDIA_LYRICS},
174     {"author",        Tag::MEDIA_AUTHOR},
175     {"composer",      Tag::MEDIA_COMPOSER},
176     {"creation_time", Tag::MEDIA_CREATION_TIME},
177     {"aigc",          Tag::MEDIA_AIGC}
178 };
179 
180 std::vector<TagType> g_supportSourceFormat = {
181     Tag::MEDIA_TITLE,
182     Tag::MEDIA_ARTIST,
183     Tag::MEDIA_ALBUM,
184     Tag::MEDIA_ALBUM_ARTIST,
185     Tag::MEDIA_DATE,
186     Tag::MEDIA_COMMENT,
187     Tag::MEDIA_GENRE,
188     Tag::MEDIA_COPYRIGHT,
189     Tag::MEDIA_LANGUAGE,
190     Tag::MEDIA_DESCRIPTION,
191     Tag::MEDIA_LYRICS,
192     Tag::MEDIA_AUTHOR,
193     Tag::MEDIA_COMPOSER,
194     Tag::MEDIA_CREATION_TIME,
195     Tag::MEDIA_AIGC
196 };
197 
SplitByChar(const char * str,const char * pattern)198 std::vector<std::string> SplitByChar(const char* str, const char* pattern)
199 {
200     FALSE_RETURN_V_NOLOG(str != nullptr && pattern != nullptr, {});
201     std::string tempStr(str);
202     std::stringstream strStream(tempStr);
203     std::vector<std::string> resultVec;
204     std::string item;
205     while (std::getline(strStream, item, *pattern)) {
206         if (!item.empty()) {
207             resultVec.push_back(item);
208         }
209     }
210     MEDIA_LOG_D("Split by [" PUBLIC_LOG_S "], get " PUBLIC_LOG_ZU " string", pattern, resultVec.size());
211     return resultVec;
212 }
213 
DumpFileInfo(const AVFormatContext & avFormatContext)214 void DumpFileInfo(const AVFormatContext& avFormatContext)
215 {
216     FALSE_RETURN_MSG(avFormatContext.iformat != nullptr, "Iformat is nullptr");
217     MEDIA_LOG_D("File name [" PUBLIC_LOG_S "]", avFormatContext.iformat->name);
218     if (StartWith(avFormatContext.iformat->name, "mov,mp4,m4a")) {
219         const AVDictionaryEntry *type = av_dict_get(avFormatContext.metadata, "major_brand", NULL, 0);
220         if (type == nullptr) {
221             MEDIA_LOG_D("Not found ftyp");
222         } else {
223             MEDIA_LOG_D("Major brand: " PUBLIC_LOG_S, type->value);
224         }
225     }
226 }
227 
RemoveDuplication(const std::string origin)228 std::string RemoveDuplication(const std::string origin)
229 {
230     FALSE_RETURN_V_NOLOG(origin.find(";") != std::string::npos, origin);
231     std::vector<std::string> subStrings = SplitByChar(origin.c_str(), ";");
232     FALSE_RETURN_V_NOLOG(subStrings.size() > 1, origin);
233 
234     std::string outString;
235     std::vector<std::string> uniqueSubStrings;
236     for (auto str : subStrings) {
237         if (std::count(uniqueSubStrings.begin(), uniqueSubStrings.end(), str) == 0) {
238             uniqueSubStrings.push_back(str);
239         }
240     }
241     for (size_t idx = 0; idx < uniqueSubStrings.size(); idx++) {
242         outString += uniqueSubStrings[idx];
243         if (idx < uniqueSubStrings.size() - 1) {
244             outString += ";";
245         }
246     }
247     MEDIA_LOG_D("[%{public}s]->[%{public}s]", origin.c_str(), outString.c_str());
248     return outString;
249 }
250 
ToLower(const std::string & str)251 std::string ToLower(const std::string& str)
252 {
253     std::string res = str;
254     std::transform(res.begin(), res.end(), res.begin(), [](unsigned char c) {
255         return (c == '_') ? c : std::tolower(c);
256     });
257     MEDIA_LOG_D("[" PUBLIC_LOG_S "] -> [" PUBLIC_LOG_S "]", str.c_str(), res.c_str());
258     return res;
259 }
260 
IsUTF8Char(unsigned char chr,int32_t & nBytes)261 bool IsUTF8Char(unsigned char chr, int32_t &nBytes)
262 {
263     if (nBytes == 0) {
264         if ((chr & MASK_80) == 0) {
265             return true;
266         }
267         while ((chr & MASK_80) == MASK_80) {
268             chr <<= 1;
269             nBytes++;
270         }
271 
272         if (nBytes < MIN_BYTES || nBytes > MAX_BYTES) {
273             return false;
274         }
275         nBytes--;
276     } else {
277         if ((chr & MASK_C0) != MASK_80) {
278             return false;
279         }
280         nBytes--;
281     }
282     return true;
283 }
284 
IsUTF8(const std::string & data)285 bool IsUTF8(const std::string &data)
286 {
287     int32_t nBytes = 0;
288     for (size_t i = 0; i < data.size(); ++i) {
289         if (!IsUTF8Char(data[i], nBytes)) {
290             MEDIA_LOG_D("Detect char not in uft8");
291             return false;
292         }
293     }
294     return true;
295 }
296 
ConvertGBKToUTF8(const std::string & strGbk)297 std::string ConvertGBKToUTF8(const std::string &strGbk)
298 {
299     if (strGbk.length() == 0) {
300         return "";
301     }
302 
303     const std::string fromCharset = "gb18030";
304     const std::string toCharset = "utf-8";
305     iconv_t cd = iconv_open(toCharset.c_str(), fromCharset.c_str());
306     if (cd == reinterpret_cast<iconv_t>(-1)) { // iconv_t is a void* type
307         MEDIA_LOG_D("Call iconv_open failed");
308         return "";
309     }
310     size_t inLen = strGbk.length();
311     size_t outLen = inLen * 4; // max for chinese character
312     char* inBuf = const_cast<char*>(strGbk.c_str());
313     if (inBuf == nullptr) {
314         MEDIA_LOG_D("Get in buffer failed");
315         iconv_close(cd);
316         return "";
317     }
318     char* outBuf = new char[outLen];
319     if (outBuf == nullptr) {
320         MEDIA_LOG_D("Get out buffer failed");
321         iconv_close(cd);
322         return "";
323     }
324     char* outBufBack = outBuf;
325     if (iconv(cd, &inBuf, &inLen, &outBuf, &outLen) == static_cast<size_t>(-1)) { // iconv return SIZE_MAX when failed
326         MEDIA_LOG_D("Call iconv failed");
327         delete[] outBufBack;
328         outBufBack = nullptr;
329         iconv_close(cd);
330         return "";
331     }
332     std::string strOut(outBufBack, outBuf - outBufBack);
333     delete[] outBufBack;
334     outBufBack = nullptr;
335     iconv_close(cd);
336     return strOut;
337 }
338 
IsGBK(const char * data)339 bool IsGBK(const char* data)
340 {
341     int len = static_cast<int>(strlen(data));
342     int i = 0;
343     while (i < len) {
344         if (static_cast<unsigned char>(data[i]) <= 0x7f) { // one byte encoding or ASCII
345             i++;
346             continue;
347         } else { // double bytes encoding
348             if (i + 1  < len &&
349                 static_cast<unsigned char>(data[i]) >= 0x81 && static_cast<unsigned char>(data[i]) <= 0xfe &&
350                 static_cast<unsigned char>(data[i + 1]) >= 0x40 && static_cast<unsigned char>(data[i + 1]) <= 0xfe) {
351                 i += DOUBLE_BYTES; // double bytes
352                 continue;
353             } else {
354                 return false;
355             }
356         }
357     }
358     return true;
359 }
360 
361 static std::vector<AVCodecID> g_imageCodecID = {
362     AV_CODEC_ID_PNG,
363     AV_CODEC_ID_PAM,
364     AV_CODEC_ID_BMP,
365     AV_CODEC_ID_JPEG2000,
366     AV_CODEC_ID_TARGA,
367     AV_CODEC_ID_TIFF,
368     AV_CODEC_ID_GIF,
369     AV_CODEC_ID_PCX,
370     AV_CODEC_ID_XWD,
371     AV_CODEC_ID_XBM,
372     AV_CODEC_ID_WEBP,
373     AV_CODEC_ID_APNG,
374     AV_CODEC_ID_XPM,
375     AV_CODEC_ID_SVG,
376 };
377 
378 static std::map<std::string, VideoRotation> g_pFfRotationMap = {
379     {"0", VIDEO_ROTATION_0},
380     {"90", VIDEO_ROTATION_90},
381     {"180", VIDEO_ROTATION_180},
382     {"270", VIDEO_ROTATION_270},
383 };
384 
385 static const std::map<std::string, VideoOrientationType> matrixTypes = {
386     /**
387      * display matrix
388      *                                  | a b u |
389      *   (a, b, u, c, d, v, x, y, w) -> | c d v |
390      *                                  | x y w |
391      * [a b c d] can confirm the orientation type
392      */
393     {"0 -1 1 0", VideoOrientationType::ROTATE_90},
394     {"-1 0 0 -1", VideoOrientationType::ROTATE_180},
395     {"0 1 -1 0", VideoOrientationType::ROTATE_270},
396     {"-1 0 0 1", VideoOrientationType::FLIP_H},
397     {"1 0 0 -1", VideoOrientationType::FLIP_V},
398     {"0 1 1 0", VideoOrientationType::FLIP_H_ROT90},
399     {"0 -1 -1 0", VideoOrientationType::FLIP_V_ROT90},
400 };
401 
GetMatrixType(const std::string & value)402 VideoOrientationType GetMatrixType(const std::string& value)
403 {
404     auto it = matrixTypes.find(value);
405     if (it!= matrixTypes.end()) {
406         return it->second;
407     } else {
408         return VideoOrientationType::ROTATE_NONE;
409     }
410 }
411 
ConvFp(int32_t x)412 inline int ConvFp(int32_t x)
413 {
414     return static_cast<int32_t>(x / (1 << 16)); // 16 is used for digital conversion
415 }
416 
ConvertArrayToString(const int * array,size_t size)417 std::string ConvertArrayToString(const int* array, size_t size)
418 {
419     std::string result;
420     for (size_t i = 0; i < size; ++i) {
421         if (i > 0) {
422             result += ' ';
423         }
424         result += std::to_string(array[i]);
425     }
426     return result;
427 }
428 
429 enum ValueType {
430     INT32 = 0,
431     FLOAT = 1,
432     BUFFER = 2
433 };
434 
435 template <typename T>
ConvertString(const std::string & str,T & result)436 bool ConvertString(const std::string &str, T &result)
437 {
438     auto [ptr, ec] = std::from_chars(str.data(), str.data() + str.size(), result);
439     return ec == std::errc{} && ptr == str.data() + str.size();
440 }
441 
StringConverterFloat(const std::string & str,float & result)442 bool StringConverterFloat(const std::string &str, float &result)
443 {
444     char *end = nullptr;
445     errno = 0;
446     result = std::strtof(str.c_str(), &end);
447     return end != str.c_str() && *end == '\0' && errno == 0;
448 }
449 
HexCharToValue(char c)450 static int8_t HexCharToValue(char c)
451 {
452     if (c >= '0' && c <= '9') {
453         return c - '0';
454     } else if (c >= 'a' && c <= 'f') {
455         return c - 'a' + VALUE_10;
456     } else if (c >= 'A' && c <= 'F') {
457         return c - 'A' + VALUE_10;
458     }
459     return INVALID_VAL;
460 }
461 
ConvertHexStrToBuffer(const std::string hexStr,std::vector<uint8_t> & buffer)462 static bool ConvertHexStrToBuffer(const std::string hexStr, std::vector<uint8_t> &buffer)
463 {
464     if (hexStr.empty() || hexStr.size() % VALUE_2 != 0) {
465         return false;
466     }
467     int len = static_cast<int>(hexStr.size()) / VALUE_2;
468     buffer.resize(len);
469     for (int i = 0; i < len; i++) {
470         int8_t high = HexCharToValue(hexStr[i * VALUE_2]);
471         int8_t low = HexCharToValue(hexStr[i * VALUE_2 + POS_1]);
472         FALSE_RETURN_V_MSG_E(high >= 0 && low >= 0, false,
473             "invalid hexChar" PUBLIC_LOG_U8 " " PUBLIC_LOG_U8, hexStr[i * VALUE_2], hexStr[i * VALUE_2 + POS_1]);
474         buffer[i] = (static_cast<uint8_t>(high) << VALUE_4) | static_cast<uint8_t>(low);
475     }
476     return true;
477 }
478 
SetToFormatIfConvertSuccess(Meta & format,const TagType & tag,std::string valueStr,ValueType valueType)479 static void SetToFormatIfConvertSuccess(Meta& format, const TagType& tag, std::string valueStr, ValueType valueType)
480 {
481     bool convertSuccess = false;
482     switch (valueType) {
483         case ValueType::INT32: {
484             int32_t int32Value = -1;
485             if (ConvertString(valueStr, int32Value)) {
486                 format.SetData<int32_t>(tag, int32Value);
487                 convertSuccess = true;
488             }
489             break;
490         }
491         case ValueType::FLOAT: {
492             float floatValue = -1;
493             if (StringConverterFloat(valueStr, floatValue)) {
494                 format.SetData<float>(tag, floatValue);
495                 convertSuccess = true;
496             }
497             break;
498         }
499         case ValueType::BUFFER: {
500             std::vector<uint8_t> buffer;
501             if (ConvertHexStrToBuffer(valueStr, buffer)) {
502                 format.SetData(tag, buffer);
503                 convertSuccess = true;
504             }
505             break;
506         }
507         default:
508             MEDIA_LOG_W("Unsupport value type " PUBLIC_LOG_D32, static_cast<int32_t>(valueType));
509             break;
510     }
511     if (!convertSuccess) {
512         MEDIA_LOG_W("Parse failed key[" PUBLIC_LOG_S "] value[" PUBLIC_LOG_S "] type[" PUBLIC_LOG_D32 "]",
513             std::string(tag).c_str(), valueStr.c_str(), static_cast<int32_t>(valueType));
514     }
515 }
516 
IsPCMStream(AVCodecID codecID)517 bool IsPCMStream(AVCodecID codecID)
518 {
519     MEDIA_LOG_D("CodecID " PUBLIC_LOG_D32 "[" PUBLIC_LOG_S "]",
520         static_cast<int32_t>(codecID), avcodec_get_name(codecID));
521     return StartWith(avcodec_get_name(codecID), "pcm_");
522 }
523 
GetDefaultTrackStartTime(const AVFormatContext & avFormatContext)524 int64_t GetDefaultTrackStartTime(const AVFormatContext& avFormatContext)
525 {
526     int64_t defaultTime = 0;
527     for (uint32_t trackIndex = 0; trackIndex < avFormatContext.nb_streams; ++trackIndex) {
528         auto avStream = avFormatContext.streams[trackIndex];
529         if (avStream != nullptr && avStream->codecpar != nullptr &&
530             avStream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && avStream->start_time != AV_NOPTS_VALUE) {
531             defaultTime = AvTime2Us(ConvertTimeFromFFmpeg(avStream->start_time, avStream->time_base));
532         }
533     }
534     return defaultTime;
535 }
536 
FfAv3aGetNbObjects(AVChannelLayout * channelLayout)537 static int FfAv3aGetNbObjects(AVChannelLayout *channelLayout)
538 {
539     int nbObjects = 0;
540     if (channelLayout->order != AV_CHANNEL_ORDER_CUSTOM) {
541         return 0;
542     }
543     for (int i = 0; i < channelLayout->nb_channels; i++) {
544         if (channelLayout->u.map[i].id == AV3A_CH_AUDIO_OBJECT) {
545             nbObjects++;
546         }
547     }
548     return nbObjects;
549 }
550 
FfAv3aGetChannelLayoutMask(AVChannelLayout * channelLayout)551 static uint64_t FfAv3aGetChannelLayoutMask(AVChannelLayout *channelLayout)
552 {
553     uint64_t mask = 0L;
554     if (channelLayout->order != AV_CHANNEL_ORDER_CUSTOM) {
555         return 0;
556     }
557     for (int i = 0; i < channelLayout->nb_channels; i++) {
558         if (channelLayout->u.map[i].id == AV3A_CH_AUDIO_OBJECT) {
559             return mask;
560         }
561         mask |= (1ULL << channelLayout->u.map[i].id);
562     }
563     return mask;
564 }
565 
ParseTrackType(const AVFormatContext & avFormatContext,Meta & format)566 void FFmpegFormatHelper::ParseTrackType(const AVFormatContext& avFormatContext, Meta& format)
567 {
568     format.Set<Tag::MEDIA_TRACK_COUNT>(static_cast<int32_t>(avFormatContext.nb_streams));
569     format.Set<Tag::MEDIA_HAS_VIDEO>(false);
570     format.Set<Tag::MEDIA_HAS_AUDIO>(false);
571     format.Set<Tag::MEDIA_HAS_SUBTITLE>(false);
572     format.Set<Tag::MEDIA_HAS_TIMEDMETA>(false);
573     format.Set<Tag::MEDIA_HAS_AUXILIARY>(false);
574     for (uint32_t i = 0; i < avFormatContext.nb_streams; ++i) {
575         if (avFormatContext.streams[i] == nullptr || avFormatContext.streams[i]->codecpar == nullptr) {
576             MEDIA_LOG_W("Track " PUBLIC_LOG_U32 " is invalid", i);
577             continue;
578         }
579         if (avFormatContext.streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
580             if (!IsImageTrack(*(avFormatContext.streams[i]))) {
581                 format.Set<Tag::MEDIA_HAS_VIDEO>(true);
582             }
583         } else if (avFormatContext.streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
584             format.Set<Tag::MEDIA_HAS_AUDIO>(true);
585         } else if (avFormatContext.streams[i]->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) {
586             format.Set<Tag::MEDIA_HAS_SUBTITLE>(true);
587         } else if (avFormatContext.streams[i]->codecpar->codec_type == AVMEDIA_TYPE_TIMEDMETA) {
588             format.Set<Tag::MEDIA_HAS_TIMEDMETA>(true);
589         } else if (avFormatContext.streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUXILIARY) {
590             format.Set<Tag::MEDIA_HAS_AUXILIARY>(true);
591         }
592     }
593 }
594 
ParseMediaInfo(const AVFormatContext & avFormatContext,Meta & format)595 void FFmpegFormatHelper::ParseMediaInfo(const AVFormatContext& avFormatContext, Meta& format)
596 {
597     ParseTrackType(avFormatContext, format);
598     DumpFileInfo(avFormatContext);
599     format.Set<Tag::MEDIA_FILE_TYPE>(GetFileTypeByName(avFormatContext));
600     int64_t duration = avFormatContext.duration;
601     if (duration == AV_NOPTS_VALUE) {
602         duration = 0;
603         const AVDictionaryEntry *metaDuration = av_dict_get(avFormatContext.metadata, "DURATION", NULL, 0);
604         int64_t us;
605         if (metaDuration != nullptr && (av_parse_time(&us, metaDuration->value, 1) == 0)) {
606             if (us > duration) {
607                 duration = us;
608             }
609         }
610     }
611     if (duration > 0 && duration != AV_NOPTS_VALUE) {
612         format.Set<Tag::MEDIA_DURATION>(static_cast<int64_t>(duration));
613     }
614     if (avFormatContext.start_time != AV_NOPTS_VALUE) {
615         format.Set<Tag::MEDIA_CONTAINER_START_TIME>(static_cast<int64_t>(avFormatContext.start_time));
616     } else {
617         format.Set<Tag::MEDIA_CONTAINER_START_TIME>(static_cast<int64_t>(0));
618         MEDIA_LOG_W("Parse container start time failed");
619     }
620     ParseLocationInfo(avFormatContext, format);
621     ParseInfoFromMetadata(avFormatContext.metadata, format);
622 }
623 
ParseLocationInfo(const AVFormatContext & avFormatContext,Meta & format)624 void FFmpegFormatHelper::ParseLocationInfo(const AVFormatContext& avFormatContext, Meta &format)
625 {
626     MEDIA_LOG_D("Parse location info");
627     AVDictionaryEntry *valPtr = nullptr;
628     valPtr = av_dict_get(avFormatContext.metadata, "location", nullptr, AV_DICT_MATCH_CASE);
629     if (valPtr == nullptr) {
630         valPtr = av_dict_get(avFormatContext.metadata, "LOCATION", nullptr, AV_DICT_MATCH_CASE);
631     }
632     if (valPtr == nullptr) {
633         MEDIA_LOG_D("Parse failed");
634         return;
635     }
636     MEDIA_LOG_D("Get location string successfully: %{private}s", valPtr->value);
637     std::string locationStr = std::string(valPtr->value);
638     std::regex pattern(R"([\+\-]\d+\.\d+)");
639     std::sregex_iterator numbers(locationStr.cbegin(), locationStr.cend(), pattern);
640     std::sregex_iterator end;
641     // at least contain latitude and longitude
642     if (static_cast<uint32_t>(std::distance(numbers, end)) < VALID_LOCATION_LEN) {
643         MEDIA_LOG_D("Info format error");
644         return;
645     }
646     SetToFormatIfConvertSuccess(format, Tag::MEDIA_LATITUDE, numbers->str(), ValueType::FLOAT);
647     SetToFormatIfConvertSuccess(format, Tag::MEDIA_LONGITUDE, (++numbers)->str(), ValueType::FLOAT);
648 }
649 
ParseUserMeta(const AVFormatContext & avFormatContext,std::shared_ptr<Meta> format)650 void FFmpegFormatHelper::ParseUserMeta(const AVFormatContext& avFormatContext, std::shared_ptr<Meta> format)
651 {
652     MEDIA_LOG_D("Parse user data info");
653     AVDictionaryEntry *valPtr = nullptr;
654     while ((valPtr = av_dict_get(avFormatContext.metadata, "", valPtr, AV_DICT_IGNORE_SUFFIX)))  {
655         if (StartWith(valPtr->key, "moov_level_meta_key_")) {
656             MEDIA_LOG_D("Ffmpeg key: " PUBLIC_LOG_S, (valPtr->key));
657             if (strlen(valPtr->value) <= VALUE_PREFIX_LEN) {
658                 MEDIA_LOG_D("Parse user data info " PUBLIC_LOG_S " failed, value too short", valPtr->key);
659                 continue;
660             }
661             if (StartWith(valPtr->value, "00000000")) { // reserved
662                 MEDIA_LOG_D("Key: " PUBLIC_LOG_S " | type: reserved", (valPtr->key + KEY_PREFIX_LEN));
663                 SetToFormatIfConvertSuccess(
664                     *format, valPtr->key + KEY_PREFIX_LEN, valPtr->value + VALUE_PREFIX_LEN, ValueType::BUFFER);
665             } else if (StartWith(valPtr->value, "00000001")) { // string
666                 MEDIA_LOG_D("Key: " PUBLIC_LOG_S " | type: string", (valPtr->key + KEY_PREFIX_LEN));
667                 format->SetData(valPtr->key + KEY_PREFIX_LEN, std::string(valPtr->value + VALUE_PREFIX_LEN));
668             } else if (StartWith(valPtr->value, "00000017")) { // float
669                 MEDIA_LOG_D("Key: " PUBLIC_LOG_S " | type: float", (valPtr->key + KEY_PREFIX_LEN));
670                 SetToFormatIfConvertSuccess(
671                     *format, valPtr->key + KEY_PREFIX_LEN, valPtr->value + VALUE_PREFIX_LEN, ValueType::FLOAT);
672             } else if (StartWith(valPtr->value, "00000043") || StartWith(valPtr->value, "00000015")) { // int
673                 MEDIA_LOG_D("Key: " PUBLIC_LOG_S " | type: int", (valPtr->key + KEY_PREFIX_LEN));
674                 SetToFormatIfConvertSuccess(
675                     *format, valPtr->key + KEY_PREFIX_LEN, valPtr->value + VALUE_PREFIX_LEN, ValueType::INT32);
676             } else { // unknow
677                 MEDIA_LOG_D("Key: " PUBLIC_LOG_S " | type: unknow", (valPtr->key + KEY_PREFIX_LEN));
678                 format->SetData(valPtr->key + KEY_PREFIX_LEN, std::string(valPtr->value + VALUE_PREFIX_LEN));
679             }
680         }
681     }
682 }
683 
ParseTrackInfo(const AVStream & avStream,Meta & format,const AVFormatContext & avFormatContext)684 void FFmpegFormatHelper::ParseTrackInfo(const AVStream& avStream, Meta& format, const AVFormatContext& avFormatContext)
685 {
686     FALSE_RETURN_MSG(avStream.codecpar != nullptr, "Codecpar is nullptr");
687     ParseBaseTrackInfo(avStream, format, avFormatContext);
688     if (avStream.codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
689         if (IsImageTrack(avStream)) {
690             ParseImageTrackInfo(avStream, format);
691         } else {
692             ParseAVTrackInfo(avStream, format);
693             ParseVideoTrackInfo(avStream, format, avFormatContext);
694         }
695     } else if (avStream.codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
696         ParseAVTrackInfo(avStream, format);
697         ParseAudioTrackInfo(avStream, format, avFormatContext);
698     } else if (avStream.codecpar->codec_type == AVMEDIA_TYPE_TIMEDMETA) {
699         ParseAVTrackInfo(avStream, format);
700         ParseTimedMetaTrackInfo(avStream, format);
701         ParseAuxiliaryTrackInfo(avStream, format);
702     } else if (avStream.codecpar->codec_type == AVMEDIA_TYPE_AUXILIARY) {
703         ParseAVTrackInfo(avStream, format);
704         ParseAuxiliaryTrackInfo(avStream, format);
705         if (IsVideoType(avStream)) {
706             ParseVideoTrackInfo(avStream, format, avFormatContext);
707         } else if (IsAudioType(avStream)) {
708             ParseAudioTrackInfo(avStream, format, avFormatContext);
709         }
710     }
711 }
712 
ParseBaseTrackInfo(const AVStream & avStream,Meta & format,const AVFormatContext & avFormatContext)713 void FFmpegFormatHelper::ParseBaseTrackInfo(const AVStream& avStream, Meta &format,
714                                             const AVFormatContext& avFormatContext)
715 {
716     if (g_codecIdToMime.count(avStream.codecpar->codec_id) != 0) {
717         format.Set<Tag::MIME_TYPE>(std::string(g_codecIdToMime[avStream.codecpar->codec_id]));
718     } else if (IsPCMStream(avStream.codecpar->codec_id)) {
719         format.Set<Tag::MIME_TYPE>(std::string(MimeType::AUDIO_RAW));
720     } else {
721         format.Set<Tag::MIME_TYPE>(std::string(MimeType::INVALID_TYPE));
722         MEDIA_LOG_W("Parse mime type failed: " PUBLIC_LOG_S, avcodec_get_name(avStream.codecpar->codec_id));
723     }
724 
725     AVMediaType mediaType = avStream.codecpar->codec_type;
726     if (g_convertFfmpegTrackType.count(mediaType) > 0) {
727         format.Set<Tag::MEDIA_TYPE>(g_convertFfmpegTrackType[mediaType]);
728     } else {
729         MEDIA_LOG_W("Parse track type failed: " PUBLIC_LOG_D32, static_cast<int32_t>(mediaType));
730     }
731 
732     if (avStream.start_time != AV_NOPTS_VALUE) {
733         format.SetData(Tag::MEDIA_START_TIME,
734             AvTime2Us(ConvertTimeFromFFmpeg(avStream.start_time, avStream.time_base)));
735     } else {
736         if (mediaType == AVMEDIA_TYPE_AUDIO || mediaType == AVMEDIA_TYPE_AUXILIARY) {
737             format.SetData(Tag::MEDIA_START_TIME, GetDefaultTrackStartTime(avFormatContext));
738         }
739         MEDIA_LOG_W("Parse track start time failed");
740     }
741 }
742 
GetFileTypeByName(const AVFormatContext & avFormatContext)743 FileType FFmpegFormatHelper::GetFileTypeByName(const AVFormatContext& avFormatContext)
744 {
745     FALSE_RETURN_V_MSG_E(avFormatContext.iformat != nullptr, FileType::UNKNOW, "Iformat is nullptr");
746     const char *fileName = avFormatContext.iformat->name;
747     FileType fileType = FileType::UNKNOW;
748     if (StartWith(fileName, "mov,mp4,m4a")) {
749         const AVDictionaryEntry *type = av_dict_get(avFormatContext.metadata, "major_brand", NULL, 0);
750         if (type == nullptr) {
751             return FileType::MP4;
752         }
753         if (StartWith(type->value, "m4a") || StartWith(type->value, "M4A") ||
754             StartWith(type->value, "m4v") || StartWith(type->value, "M4V")) {
755             fileType = FileType::M4A;
756         } else if (StartWith(type->value, "qt") || StartWith(type->value, "QT")) {
757             fileType = FileType::MOV;
758         } else {
759             fileType = FileType::MP4;
760         }
761     } else {
762         if (g_convertFfmpegFileType.count(fileName) != 0) {
763             fileType = g_convertFfmpegFileType[fileName];
764         }
765     }
766     return fileType;
767 }
768 
ParseAVTrackInfo(const AVStream & avStream,Meta & format)769 void FFmpegFormatHelper::ParseAVTrackInfo(const AVStream& avStream, Meta &format)
770 {
771     int64_t bitRate = static_cast<int64_t>(avStream.codecpar->bit_rate);
772     if (bitRate > 0) {
773         format.Set<Tag::MEDIA_BITRATE>(bitRate);
774     } else {
775         MEDIA_LOG_D("Parse bitrate failed: " PUBLIC_LOG_D64, bitRate);
776     }
777 
778     if (avStream.codecpar->extradata_size > 0 && avStream.codecpar->extradata != nullptr) {
779         std::vector<uint8_t> extra(avStream.codecpar->extradata_size);
780         extra.assign(avStream.codecpar->extradata, avStream.codecpar->extradata + avStream.codecpar->extradata_size);
781         format.Set<Tag::MEDIA_CODEC_CONFIG>(extra);
782     } else {
783         MEDIA_LOG_D("Parse codec config failed");
784     }
785     AVDictionaryEntry *valPtr = nullptr;
786     valPtr = av_dict_get(avStream.metadata, "language", nullptr, AV_DICT_MATCH_CASE);
787     if (valPtr != nullptr) {
788         format.SetData(Tag::MEDIA_LANGUAGE, std::string(valPtr->value));
789     } else {
790         MEDIA_LOG_D("Parse track language failed");
791     }
792 }
793 
ParseVideoTrackInfo(const AVStream & avStream,Meta & format,const AVFormatContext & avFormatContext)794 void FFmpegFormatHelper::ParseVideoTrackInfo(const AVStream& avStream, Meta &format,
795                                              const AVFormatContext& avFormatContext)
796 {
797     format.Set<Tag::VIDEO_WIDTH>(static_cast<uint32_t>(avStream.codecpar->width));
798     format.Set<Tag::VIDEO_HEIGHT>(static_cast<uint32_t>(avStream.codecpar->height));
799     format.Set<Tag::VIDEO_DELAY>(static_cast<uint32_t>(avStream.codecpar->video_delay));
800 
801     double frameRate = 0;
802     if (avStream.avg_frame_rate.den == 0 || avStream.avg_frame_rate.num == 0) {
803         frameRate = static_cast<double>(av_q2d(avStream.r_frame_rate));
804     } else {
805         frameRate = static_cast<double>(av_q2d(avStream.avg_frame_rate));
806     }
807     if (frameRate > 0) {
808         format.Set<Tag::VIDEO_FRAME_RATE>(frameRate);
809     } else {
810         MEDIA_LOG_D("Parse frame rate failed: " PUBLIC_LOG_F, frameRate);
811     }
812 
813     AVDictionaryEntry *valPtr = nullptr;
814     valPtr = av_dict_get(avStream.metadata, "rotate", nullptr, AV_DICT_MATCH_CASE);
815     if (valPtr == nullptr) {
816         valPtr = av_dict_get(avStream.metadata, "ROTATE", nullptr, AV_DICT_MATCH_CASE);
817     }
818     if (valPtr == nullptr) {
819         MEDIA_LOG_D("Parse rotate info from meta failed");
820         ParseRotationFromMatrix(avStream, format);
821     } else {
822         if (g_pFfRotationMap.count(std::string(valPtr->value)) > 0) {
823             format.Set<Tag::VIDEO_ROTATION>(g_pFfRotationMap[std::string(valPtr->value)]);
824         } else {
825             MEDIA_LOG_D("Unsupport rotate " PUBLIC_LOG_S, valPtr->value);
826         }
827     }
828     FileType fileType = GetFileTypeByName(avFormatContext);
829     if (IsMpeg4File(fileType)) {
830         ParseOrientationFromMatrix(avStream, format);
831     }
832 
833     AVRational sar = avStream.sample_aspect_ratio;
834     if (sar.num && sar.den) {
835         format.Set<Tag::VIDEO_SAR>(static_cast<double>(av_q2d(sar)));
836     }
837 
838     if (avStream.codecpar->codec_id == AV_CODEC_ID_HEVC) {
839         ParseHvccBoxInfo(avStream, format);
840         ParseColorBoxInfo(avStream, format);
841     }
842 }
843 
ParseRotationFromMatrix(const AVStream & avStream,Meta & format)844 void FFmpegFormatHelper::ParseRotationFromMatrix(const AVStream& avStream, Meta &format)
845 {
846     int32_t *displayMatrix = (int32_t *)av_stream_get_side_data(&avStream, AV_PKT_DATA_DISPLAYMATRIX, NULL);
847     if (displayMatrix) {
848         float rotation = -round(av_display_rotation_get(displayMatrix));
849         MEDIA_LOG_D("Parse rotate info from display matrix: " PUBLIC_LOG_F, rotation);
850         if (isnan(rotation)) {
851             format.Set<Tag::VIDEO_ROTATION>(g_pFfRotationMap["0"]);
852             return;
853         } else if (rotation < 0) {
854             rotation += VIDEO_ROTATION_360;
855         }
856         switch (int(rotation)) {
857             case VIDEO_ROTATION_90:
858                 format.Set<Tag::VIDEO_ROTATION>(g_pFfRotationMap["90"]);
859                 break;
860             case VIDEO_ROTATION_180:
861                 format.Set<Tag::VIDEO_ROTATION>(g_pFfRotationMap["180"]);
862                 break;
863             case VIDEO_ROTATION_270:
864                 format.Set<Tag::VIDEO_ROTATION>(g_pFfRotationMap["270"]);
865                 break;
866             default:
867                 format.Set<Tag::VIDEO_ROTATION>(g_pFfRotationMap["0"]);
868                 break;
869         }
870     } else {
871         MEDIA_LOG_D("Parse rotate info from display matrix failed, set rotation as default 0");
872         format.Set<Tag::VIDEO_ROTATION>(g_pFfRotationMap["0"]);
873     }
874 }
875 
PrintMatrixToLog(int32_t * matrix,const std::string & matrixName)876 void PrintMatrixToLog(int32_t * matrix, const std::string& matrixName)
877 {
878     MEDIA_LOG_D(PUBLIC_LOG_S ": [" PUBLIC_LOG_D32 " " PUBLIC_LOG_D32 " " PUBLIC_LOG_D32 " " PUBLIC_LOG_D32 " "
879             PUBLIC_LOG_D32 " " PUBLIC_LOG_D32 " " PUBLIC_LOG_D32 " " PUBLIC_LOG_D32 " " PUBLIC_LOG_D32 "]",
880             matrixName.c_str(), matrix[0], matrix[1], matrix[2], matrix[3], matrix[4],
881             matrix[5], matrix[6], matrix[7], matrix[8]);
882 }
883 
ParseOrientationFromMatrix(const AVStream & avStream,Meta & format)884 void FFmpegFormatHelper::ParseOrientationFromMatrix(const AVStream& avStream, Meta &format)
885 {
886     VideoOrientationType orientationType = VideoOrientationType::ROTATE_NONE;
887     int32_t *displayMatrix = (int32_t *)av_stream_get_side_data(&avStream, AV_PKT_DATA_DISPLAYMATRIX, NULL);
888     if (displayMatrix) {
889         PrintMatrixToLog(displayMatrix, "displayMatrix");
890         int convertedMatrix[CONVERT_MATRIX_SIZE] = {0, 0, 0, 0};
891         std::transform(&displayMatrix[0], &displayMatrix[0] + 1, // 0 is displayMatrix index, 1 is copy lenth
892                        &convertedMatrix[0], ConvFp); // 0 is convertedMatrix index
893         std::transform(&displayMatrix[1], &displayMatrix[1] + 1, // 1 is displayMatrix index, 1 is copy lenth
894                        &convertedMatrix[1], ConvFp); // 1 is convertedMatrix index
895         std::transform(&displayMatrix[3], &displayMatrix[3] + 1, // 3 is displayMatrix index, 1 is copy lenth
896                        &convertedMatrix[2], ConvFp); // 2 is convertedMatrix index
897         std::transform(&displayMatrix[4], &displayMatrix[4] + 1, // 4 is displayMatrix index, 1 is copy lenth
898                        &convertedMatrix[3], ConvFp); // 3 is convertedMatrix index
899         orientationType = GetMatrixType(ConvertArrayToString(convertedMatrix, CONVERT_MATRIX_SIZE));
900     } else {
901         MEDIA_LOG_D("Parse orientation info from display matrix failed, set orientation as dafault 0");
902     }
903     format.Set<Tag::VIDEO_ORIENTATION_TYPE>(orientationType);
904     MEDIA_LOG_D("Type of matrix is: " PUBLIC_LOG_D32, static_cast<int>(orientationType));
905 }
906 
ParseImageTrackInfo(const AVStream & avStream,Meta & format)907 void FFmpegFormatHelper::ParseImageTrackInfo(const AVStream& avStream, Meta &format)
908 {
909     format.Set<Tag::VIDEO_WIDTH>(static_cast<uint32_t>(avStream.codecpar->width));
910     format.Set<Tag::VIDEO_HEIGHT>(static_cast<uint32_t>(avStream.codecpar->height));
911     AVPacket pkt = avStream.attached_pic;
912     if (pkt.size > 0 && pkt.data != nullptr) {
913         std::vector<uint8_t> cover(pkt.size);
914         cover.assign(pkt.data, pkt.data + pkt.size);
915         format.Set<Tag::MEDIA_COVER>(cover);
916     } else {
917         MEDIA_LOG_D("Parse cover failed: " PUBLIC_LOG_D32, pkt.size);
918     }
919 }
920 
ParseAudioTrackInfo(const AVStream & avStream,Meta & format,const AVFormatContext & avFormatContext)921 void FFmpegFormatHelper::ParseAudioTrackInfo(const AVStream& avStream, Meta &format,
922                                              const AVFormatContext& avFormatContext)
923 {
924     int sampleRate = avStream.codecpar->sample_rate;
925     int channels = avStream.codecpar->channels;
926     if (channels <= 0) {
927         channels = avStream.codecpar->ch_layout.nb_channels;
928     }
929     int frameSize = avStream.codecpar->frame_size;
930     if (sampleRate > 0) {
931         format.Set<Tag::AUDIO_SAMPLE_RATE>(static_cast<uint32_t>(sampleRate));
932     } else {
933         MEDIA_LOG_D("Parse sample rate failed: " PUBLIC_LOG_D32, sampleRate);
934     }
935     if (channels > 0) {
936         format.Set<Tag::AUDIO_OUTPUT_CHANNELS>(static_cast<uint32_t>(channels));
937         format.Set<Tag::AUDIO_CHANNEL_COUNT>(static_cast<uint32_t>(channels));
938     } else {
939         MEDIA_LOG_D("Parse channel count failed: " PUBLIC_LOG_D32, channels);
940     }
941     if (frameSize > 0) {
942         format.Set<Tag::AUDIO_SAMPLE_PER_FRAME>(static_cast<uint32_t>(frameSize));
943     } else {
944         MEDIA_LOG_D("Parse frame rate failed: " PUBLIC_LOG_D32, frameSize);
945     }
946     AudioChannelLayout channelLayout = FFMpegConverter::ConvertFFToOHAudioChannelLayoutV2(
947         avStream.codecpar->channel_layout, channels);
948     format.Set<Tag::AUDIO_OUTPUT_CHANNEL_LAYOUT>(channelLayout);
949     format.Set<Tag::AUDIO_CHANNEL_LAYOUT>(channelLayout);
950 
951     AudioSampleFormat fmt = (IsPCMStream(avStream.codecpar->codec_id)) ?
952         FFMpegConverter::ConvertFFMpegAVCodecIdToOHAudioFormat(avStream.codecpar->codec_id) :
953         FFMpegConverter::ConvertFFMpegToOHAudioFormat(static_cast<AVSampleFormat>(avStream.codecpar->format));
954     format.Set<Tag::AUDIO_SAMPLE_FORMAT>(fmt);
955 
956     if (avStream.codecpar->codec_id == AV_CODEC_ID_AAC) {
957         format.Set<Tag::AUDIO_AAC_IS_ADTS>(1);
958     } else if (avStream.codecpar->codec_id == AV_CODEC_ID_AAC_LATM) {
959         format.Set<Tag::AUDIO_AAC_IS_ADTS>(0);
960     }
961     format.Set<Tag::AUDIO_BITS_PER_CODED_SAMPLE>(avStream.codecpar->bits_per_coded_sample);
962     format.Set<Tag::AUDIO_BITS_PER_RAW_SAMPLE>(avStream.codecpar->bits_per_raw_sample);
963 
964     if (avStream.codecpar->codec_id == AV_CODEC_ID_AVS3DA) {
965         format.Set<Tag::AUDIO_CHANNEL_LAYOUT>(AudioChannelLayout::UNKNOWN);
966         format.Set<Tag::AUDIO_OUTPUT_CHANNEL_LAYOUT>(AudioChannelLayout::UNKNOWN);
967         if (avStream.codecpar->ch_layout.order == AV_CHANNEL_ORDER_CUSTOM ||
968             avStream.codecpar->ch_layout.order == AV_CHANNEL_ORDER_AMBISONIC) {
969             ParseAv3aInfo(avStream, format);
970         }
971         ConvertAv3aSampleFormat(avStream, format);
972     }
973 
974     ParseAudioApeTrackInfo(avStream, format, avFormatContext);
975 }
976 
ParseAudioApeTrackInfo(const AVStream & avStream,Meta & format,const AVFormatContext & avFormatContext)977 void FFmpegFormatHelper::ParseAudioApeTrackInfo(const AVStream& avStream, Meta &format,
978                                                 const AVFormatContext& avFormatContext)
979 {
980     if (GetFileTypeByName(avFormatContext) == FileType::APE) {
981         // Ffmpeg ensures that the value is definitely Int type
982         const AVDictionaryEntry *meta = av_dict_get(avFormatContext.metadata, "max_frame_size", NULL, 0);
983         if (meta != nullptr) {
984             int64_t maxFrameSize = -1;
985             if (ConvertString<int64_t>(meta->value, maxFrameSize)) {
986                 FALSE_RETURN_MSG(maxFrameSize >= INT32_MIN && maxFrameSize <= INT32_MAX, "Parse max frame size failed");
987                 format.Set<Tag::AUDIO_MAX_INPUT_SIZE>(static_cast<int32_t>(maxFrameSize));
988             } else {
989                 MEDIA_LOG_W("error frameSize " PUBLIC_LOG_S, meta->value);
990             }
991         }
992         meta = av_dict_get(avFormatContext.metadata, "sample_per_frame", NULL, 0);
993         if (meta != nullptr) {
994             int64_t samplePerFrame = -1;
995             if (ConvertString<int64_t>(meta->value, samplePerFrame)) {
996                 FALSE_RETURN_MSG(samplePerFrame >= INT32_MIN && samplePerFrame <= INT32_MAX,
997                     "Parse sample per frame failed");
998                 format.Set<Tag::AUDIO_SAMPLE_PER_FRAME>(static_cast<int32_t>(samplePerFrame));
999             } else {
1000                 MEDIA_LOG_W("error sample per frame " PUBLIC_LOG_S, meta->value);
1001             }
1002         }
1003     }
1004 }
1005 
ConvertAv3aSampleFormat(const AVStream & avStream,Meta & format)1006 void FFmpegFormatHelper::ConvertAv3aSampleFormat(const AVStream& avStream, Meta &format)
1007 {
1008     AudioSampleFormat fmt;
1009     switch (avStream.codecpar->bits_per_raw_sample) {
1010         case AV3A_SAMPLE_8BITS: // 8 bits
1011             fmt = AudioSampleFormat::SAMPLE_U8;
1012             break;
1013         case AV3A_SAMPLE_16BITS: // 16 bits
1014             fmt = AudioSampleFormat::SAMPLE_S16LE;
1015             break;
1016         case AV3A_SAMPLE_24BITS: // 24 bits
1017             fmt = AudioSampleFormat::SAMPLE_S24LE;
1018             break;
1019         default:
1020             fmt = AudioSampleFormat::INVALID_WIDTH;
1021             break;
1022     }
1023     format.Set<Tag::AUDIO_SAMPLE_FORMAT>(fmt);
1024 }
1025 
ParseAv3aInfo(const AVStream & avStream,Meta & format)1026 void FFmpegFormatHelper::ParseAv3aInfo(const AVStream& avStream, Meta &format)
1027 {
1028     int channels = avStream.codecpar->channels; // 总通道数
1029     AudioChannelLayout channelLayout = AudioChannelLayout::UNKNOWN;
1030     int objectNumber = 0; // 对象数量
1031     uint64_t channelLayoutMask = 0L;
1032     if (avStream.codecpar->ch_layout.order == AV_CHANNEL_ORDER_CUSTOM) {
1033         // 获取mask(如果是纯对象模式则不包含声场,返回0L)
1034         channelLayoutMask = FfAv3aGetChannelLayoutMask(&avStream.codecpar->ch_layout);
1035         objectNumber = FfAv3aGetNbObjects(&avStream.codecpar->ch_layout); // 获取对象数量,如果不包含对象返回0
1036         if (channelLayoutMask > 0L) {
1037             channelLayout = FFMpegConverter::ConvertAudioVividToOHAudioChannelLayout(
1038                 channelLayoutMask, channels - objectNumber);
1039             if (channelLayoutMask != static_cast<uint64_t>(channelLayout)) {
1040                 MEDIA_LOG_W("Get channel layout failed, use default channel layout");
1041             }
1042         } else {
1043             channelLayout = AudioChannelLayout::UNKNOWN;
1044         }
1045     } else if (avStream.codecpar->ch_layout.order == AV_CHANNEL_ORDER_AMBISONIC) {
1046         int hoaOrder = static_cast<int>(sqrt(channels)) - 1;
1047         if (hoaOrder == 1) {
1048             channelLayout = AudioChannelLayout::HOA_ORDER1_ACN_SN3D;
1049         } else if (hoaOrder == 2) { // hoaOrder is 2
1050             channelLayout = AudioChannelLayout::HOA_ORDER2_ACN_SN3D;
1051         } else if (hoaOrder == 3) { // hoaOrder is 3
1052             channelLayout = AudioChannelLayout::HOA_ORDER3_ACN_SN3D;
1053         } else {
1054             MEDIA_LOG_W("Get hoa order failed");
1055         }
1056         format.Set<Tag::AUDIO_HOA_ORDER>(hoaOrder);
1057     } else {
1058         MEDIA_LOG_W("Get channel layout failed");
1059     }
1060     format.Set<Tag::AUDIO_OBJECT_NUMBER>(objectNumber);
1061     format.Set<Tag::AUDIO_SOUNDBED_CHANNELS_NUMBER>(channels - objectNumber);
1062     // 设置一个整个音频内容通道总数
1063     format.Set<Tag::AUDIO_OUTPUT_CHANNEL_LAYOUT>(channelLayout);
1064     format.Set<Tag::AUDIO_CHANNEL_LAYOUT>(channelLayout);
1065     if (channels > 0) {
1066         format.Set<Tag::AUDIO_OUTPUT_CHANNELS>(static_cast<uint32_t>(channels));
1067         format.Set<Tag::AUDIO_CHANNEL_COUNT>(static_cast<uint32_t>(channels));
1068     } else {
1069         MEDIA_LOG_D("Parse channel count failed: " PUBLIC_LOG_D32, channels);
1070     }
1071 }
1072 
ParseTimedMetaTrackInfo(const AVStream & avStream,Meta & format)1073 void FFmpegFormatHelper::ParseTimedMetaTrackInfo(const AVStream& avStream, Meta &format)
1074 {
1075     AVDictionaryEntry *valPtr = nullptr;
1076     valPtr = av_dict_get(avStream.metadata, "timed_metadata_key", nullptr, AV_DICT_IGNORE_SUFFIX);
1077     if (valPtr == nullptr) {
1078         MEDIA_LOG_W("Get timed metadata key failed");
1079     } else {
1080         format.Set<Tag::TIMED_METADATA_KEY>(std::string(valPtr->value));
1081     }
1082     valPtr = av_dict_get(avStream.metadata, "src_track_id", nullptr, AV_DICT_MATCH_CASE);
1083     if (valPtr == nullptr) {
1084         MEDIA_LOG_W("Get src track id failed");
1085     } else {
1086         format.Set<Tag::TIMED_METADATA_SRC_TRACK>(std::stoi(valPtr->value));
1087     }
1088 }
1089 
ParseAuxiliaryTrackInfo(const AVStream & avStream,Meta & format)1090 void FFmpegFormatHelper::ParseAuxiliaryTrackInfo(const AVStream& avStream, Meta &format)
1091 {
1092     AVDictionaryEntry *valPtr = nullptr;
1093     valPtr = av_dict_get(avStream.metadata, "handler_name", nullptr, AV_DICT_IGNORE_SUFFIX);
1094     if (valPtr == nullptr) {
1095         MEDIA_LOG_W("Get ref desc failed");
1096     } else {
1097         format.Set<Tag::TRACK_DESCRIPTION>(std::string(valPtr->value));
1098     }
1099 
1100     valPtr = av_dict_get(avStream.metadata, "track_reference_type", nullptr, AV_DICT_IGNORE_SUFFIX);
1101     if (valPtr == nullptr) {
1102         MEDIA_LOG_W("Get ref type failed");
1103     } else {
1104         format.Set<Tag::TRACK_REFERENCE_TYPE>(std::string(valPtr->value));
1105     }
1106 
1107     valPtr = av_dict_get(avStream.metadata, "reference_track_ids", nullptr, AV_DICT_MATCH_CASE);
1108     if (valPtr == nullptr) {
1109         MEDIA_LOG_W("Get src track id failed");
1110     } else {
1111         std::vector<int32_t> referenceIds;
1112         std::vector<std::string> referenceIdsString;
1113         std::string values = std::string(valPtr->value);
1114         if (values.find(",") != std::string::npos) {
1115             referenceIdsString = SplitByChar(values.c_str(), ",");
1116         }
1117         FALSE_RETURN_MSG_W(referenceIdsString.size() > 0, "Auxl track without ref track");
1118         for (std::string subStr : referenceIdsString) {
1119             // Ffmpeg ensures that the value is definitely Int type
1120             int32_t id = -1;
1121             if (ConvertString<int32_t>(subStr, id)) {
1122                 referenceIds.push_back(id);
1123             } else {
1124                 MEDIA_LOG_W("error trackids " PUBLIC_LOG_S, subStr.c_str());
1125             }
1126         }
1127         format.Set<Tag::REFERENCE_TRACK_IDS>(referenceIds);
1128     }
1129 }
1130 
ParseHvccBoxInfo(const AVStream & avStream,Meta & format)1131 void FFmpegFormatHelper::ParseHvccBoxInfo(const AVStream& avStream, Meta &format)
1132 {
1133     HEVCProfile profile = FFMpegConverter::ConvertFFMpegToOHHEVCProfile(avStream.codecpar->profile);
1134     if (profile != HEVCProfile::HEVC_PROFILE_UNKNOW) {
1135         format.Set<Tag::VIDEO_H265_PROFILE>(profile);
1136         format.Set<Tag::MEDIA_PROFILE>(profile);
1137     } else {
1138         MEDIA_LOG_D("Parse hevc profile failed: " PUBLIC_LOG_D32, profile);
1139     }
1140     HEVCLevel level = FFMpegConverter::ConvertFFMpegToOHHEVCLevel(avStream.codecpar->level);
1141     if (level != HEVCLevel::HEVC_LEVEL_UNKNOW) {
1142         format.Set<Tag::VIDEO_H265_LEVEL>(level);
1143         format.Set<Tag::MEDIA_LEVEL>(level);
1144     } else {
1145         MEDIA_LOG_D("Parse hevc level failed: " PUBLIC_LOG_D32, level);
1146     }
1147 }
1148 
ParseColorBoxInfo(const AVStream & avStream,Meta & format)1149 void FFmpegFormatHelper::ParseColorBoxInfo(const AVStream& avStream, Meta &format)
1150 {
1151     int colorRange = FFMpegConverter::ConvertFFMpegToOHColorRange(avStream.codecpar->color_range);
1152     format.Set<Tag::VIDEO_COLOR_RANGE>(static_cast<bool>(colorRange));
1153 
1154     ColorPrimary colorPrimaries = FFMpegConverter::ConvertFFMpegToOHColorPrimaries(avStream.codecpar->color_primaries);
1155     format.Set<Tag::VIDEO_COLOR_PRIMARIES>(colorPrimaries);
1156 
1157     TransferCharacteristic colorTrans = FFMpegConverter::ConvertFFMpegToOHColorTrans(avStream.codecpar->color_trc);
1158     format.Set<Tag::VIDEO_COLOR_TRC>(colorTrans);
1159 
1160     MatrixCoefficient colorMatrix = FFMpegConverter::ConvertFFMpegToOHColorMatrix(avStream.codecpar->color_space);
1161     format.Set<Tag::VIDEO_COLOR_MATRIX_COEFF>(colorMatrix);
1162 
1163     ChromaLocation chromaLoc = FFMpegConverter::ConvertFFMpegToOHChromaLocation(avStream.codecpar->chroma_location);
1164     format.Set<Tag::VIDEO_CHROMA_LOCATION>(chromaLoc);
1165 }
1166 
ParseColorBoxInfo(const AVFormatContext & avFormatContext,HevcParseFormat parse,Meta & format)1167 void FFmpegFormatHelper::ParseColorBoxInfo(const AVFormatContext& avFormatContext, HevcParseFormat parse, Meta &format)
1168 {
1169     ColorPrimary colorPrimaries = FFMpegConverter::ConvertFFMpegToOHColorPrimaries(
1170         static_cast<AVColorPrimaries>(parse.colorPrimaries));
1171     if (colorPrimaries != ColorPrimary::UNSPECIFIED) {
1172         format.Set<Tag::VIDEO_COLOR_PRIMARIES>(colorPrimaries);
1173         format.Set<Tag::VIDEO_COLOR_RANGE>((bool)(parse.colorRange));
1174     } else {
1175         MEDIA_LOG_D("Parse colorPri from xps failed");
1176     }
1177 
1178     TransferCharacteristic colorTrans = FFMpegConverter::ConvertFFMpegToOHColorTrans(
1179         static_cast<AVColorTransferCharacteristic>(parse.colorTransfer));
1180     if (colorTrans != TransferCharacteristic::UNSPECIFIED) {
1181         format.Set<Tag::VIDEO_COLOR_TRC>(colorTrans);
1182     } else {
1183         MEDIA_LOG_D("Parse colorTrc from xps failed");
1184     }
1185 
1186     MatrixCoefficient colorMatrix = FFMpegConverter::ConvertFFMpegToOHColorMatrix(
1187         static_cast<AVColorSpace>(parse.colorMatrixCoeff));
1188     if (colorMatrix != MatrixCoefficient::UNSPECIFIED) {
1189         format.Set<Tag::VIDEO_COLOR_MATRIX_COEFF>(colorMatrix);
1190     } else {
1191         MEDIA_LOG_D("Parse colorMatrix from xps failed");
1192     }
1193 
1194     ChromaLocation chromaLoc = FFMpegConverter::ConvertFFMpegToOHChromaLocation(
1195         static_cast<AVChromaLocation>(parse.chromaLocation));
1196     if (chromaLoc != ChromaLocation::UNSPECIFIED) {
1197         format.Set<Tag::VIDEO_CHROMA_LOCATION>(chromaLoc);
1198     } else {
1199         MEDIA_LOG_D("Parse chromaLoc from xps failed");
1200     }
1201 }
1202 
ParseHevcInfo(const AVFormatContext & avFormatContext,HevcParseFormat parse,Meta & format)1203 void FFmpegFormatHelper::ParseHevcInfo(const AVFormatContext &avFormatContext, HevcParseFormat parse, Meta &format)
1204 {
1205     if (parse.isHdrVivid) {
1206         format.Set<Tag::VIDEO_IS_HDR_VIVID>(true);
1207     }
1208     ParseColorBoxInfo(avFormatContext, parse, format);
1209     HEVCProfile profile = FFMpegConverter::ConvertFFMpegToOHHEVCProfile(static_cast<int>(parse.profile));
1210     if (profile != HEVCProfile::HEVC_PROFILE_UNKNOW) {
1211         format.Set<Tag::VIDEO_H265_PROFILE>(profile);
1212         format.Set<Tag::MEDIA_PROFILE>(profile);
1213     } else {
1214         MEDIA_LOG_D("Parse hevc profile failed: " PUBLIC_LOG_D32, profile);
1215     }
1216     HEVCLevel level = FFMpegConverter::ConvertFFMpegToOHHEVCLevel(static_cast<int>(parse.level));
1217     if (level != HEVCLevel::HEVC_LEVEL_UNKNOW) {
1218         format.Set<Tag::VIDEO_H265_LEVEL>(level);
1219         format.Set<Tag::MEDIA_LEVEL>(level);
1220     } else {
1221         MEDIA_LOG_D("Parse hevc level failed: " PUBLIC_LOG_D32, level);
1222     }
1223     auto FileType = GetFileTypeByName(avFormatContext);
1224     if (FileType == FileType::MPEGTS ||
1225         FileType == FileType::FLV) {
1226         format.Set<Tag::VIDEO_WIDTH>(static_cast<uint32_t>(parse.picWidInLumaSamples));
1227         format.Set<Tag::VIDEO_HEIGHT>(static_cast<uint32_t>(parse.picHetInLumaSamples));
1228     }
1229 }
1230 
ParseInfoFromMetadata(const AVDictionary * metadata,Meta & format)1231 void FFmpegFormatHelper::ParseInfoFromMetadata(const AVDictionary* metadata, Meta &format)
1232 {
1233     AVDictionaryEntry *valPtr = nullptr;
1234     while ((valPtr = av_dict_get(metadata, "", valPtr, AV_DICT_IGNORE_SUFFIX)) != nullptr) {
1235         std::string tempKey = ToLower(std::string(valPtr->key));
1236         if (tempKey.find("moov_level_meta_key_") == 0) {
1237             MEDIA_LOG_D("UserMeta:" PUBLIC_LOG_S, valPtr->key);
1238             if (g_formatToString.count(tempKey.c_str() + KEY_PREFIX_LEN) > 0 &&
1239                 strlen(valPtr->value) > VALUE_PREFIX_LEN) {
1240                     format.SetData(g_formatToString[tempKey.c_str() + KEY_PREFIX_LEN],
1241                                    std::string(valPtr->value + VALUE_PREFIX_LEN));
1242                 }
1243             continue;
1244         }
1245         if (g_formatToString.count(tempKey) <= 0) {
1246             MEDIA_LOG_D("UnsupportMeta:" PUBLIC_LOG_S, valPtr->key);
1247             continue;
1248         }
1249         MEDIA_LOG_D("SupportMeta:" PUBLIC_LOG_S, valPtr->key);
1250         // ffmpeg use ';' to contact all single value in vorbis-comment, need to remove duplicates
1251         std::string value = RemoveDuplication(std::string(valPtr->value));
1252         format.SetData(g_formatToString[tempKey], value);
1253         if (!IsUTF8(value.c_str()) && IsGBK(value.c_str())) {
1254             std::string resultStr = ConvertGBKToUTF8(value);
1255             if (resultStr.length() > 0) {
1256                 format.SetData(g_formatToString[tempKey], resultStr);
1257             } else {
1258                 MEDIA_LOG_D("Convert utf8 failed");
1259             }
1260         }
1261     }
1262 }
1263 
IsVideoCodecId(const AVCodecID & codecId)1264 bool FFmpegFormatHelper::IsVideoCodecId(const AVCodecID &codecId)
1265 {
1266     if (g_codecIdToMime.count(codecId) == 0) {
1267         return false;
1268     }
1269     return StartWith(std::string(g_codecIdToMime[codecId]).c_str(), "video/");
1270 }
1271 
IsImageTrack(const AVStream & avStream)1272 bool FFmpegFormatHelper::IsImageTrack(const AVStream &avStream)
1273 {
1274     FALSE_RETURN_V_MSG_E(avStream.codecpar != nullptr, false, "AVStream is nullptr");
1275     AVCodecID codecId = avStream.codecpar->codec_id;
1276     return (
1277         (static_cast<uint32_t>(avStream.disposition) & static_cast<uint32_t>(AV_DISPOSITION_ATTACHED_PIC)) ||
1278         (std::count(g_imageCodecID.begin(), g_imageCodecID.end(), codecId) > 0)
1279     );
1280 }
1281 
IsVideoType(const AVStream & avStream)1282 bool FFmpegFormatHelper::IsVideoType(const AVStream &avStream)
1283 {
1284     FALSE_RETURN_V_MSG_E(avStream.codecpar != nullptr, false, "AVStream is nullptr");
1285     AVCodecID codecId = avStream.codecpar->codec_id;
1286     return (avStream.codecpar->codec_type == AVMEDIA_TYPE_VIDEO && !IsImageTrack(avStream)) ||
1287         (g_codecIdToMime.count(codecId) > 0 && g_codecIdToMime[codecId].find("video") != std::string::npos);
1288 }
1289 
IsAudioType(const AVStream & avStream)1290 bool FFmpegFormatHelper::IsAudioType(const AVStream &avStream)
1291 {
1292     FALSE_RETURN_V_MSG_E(avStream.codecpar != nullptr, false, "AVStream is nullptr");
1293     AVCodecID codecId = avStream.codecpar->codec_id;
1294     return avStream.codecpar->codec_type == AVMEDIA_TYPE_AUDIO ||
1295         (g_codecIdToMime.count(codecId) > 0 && g_codecIdToMime[codecId].find("audio") != std::string::npos);
1296 }
1297 
IsMpeg4File(FileType filetype)1298 bool FFmpegFormatHelper::IsMpeg4File(FileType filetype)
1299 {
1300     return filetype == FileType::MP4 || filetype == FileType::MOV;
1301 }
1302 
IsValidCodecId(const AVCodecID & codecId)1303 bool FFmpegFormatHelper::IsValidCodecId(const AVCodecID &codecId)
1304 {
1305     return (g_codecIdToMime.count(codecId) > 0) || (IsPCMStream(codecId));
1306 }
1307 } // namespace Ffmpeg
1308 } // namespace Plugins
1309 } // namespace Media
1310 } // namespace OHOS