1 /*
2  * Copyright (c) 2023 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 <regex>
20 #include <iconv.h>
21 #include "ffmpeg_converter.h"
22 #include "meta/meta_key.h"
23 #include "meta/media_types.h"
24 #include "meta/mime_type.h"
25 #include "meta/video_types.h"
26 #include "meta/audio_types.h"
27 #include "common/log.h"
28 #include "ffmpeg_format_helper.h"
29 
30 #ifdef __cplusplus
31 extern "C" {
32 #endif
33 #include "libavutil/avutil.h"
34 #include "libavutil/display.h"
35 #ifdef __cplusplus
36 }
37 #endif
38 
39 #define DISPLAY_MATRIX_SIZE (static_cast<size_t>(9))
40 #define CONVERT_MATRIX_SIZE (static_cast<size_t>(4))
41 #define CUVA_VERSION_MAP (static_cast<uint16_t>(1))
42 #define TERMINAL_PROVIDE_CODE (static_cast<uint16_t>(4))
43 #define TERMINAL_PROVIDE_ORIENTED_CODE (static_cast<uint16_t>(5))
44 
45 namespace {
46 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_DOMAIN_DEMUXER, "FfmpegFormatHelper" };
47 }
48 
49 namespace OHOS {
50 namespace Media {
51 namespace Plugins {
52 namespace Ffmpeg {
53 const uint32_t MAX_VALUE_LEN = 256;
54 const uint32_t DOUBLE_BYTES = 2;
55 const uint32_t KEY_PREFIX_LEN = 20;
56 const uint32_t VALUE_PREFIX_LEN = 8;
57 const uint32_t VALID_LOCATION_LEN = 2;
58 const int32_t VIDEO_ROTATION_360 = 360;
59 const int32_t AV3A_SAMPLE_8BITS = 8;
60 const int32_t AV3A_SAMPLE_16BITS = 16;
61 const int32_t AV3A_SAMPLE_24BITS = 24;
62 
63 static std::map<AVMediaType, MediaType> g_convertFfmpegTrackType = {
64     {AVMEDIA_TYPE_VIDEO, MediaType::VIDEO},
65     {AVMEDIA_TYPE_AUDIO, MediaType::AUDIO},
66     {AVMEDIA_TYPE_SUBTITLE, MediaType::SUBTITLE},
67     {AVMEDIA_TYPE_TIMEDMETA, MediaType::TIMEDMETA}
68 };
69 
70 static std::map<AVCodecID, std::string_view> g_codecIdToMime = {
71     {AV_CODEC_ID_MP1, MimeType::AUDIO_MPEG},
72     {AV_CODEC_ID_MP2, MimeType::AUDIO_MPEG},
73     {AV_CODEC_ID_MP3, MimeType::AUDIO_MPEG},
74     {AV_CODEC_ID_FLAC, MimeType::AUDIO_FLAC},
75     {AV_CODEC_ID_AAC, MimeType::AUDIO_AAC},
76     {AV_CODEC_ID_VORBIS, MimeType::AUDIO_VORBIS},
77     {AV_CODEC_ID_OPUS, MimeType::AUDIO_OPUS},
78     {AV_CODEC_ID_AMR_NB, MimeType::AUDIO_AMR_NB},
79     {AV_CODEC_ID_AMR_WB, MimeType::AUDIO_AMR_WB},
80     {AV_CODEC_ID_H264, MimeType::VIDEO_AVC},
81     {AV_CODEC_ID_MPEG4, MimeType::VIDEO_MPEG4},
82     {AV_CODEC_ID_MJPEG, MimeType::IMAGE_JPG},
83     {AV_CODEC_ID_PNG, MimeType::IMAGE_PNG},
84     {AV_CODEC_ID_BMP, MimeType::IMAGE_BMP},
85     {AV_CODEC_ID_H263, MimeType::VIDEO_H263},
86     {AV_CODEC_ID_MPEG2TS, MimeType::VIDEO_MPEG2},
87     {AV_CODEC_ID_MPEG2VIDEO, MimeType::VIDEO_MPEG2},
88     {AV_CODEC_ID_HEVC, MimeType::VIDEO_HEVC},
89     {AV_CODEC_ID_VVC, MimeType::VIDEO_VVC},
90     {AV_CODEC_ID_VP8, MimeType::VIDEO_VP8},
91     {AV_CODEC_ID_VP9, MimeType::VIDEO_VP9},
92     {AV_CODEC_ID_AVS3DA, MimeType::AUDIO_AVS3DA},
93     {AV_CODEC_ID_APE, MimeType::AUDIO_APE},
94     {AV_CODEC_ID_PCM_MULAW, MimeType::AUDIO_G711MU},
95     {AV_CODEC_ID_SUBRIP, MimeType::TEXT_SUBRIP},
96     {AV_CODEC_ID_WEBVTT, MimeType::TEXT_WEBVTT},
97     {AV_CODEC_ID_FFMETADATA, MimeType::TIMED_METADATA}
98 };
99 
100 static std::map<std::string, FileType> g_convertFfmpegFileType = {
101     {"mpegts", FileType::MPEGTS},
102     {"matroska,webm", FileType::MKV},
103     {"amr", FileType::AMR},
104     {"amrnb", FileType::AMR},
105     {"amrwb", FileType::AMR},
106     {"aac", FileType::AAC},
107     {"mp3", FileType::MP3},
108     {"flac", FileType::FLAC},
109     {"ogg", FileType::OGG},
110     {"wav", FileType::WAV},
111     {"flv", FileType::FLV},
112     {"avi", FileType::AVI},
113     {"mpeg", FileType::MPEGPS},
114     {"ape", FileType::APE},
115     {"srt", FileType::SRT},
116     {"webvtt", FileType::VTT},
117 };
118 
119 static std::map<TagType, std::string> g_formatToString = {
120     {Tag::MEDIA_TITLE, "title"},
121     {Tag::MEDIA_ARTIST, "artist"},
122     {Tag::MEDIA_ALBUM, "album"},
123     {Tag::MEDIA_ALBUM_ARTIST, "album_artist"},
124     {Tag::MEDIA_DATE, "date"},
125     {Tag::MEDIA_COMMENT, "comment"},
126     {Tag::MEDIA_GENRE, "genre"},
127     {Tag::MEDIA_COPYRIGHT, "copyright"},
128     {Tag::MEDIA_LANGUAGE, "language"},
129     {Tag::MEDIA_DESCRIPTION, "description"},
130     {Tag::MEDIA_LYRICS, "lyrics"},
131     {Tag::MEDIA_AUTHOR, "author"},
132     {Tag::MEDIA_COMPOSER, "composer"},
133     {Tag::MEDIA_CREATION_TIME, "creation_time"}
134 };
135 
136 std::vector<TagType> g_supportSourceFormat = {
137     Tag::MEDIA_TITLE,
138     Tag::MEDIA_ARTIST,
139     Tag::MEDIA_ALBUM,
140     Tag::MEDIA_ALBUM_ARTIST,
141     Tag::MEDIA_DATE,
142     Tag::MEDIA_COMMENT,
143     Tag::MEDIA_GENRE,
144     Tag::MEDIA_COPYRIGHT,
145     Tag::MEDIA_LANGUAGE,
146     Tag::MEDIA_DESCRIPTION,
147     Tag::MEDIA_LYRICS,
148     Tag::MEDIA_AUTHOR,
149     Tag::MEDIA_COMPOSER,
150     Tag::MEDIA_CREATION_TIME
151 };
152 
SwitchCase(const std::string & str)153 std::string SwitchCase(const std::string& str)
154 {
155     std::string res;
156     for (char c : str) {
157         if (c == '_') {
158             res += c;
159         } else {
160             res += std::toupper(c);
161         }
162     }
163     MEDIA_LOG_D("Parse meta " PUBLIC_LOG_S " failed, try to parse " PUBLIC_LOG_S, str.c_str(), res.c_str());
164     return res;
165 }
166 
ConvertGBK2UTF8(char * input,const size_t inputLen,char * output,const size_t outputLen)167 int ConvertGBK2UTF8(char* input, const size_t inputLen, char* output, const size_t outputLen)
168 {
169     MEDIA_LOG_D("Convert GBK to UTF-8, inputLen=" PUBLIC_LOG_ZU, inputLen);
170     int resultLen = -1;
171     size_t inputTempLen = inputLen;
172     size_t outputTempLen = outputLen;
173     iconv_t cd = iconv_open("UTF-8", "GB2312");
174     if (cd != reinterpret_cast<iconv_t>(-1)) {
175         size_t ret = iconv(cd, &input, &inputTempLen, &output, &outputTempLen);
176         if (ret != static_cast<size_t>(-1))  {
177             resultLen = static_cast<int>(outputLen - outputTempLen);
178         } else {
179             MEDIA_LOG_D("Convert failed");
180         }
181         iconv_close(cd);
182     }
183     MEDIA_LOG_D("Convert GBK to UTF-8, resultLen=" PUBLIC_LOG_D32, resultLen);
184     return resultLen;
185 }
186 
IsGBK(const char * data)187 bool IsGBK(const char* data)
188 {
189     int len = static_cast<int>(strlen(data));
190     int i = 0;
191     while (i < len) {
192         if (static_cast<unsigned char>(data[i]) <= 0x7f) { // one byte encoding or ASCII
193             i++;
194             continue;
195         } else { // double bytes encoding
196             if (i + 1  < len &&
197                 static_cast<unsigned char>(data[i]) >= 0x81 && static_cast<unsigned char>(data[i]) <= 0xfe &&
198                 static_cast<unsigned char>(data[i + 1]) >= 0x40 && static_cast<unsigned char>(data[i + 1]) <= 0xfe) {
199                 i += DOUBLE_BYTES; // double bytes
200                 continue;
201             } else {
202                 return false;
203             }
204         }
205     }
206     return true;
207 }
208 
209 static std::vector<AVCodecID> g_imageCodecID = {
210     AV_CODEC_ID_MJPEG,
211     AV_CODEC_ID_PNG,
212     AV_CODEC_ID_PAM,
213     AV_CODEC_ID_BMP,
214     AV_CODEC_ID_JPEG2000,
215     AV_CODEC_ID_TARGA,
216     AV_CODEC_ID_TIFF,
217     AV_CODEC_ID_GIF,
218     AV_CODEC_ID_PCX,
219     AV_CODEC_ID_XWD,
220     AV_CODEC_ID_XBM,
221     AV_CODEC_ID_WEBP,
222     AV_CODEC_ID_APNG,
223     AV_CODEC_ID_XPM,
224     AV_CODEC_ID_SVG,
225 };
226 
227 static std::map<std::string, VideoRotation> g_pFfRotationMap = {
228     {"0", VIDEO_ROTATION_0},
229     {"90", VIDEO_ROTATION_90},
230     {"180", VIDEO_ROTATION_180},
231     {"270", VIDEO_ROTATION_270},
232 };
233 
234 static const std::map<std::string, VideoOrientationType> matrixTypes = {
235     /**
236      * display matrix
237      *                                  | a b u |
238      *   (a, b, u, c, d, v, x, y, w) -> | c d v |
239      *                                  | x y w |
240      * [a b c d] can confirm the orientation type
241      */
242     {"0 -1 1 0", VideoOrientationType::ROTATE_90},
243     {"-1 0 0 -1", VideoOrientationType::ROTATE_180},
244     {"0 1 -1 0", VideoOrientationType::ROTATE_270},
245     {"-1 0 0 1", VideoOrientationType::FLIP_H},
246     {"1 0 0 -1", VideoOrientationType::FLIP_V},
247     {"0 1 1 0", VideoOrientationType::FLIP_H_ROT90},
248     {"0 -1 -1 0", VideoOrientationType::FLIP_V_ROT90},
249 };
250 
GetMatrixType(const std::string & value)251 VideoOrientationType GetMatrixType(const std::string& value)
252 {
253     auto it = matrixTypes.find(value);
254     if (it!= matrixTypes.end()) {
255         return it->second;
256     } else {
257         return VideoOrientationType::ROTATE_NONE;
258     }
259 }
260 
ConvFp(int32_t x)261 inline int ConvFp(int32_t x)
262 {
263     return static_cast<int32_t>(x / (1 << 16)); // 16 is used for digital conversion
264 }
265 
ConvertArrayToString(const int * Array,size_t size)266 std::string ConvertArrayToString(const int* Array, size_t size)
267 {
268     std::string result;
269     for (size_t i = 0; i < size; ++i) {
270         if (i > 0) {
271             result += ' ';
272         }
273         result += std::to_string(Array[i]);
274     }
275     return result;
276 }
277 
IsPCMStream(AVCodecID codecID)278 bool IsPCMStream(AVCodecID codecID)
279 {
280     MEDIA_LOG_D("CodecID " PUBLIC_LOG_D32 "[" PUBLIC_LOG_S "]",
281         static_cast<int32_t>(codecID), avcodec_get_name(codecID));
282     return StartWith(avcodec_get_name(codecID), "pcm_");
283 }
284 
GetDefaultTrackStartTime(const AVFormatContext & avFormatContext)285 int64_t GetDefaultTrackStartTime(const AVFormatContext& avFormatContext)
286 {
287     int64_t dafaultTime = 0;
288     for (uint32_t trackIndex = 0; trackIndex < avFormatContext.nb_streams; ++trackIndex) {
289         auto avStream = avFormatContext.streams[trackIndex];
290         if (avStream != nullptr && avStream->codecpar != nullptr &&
291             avStream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && avStream->start_time != AV_NOPTS_VALUE) {
292             dafaultTime = AvTime2Us(ConvertTimeFromFFmpeg(avStream->start_time, avStream->time_base));
293         }
294     }
295     return dafaultTime;
296 }
297 
FfAv3aGetNbObjects(AVChannelLayout * channelLayout)298 static int FfAv3aGetNbObjects(AVChannelLayout *channelLayout)
299 {
300     int nbObjects = 0;
301     if (channelLayout->order != AV_CHANNEL_ORDER_CUSTOM) {
302         return 0;
303     }
304     for (int i = 0; i < channelLayout->nb_channels; i++) {
305         if (channelLayout->u.map[i].id == AV3A_CH_AUDIO_OBJECT) {
306             nbObjects++;
307         }
308     }
309     return nbObjects;
310 }
311 
FfAv3aGetChannelLayoutMask(AVChannelLayout * channelLayout)312 static uint64_t FfAv3aGetChannelLayoutMask(AVChannelLayout *channelLayout)
313 {
314     uint64_t mask = 0L;
315     if (channelLayout->order != AV_CHANNEL_ORDER_CUSTOM) {
316         return 0;
317     }
318     for (int i = 0; i < channelLayout->nb_channels; i++) {
319         if (channelLayout->u.map[i].id == AV3A_CH_AUDIO_OBJECT) {
320             return mask;
321         }
322         mask |= (1ULL << channelLayout->u.map[i].id);
323     }
324     return mask;
325 }
326 
ParseTrackType(const AVFormatContext & avFormatContext,Meta & format)327 void FFmpegFormatHelper::ParseTrackType(const AVFormatContext& avFormatContext, Meta& format)
328 {
329     format.Set<Tag::MEDIA_TRACK_COUNT>(static_cast<int32_t>(avFormatContext.nb_streams));
330     bool hasVideo = false;
331     bool hasAudio = false;
332     bool hasSubtitle = false;
333     bool hasTimedMeta = false;
334     for (uint32_t i = 0; i < avFormatContext.nb_streams; ++i) {
335         if (avFormatContext.streams[i] == nullptr || avFormatContext.streams[i]->codecpar == nullptr) {
336             MEDIA_LOG_W("Track " PUBLIC_LOG_U32 " is invalid", i);
337             continue;
338         }
339         if (avFormatContext.streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
340             AVCodecID codecID = avFormatContext.streams[i]->codecpar->codec_id;
341             if (std::count(g_imageCodecID.begin(), g_imageCodecID.end(), codecID) <= 0) {
342                 hasVideo = true;
343             }
344         } else if (avFormatContext.streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
345             hasAudio = true;
346         } else if (avFormatContext.streams[i]->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) {
347             hasSubtitle = true;
348         } else if (avFormatContext.streams[i]->codecpar->codec_type == AVMEDIA_TYPE_TIMEDMETA) {
349             hasTimedMeta = true;
350         }
351     }
352     format.Set<Tag::MEDIA_HAS_VIDEO>(hasVideo);
353     format.Set<Tag::MEDIA_HAS_AUDIO>(hasAudio);
354     format.Set<Tag::MEDIA_HAS_SUBTITLE>(hasSubtitle);
355     format.Set<Tag::MEDIA_HAS_TIMEDMETA>(hasTimedMeta);
356 }
357 
ParseMediaInfo(const AVFormatContext & avFormatContext,Meta & format)358 void FFmpegFormatHelper::ParseMediaInfo(const AVFormatContext& avFormatContext, Meta& format)
359 {
360     ParseTrackType(avFormatContext, format);
361     format.Set<Tag::MEDIA_FILE_TYPE>(GetFileTypeByName(avFormatContext));
362     int64_t duration = avFormatContext.duration;
363     if (duration == AV_NOPTS_VALUE) {
364         duration = 0;
365         const AVDictionaryEntry *metaDuration = av_dict_get(avFormatContext.metadata, "DURATION", NULL, 0);
366         int64_t us;
367         if (metaDuration != nullptr && (av_parse_time(&us, metaDuration->value, 1) == 0)) {
368             if (us > duration) {
369                 duration = us;
370             }
371         }
372     }
373     if (duration > 0 && duration != AV_NOPTS_VALUE) {
374         format.Set<Tag::MEDIA_DURATION>(static_cast<int64_t>(duration));
375     }
376     if (avFormatContext.start_time != AV_NOPTS_VALUE) {
377         format.Set<Tag::MEDIA_CONTAINER_START_TIME>(static_cast<int64_t>(avFormatContext.start_time));
378     } else {
379         format.Set<Tag::MEDIA_CONTAINER_START_TIME>(static_cast<int64_t>(0));
380         MEDIA_LOG_W("Parse container start time failed");
381     }
382     ParseLocationInfo(avFormatContext, format);
383     for (TagType key: g_supportSourceFormat) {
384         ParseInfoFromMetadata(avFormatContext.metadata, key, format);
385     }
386 }
387 
ParseLocationInfo(const AVFormatContext & avFormatContext,Meta & format)388 void FFmpegFormatHelper::ParseLocationInfo(const AVFormatContext& avFormatContext, Meta &format)
389 {
390     MEDIA_LOG_D("Parse location info");
391     AVDictionaryEntry *valPtr = nullptr;
392     valPtr = av_dict_get(avFormatContext.metadata, "location", nullptr, AV_DICT_MATCH_CASE);
393     if (valPtr == nullptr) {
394         valPtr = av_dict_get(avFormatContext.metadata, "LOCATION", nullptr, AV_DICT_MATCH_CASE);
395     }
396     if (valPtr == nullptr) {
397         MEDIA_LOG_D("Parse failed");
398         return;
399     }
400     MEDIA_LOG_D("Get location string successfully: %{private}s", valPtr->value);
401     std::string locationStr = std::string(valPtr->value);
402     std::regex pattern(R"([\+\-]\d+\.\d+)");
403     std::sregex_iterator numbers(locationStr.cbegin(), locationStr.cend(), pattern);
404     std::sregex_iterator end;
405     // at least contain latitude and longitude
406     if (std::distance(numbers, end) < VALID_LOCATION_LEN) {
407         MEDIA_LOG_D("Info format error");
408         return;
409     }
410     format.Set<Tag::MEDIA_LATITUDE>(std::stof(numbers->str()));
411     format.Set<Tag::MEDIA_LONGITUDE>(std::stof((++numbers)->str()));
412 }
413 
ParseUserMeta(const AVFormatContext & avFormatContext,std::shared_ptr<Meta> format)414 void FFmpegFormatHelper::ParseUserMeta(const AVFormatContext& avFormatContext, std::shared_ptr<Meta> format)
415 {
416     MEDIA_LOG_D("Parse user data info");
417     AVDictionaryEntry *valPtr = nullptr;
418     while ((valPtr = av_dict_get(avFormatContext.metadata, "", valPtr, AV_DICT_IGNORE_SUFFIX)))  {
419         if (StartWith(valPtr->key, "moov_level_meta_key_")) {
420             MEDIA_LOG_D("Ffmpeg key: " PUBLIC_LOG_S, (valPtr->key));
421             if (strlen(valPtr->value) <= VALUE_PREFIX_LEN) {
422                 MEDIA_LOG_D("Parse user data info " PUBLIC_LOG_S " failed, value too short", valPtr->key);
423                 continue;
424             }
425             if (StartWith(valPtr->value, "00000001")) { // string
426                 MEDIA_LOG_D("Key: " PUBLIC_LOG_S " | type: string", (valPtr->key + KEY_PREFIX_LEN));
427                 format->SetData(valPtr->key + KEY_PREFIX_LEN, std::string(valPtr->value + VALUE_PREFIX_LEN));
428             } else if (StartWith(valPtr->value, "00000017")) { // float
429                 MEDIA_LOG_D("Key: " PUBLIC_LOG_S " | type: float", (valPtr->key + KEY_PREFIX_LEN));
430                 format->SetData(valPtr->key + KEY_PREFIX_LEN, std::stof(valPtr->value + VALUE_PREFIX_LEN));
431             } else if (StartWith(valPtr->value, "00000043") || StartWith(valPtr->value, "00000015")) { // int
432                 MEDIA_LOG_D("Key: " PUBLIC_LOG_S " | type: int", (valPtr->key + KEY_PREFIX_LEN));
433                 format->SetData(valPtr->key + KEY_PREFIX_LEN, std::stoi(valPtr->value + VALUE_PREFIX_LEN));
434             } else { // unknow
435                 MEDIA_LOG_D("Key: " PUBLIC_LOG_S " | type: unknow", (valPtr->key + KEY_PREFIX_LEN));
436                 format->SetData(valPtr->key + KEY_PREFIX_LEN, std::string(valPtr->value + VALUE_PREFIX_LEN));
437             }
438         }
439     }
440 }
441 
ParseTrackInfo(const AVStream & avStream,Meta & format,const AVFormatContext & avFormatContext)442 void FFmpegFormatHelper::ParseTrackInfo(const AVStream& avStream, Meta& format, const AVFormatContext& avFormatContext)
443 {
444     FALSE_RETURN_MSG(avStream.codecpar != nullptr, "Codecpar is nullptr");
445     ParseBaseTrackInfo(avStream, format, avFormatContext);
446     if (avStream.codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
447         if ((static_cast<uint32_t>(avStream.disposition) & static_cast<uint32_t>(AV_DISPOSITION_ATTACHED_PIC)) ||
448             (std::count(g_imageCodecID.begin(), g_imageCodecID.end(), avStream.codecpar->codec_id) > 0)) {
449             ParseImageTrackInfo(avStream, format);
450         } else {
451             ParseAVTrackInfo(avStream, format);
452             ParseVideoTrackInfo(avStream, format, avFormatContext);
453         }
454     } else if (avStream.codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
455         ParseAVTrackInfo(avStream, format);
456         ParseAudioTrackInfo(avStream, format);
457     } else if (avStream.codecpar->codec_type == AVMEDIA_TYPE_TIMEDMETA) {
458         ParseAVTrackInfo(avStream, format);
459         ParseTimedMetaTrackInfo(avStream, format);
460     }
461 }
462 
ParseBaseTrackInfo(const AVStream & avStream,Meta & format,const AVFormatContext & avFormatContext)463 void FFmpegFormatHelper::ParseBaseTrackInfo(const AVStream& avStream, Meta &format,
464                                             const AVFormatContext& avFormatContext)
465 {
466     if (g_codecIdToMime.count(avStream.codecpar->codec_id) != 0) {
467         format.Set<Tag::MIME_TYPE>(std::string(g_codecIdToMime[avStream.codecpar->codec_id]));
468     } else if (IsPCMStream(avStream.codecpar->codec_id)) {
469         format.Set<Tag::MIME_TYPE>(std::string(MimeType::AUDIO_RAW));
470     } else {
471         format.Set<Tag::MIME_TYPE>(std::string(MimeType::INVALID_TYPE));
472         MEDIA_LOG_W("Parse mime type failed: " PUBLIC_LOG_D32, static_cast<int32_t>(avStream.codecpar->codec_id));
473     }
474 
475     AVMediaType mediaType = avStream.codecpar->codec_type;
476     if (g_convertFfmpegTrackType.count(mediaType) > 0) {
477         format.Set<Tag::MEDIA_TYPE>(g_convertFfmpegTrackType[mediaType]);
478     } else {
479         MEDIA_LOG_W("Parse track type failed: " PUBLIC_LOG_D32, static_cast<int32_t>(mediaType));
480     }
481 
482     if (avStream.start_time != AV_NOPTS_VALUE) {
483         format.SetData(Tag::MEDIA_START_TIME,
484             AvTime2Us(ConvertTimeFromFFmpeg(avStream.start_time, avStream.time_base)));
485     } else {
486         if (mediaType == AVMEDIA_TYPE_AUDIO) {
487             format.SetData(Tag::MEDIA_START_TIME, GetDefaultTrackStartTime(avFormatContext));
488         }
489         MEDIA_LOG_W("Parse track start time failed");
490     }
491 }
492 
GetFileTypeByName(const AVFormatContext & avFormatContext)493 FileType FFmpegFormatHelper::GetFileTypeByName(const AVFormatContext& avFormatContext)
494 {
495     FALSE_RETURN_V_MSG_E(avFormatContext.iformat != nullptr, FileType::UNKNOW, "Iformat is nullptr");
496     const char *fileName = avFormatContext.iformat->name;
497     FileType fileType = FileType::UNKNOW;
498     if (StartWith(fileName, "mov,mp4,m4a")) {
499         const AVDictionaryEntry *type = av_dict_get(avFormatContext.metadata, "major_brand", NULL, 0);
500         if (type == nullptr) {
501             MEDIA_LOG_D("Not found ftyp");
502             return FileType::MP4;
503         }
504         if (StartWith(type->value, "m4a") || StartWith(type->value, "M4A") ||
505             StartWith(type->value, "m4v") || StartWith(type->value, "M4V")) {
506             fileType = FileType::M4A;
507         } else if (StartWith(type->value, "qt") || StartWith(type->value, "QT")) {
508             fileType = FileType::MOV;
509         } else {
510             fileType = FileType::MP4;
511         }
512     } else {
513         if (g_convertFfmpegFileType.count(fileName) != 0) {
514             fileType = g_convertFfmpegFileType[fileName];
515         }
516     }
517     MEDIA_LOG_D("File name [" PUBLIC_LOG_S "] file type [" PUBLIC_LOG_D32 "]",
518         fileName, static_cast<int32_t>(fileType));
519     return fileType;
520 }
521 
ParseAVTrackInfo(const AVStream & avStream,Meta & format)522 void FFmpegFormatHelper::ParseAVTrackInfo(const AVStream& avStream, Meta &format)
523 {
524     int64_t bitRate = static_cast<int64_t>(avStream.codecpar->bit_rate);
525     if (bitRate > 0) {
526         format.Set<Tag::MEDIA_BITRATE>(bitRate);
527     } else {
528         MEDIA_LOG_D("Parse bitrate failed: " PUBLIC_LOG_D64, bitRate);
529     }
530 
531     if (avStream.codecpar->extradata_size > 0 && avStream.codecpar->extradata != nullptr) {
532         std::vector<uint8_t> extra(avStream.codecpar->extradata_size);
533         extra.assign(avStream.codecpar->extradata, avStream.codecpar->extradata + avStream.codecpar->extradata_size);
534         format.Set<Tag::MEDIA_CODEC_CONFIG>(extra);
535     } else {
536         MEDIA_LOG_D("Parse codec config failed");
537     }
538     AVDictionaryEntry *valPtr = nullptr;
539     valPtr = av_dict_get(avStream.metadata, "language", nullptr, AV_DICT_MATCH_CASE);
540     if (valPtr != nullptr) {
541         format.SetData(Tag::MEDIA_LANGUAGE, std::string(valPtr->value));
542     } else {
543         MEDIA_LOG_D("Parse track language failed");
544     }
545 }
546 
ParseVideoTrackInfo(const AVStream & avStream,Meta & format,const AVFormatContext & avFormatContext)547 void FFmpegFormatHelper::ParseVideoTrackInfo(const AVStream& avStream, Meta &format,
548                                              const AVFormatContext& avFormatContext)
549 {
550     format.Set<Tag::VIDEO_WIDTH>(static_cast<uint32_t>(avStream.codecpar->width));
551     format.Set<Tag::VIDEO_HEIGHT>(static_cast<uint32_t>(avStream.codecpar->height));
552     format.Set<Tag::VIDEO_DELAY>(static_cast<uint32_t>(avStream.codecpar->video_delay));
553 
554     double frameRate = 0;
555     if (avStream.avg_frame_rate.den == 0 || avStream.avg_frame_rate.num == 0) {
556         frameRate = static_cast<double>(av_q2d(avStream.r_frame_rate));
557     } else {
558         frameRate = static_cast<double>(av_q2d(avStream.avg_frame_rate));
559     }
560     if (frameRate > 0) {
561         format.Set<Tag::VIDEO_FRAME_RATE>(frameRate);
562     } else {
563         MEDIA_LOG_D("Parse frame rate failed: " PUBLIC_LOG_F, frameRate);
564     }
565 
566     AVDictionaryEntry *valPtr = nullptr;
567     valPtr = av_dict_get(avStream.metadata, "rotate", nullptr, AV_DICT_MATCH_CASE);
568     if (valPtr == nullptr) {
569         valPtr = av_dict_get(avStream.metadata, "ROTATE", nullptr, AV_DICT_MATCH_CASE);
570     }
571     if (valPtr == nullptr) {
572         MEDIA_LOG_D("Parse rotate info from meta failed");
573         ParseRotationFromMatrix(avStream, format);
574     } else {
575         if (g_pFfRotationMap.count(std::string(valPtr->value)) > 0) {
576             format.Set<Tag::VIDEO_ROTATION>(g_pFfRotationMap[std::string(valPtr->value)]);
577         }
578     }
579     if (GetFileTypeByName(avFormatContext) == FileType::MP4) {
580         ParseOrientationFromMatrix(avStream, format);
581     }
582 
583     AVRational sar = avStream.sample_aspect_ratio;
584     if (sar.num && sar.den) {
585         format.Set<Tag::VIDEO_SAR>(static_cast<double>(av_q2d(sar)));
586     }
587 
588     if (avStream.codecpar->codec_id == AV_CODEC_ID_HEVC) {
589         ParseHvccBoxInfo(avStream, format);
590         ParseColorBoxInfo(avStream, format);
591     }
592 }
593 
ParseRotationFromMatrix(const AVStream & avStream,Meta & format)594 void FFmpegFormatHelper::ParseRotationFromMatrix(const AVStream& avStream, Meta &format)
595 {
596     int32_t *displayMatrix = (int32_t *)av_stream_get_side_data(&avStream, AV_PKT_DATA_DISPLAYMATRIX, NULL);
597     if (displayMatrix) {
598         float rotation = -round(av_display_rotation_get(displayMatrix));
599         MEDIA_LOG_D("Parse rotate info from display matrix: " PUBLIC_LOG_F, rotation);
600         if (isnan(rotation)) {
601             format.Set<Tag::VIDEO_ROTATION>(g_pFfRotationMap["0"]);
602             return;
603         } else if (rotation < 0) {
604             rotation += VIDEO_ROTATION_360;
605         }
606         switch (int(rotation)) {
607             case VIDEO_ROTATION_90:
608                 format.Set<Tag::VIDEO_ROTATION>(g_pFfRotationMap["90"]);
609                 break;
610             case VIDEO_ROTATION_180:
611                 format.Set<Tag::VIDEO_ROTATION>(g_pFfRotationMap["180"]);
612                 break;
613             case VIDEO_ROTATION_270:
614                 format.Set<Tag::VIDEO_ROTATION>(g_pFfRotationMap["270"]);
615                 break;
616             default:
617                 format.Set<Tag::VIDEO_ROTATION>(g_pFfRotationMap["0"]);
618                 break;
619         }
620     } else {
621         MEDIA_LOG_D("Parse rotate info from display matrix failed, set rotation as dafault 0");
622         format.Set<Tag::VIDEO_ROTATION>(g_pFfRotationMap["0"]);
623     }
624 }
625 
PrintMatrixToLog(int32_t * matrix,const std::string & matrixName)626 void PrintMatrixToLog(int32_t * matrix, const std::string& matrixName)
627 {
628     MEDIA_LOG_D(PUBLIC_LOG_S ": [" PUBLIC_LOG_D32 " " PUBLIC_LOG_D32 " " PUBLIC_LOG_D32 " " PUBLIC_LOG_D32 " "
629             PUBLIC_LOG_D32 " " PUBLIC_LOG_D32 " " PUBLIC_LOG_D32 " " PUBLIC_LOG_D32 " " PUBLIC_LOG_D32 "]",
630             matrixName.c_str(), matrix[0], matrix[1], matrix[2], matrix[3], matrix[4],
631             matrix[5], matrix[6], matrix[7], matrix[8]);
632 }
633 
ParseOrientationFromMatrix(const AVStream & avStream,Meta & format)634 void FFmpegFormatHelper::ParseOrientationFromMatrix(const AVStream& avStream, Meta &format)
635 {
636     VideoOrientationType orientationType = VideoOrientationType::ROTATE_NONE;
637     int32_t *displayMatrix = (int32_t *)av_stream_get_side_data(&avStream, AV_PKT_DATA_DISPLAYMATRIX, NULL);
638     if (displayMatrix) {
639         PrintMatrixToLog(displayMatrix, "displayMatrix");
640         int convertedMatrix[CONVERT_MATRIX_SIZE];
641         std::transform(&displayMatrix[0], &displayMatrix[0] + 1, // 0 is displayMatrix index, 1 is copy lenth
642                        &convertedMatrix[0], ConvFp); // 0 is convertedMatrix index
643         std::transform(&displayMatrix[1], &displayMatrix[1] + 1, // 1 is displayMatrix index, 1 is copy lenth
644                        &convertedMatrix[1], ConvFp); // 1 is convertedMatrix index
645         std::transform(&displayMatrix[3], &displayMatrix[3] + 1, // 3 is displayMatrix index, 1 is copy lenth
646                        &convertedMatrix[2], ConvFp); // 2 is convertedMatrix index
647         std::transform(&displayMatrix[4], &displayMatrix[4] + 1, // 4 is displayMatrix index, 1 is copy lenth
648                        &convertedMatrix[3], ConvFp); // 3 is convertedMatrix index
649         orientationType = GetMatrixType(ConvertArrayToString(convertedMatrix, CONVERT_MATRIX_SIZE));
650     } else {
651         MEDIA_LOG_D("Parse orientation info from display matrix failed, set orientation as dafault 0");
652     }
653     format.Set<Tag::VIDEO_ORIENTATION_TYPE>(orientationType);
654     MEDIA_LOG_D("Type of matrix is: " PUBLIC_LOG_D32, static_cast<int>(orientationType));
655 }
656 
ParseImageTrackInfo(const AVStream & avStream,Meta & format)657 void FFmpegFormatHelper::ParseImageTrackInfo(const AVStream& avStream, Meta &format)
658 {
659     format.Set<Tag::VIDEO_WIDTH>(static_cast<uint32_t>(avStream.codecpar->width));
660     format.Set<Tag::VIDEO_HEIGHT>(static_cast<uint32_t>(avStream.codecpar->height));
661     AVPacket pkt = avStream.attached_pic;
662     if (pkt.size > 0 && pkt.data != nullptr) {
663         std::vector<uint8_t> cover(pkt.size);
664         cover.assign(pkt.data, pkt.data + pkt.size);
665         format.Set<Tag::MEDIA_COVER>(cover);
666     } else {
667         MEDIA_LOG_D("Parse cover failed: " PUBLIC_LOG_D32, pkt.size);
668     }
669 }
670 
ParseAudioTrackInfo(const AVStream & avStream,Meta & format)671 void FFmpegFormatHelper::ParseAudioTrackInfo(const AVStream& avStream, Meta &format)
672 {
673     int sampelRate = avStream.codecpar->sample_rate;
674     int channels = avStream.codecpar->channels;
675     if (channels <= 0) {
676         channels = avStream.codecpar->ch_layout.nb_channels;
677     }
678     int frameSize = avStream.codecpar->frame_size;
679     if (sampelRate > 0) {
680         format.Set<Tag::AUDIO_SAMPLE_RATE>(static_cast<uint32_t>(sampelRate));
681     } else {
682         MEDIA_LOG_D("Parse sample rate failed: " PUBLIC_LOG_D32, sampelRate);
683     }
684     if (channels > 0) {
685         format.Set<Tag::AUDIO_OUTPUT_CHANNELS>(static_cast<uint32_t>(channels));
686         format.Set<Tag::AUDIO_CHANNEL_COUNT>(static_cast<uint32_t>(channels));
687     } else {
688         MEDIA_LOG_D("Parse channel count failed: " PUBLIC_LOG_D32, channels);
689     }
690     if (frameSize > 0) {
691         format.Set<Tag::AUDIO_SAMPLE_PER_FRAME>(static_cast<uint32_t>(frameSize));
692     } else {
693         MEDIA_LOG_D("Parse frame rate failed: " PUBLIC_LOG_D32, frameSize);
694     }
695     AudioChannelLayout channelLayout = FFMpegConverter::ConvertFFToOHAudioChannelLayoutV2(
696         avStream.codecpar->channel_layout, channels);
697     format.Set<Tag::AUDIO_OUTPUT_CHANNEL_LAYOUT>(channelLayout);
698     format.Set<Tag::AUDIO_CHANNEL_LAYOUT>(channelLayout);
699 
700     AudioSampleFormat fmt = (IsPCMStream(avStream.codecpar->codec_id)) ?
701         FFMpegConverter::ConvertFFMpegAVCodecIdToOHAudioFormat(avStream.codecpar->codec_id) :
702         FFMpegConverter::ConvertFFMpegToOHAudioFormat(static_cast<AVSampleFormat>(avStream.codecpar->format));
703     format.Set<Tag::AUDIO_SAMPLE_FORMAT>(fmt);
704 
705     if (avStream.codecpar->codec_id == AV_CODEC_ID_AAC) {
706         format.Set<Tag::AUDIO_AAC_IS_ADTS>(1);
707     } else if (avStream.codecpar->codec_id == AV_CODEC_ID_AAC_LATM) {
708         format.Set<Tag::AUDIO_AAC_IS_ADTS>(0);
709     }
710     format.Set<Tag::AUDIO_BITS_PER_CODED_SAMPLE>(avStream.codecpar->bits_per_coded_sample);
711     format.Set<Tag::AUDIO_BITS_PER_RAW_SAMPLE>(avStream.codecpar->bits_per_raw_sample);
712 
713     if (avStream.codecpar->codec_id == AV_CODEC_ID_AVS3DA) {
714         format.Set<Tag::AUDIO_CHANNEL_LAYOUT>(AudioChannelLayout::UNKNOWN);
715         format.Set<Tag::AUDIO_OUTPUT_CHANNEL_LAYOUT>(AudioChannelLayout::UNKNOWN);
716         if (avStream.codecpar->ch_layout.order == AV_CHANNEL_ORDER_CUSTOM ||
717             avStream.codecpar->ch_layout.order == AV_CHANNEL_ORDER_AMBISONIC) {
718             ParseAv3aInfo(avStream, format);
719         }
720         ConvertAv3aSampleFormat(avStream, format);
721     }
722 }
723 
ConvertAv3aSampleFormat(const AVStream & avStream,Meta & format)724 void FFmpegFormatHelper::ConvertAv3aSampleFormat(const AVStream& avStream, Meta &format)
725 {
726     AudioSampleFormat fmt;
727     switch (avStream.codecpar->bits_per_raw_sample) {
728         case AV3A_SAMPLE_8BITS: // 8 bits
729             fmt = AudioSampleFormat::SAMPLE_U8;
730             break;
731         case AV3A_SAMPLE_16BITS: // 16 bits
732             fmt = AudioSampleFormat::SAMPLE_S16LE;
733             break;
734         case AV3A_SAMPLE_24BITS: // 24 bits
735             fmt = AudioSampleFormat::SAMPLE_S24LE;
736             break;
737         default:
738             fmt = AudioSampleFormat::INVALID_WIDTH;
739             break;
740     }
741     format.Set<Tag::AUDIO_SAMPLE_FORMAT>(fmt);
742 }
743 
ParseAv3aInfo(const AVStream & avStream,Meta & format)744 void FFmpegFormatHelper::ParseAv3aInfo(const AVStream& avStream, Meta &format)
745 {
746     int channels = avStream.codecpar->channels; // 总通道数
747     AudioChannelLayout channelLayout = AudioChannelLayout::UNKNOWN;
748     int objectNumber = 0; // 对象数量
749     uint64_t channelLayoutMask = 0L;
750     if (avStream.codecpar->ch_layout.order == AV_CHANNEL_ORDER_CUSTOM) {
751         // 获取mask(如果是纯对象模式则不包含声场,返回0L)
752         channelLayoutMask = FfAv3aGetChannelLayoutMask(&avStream.codecpar->ch_layout);
753         objectNumber = FfAv3aGetNbObjects(&avStream.codecpar->ch_layout); // 获取对象数量,如果不包含对象返回0
754         if (channelLayoutMask > 0L) {
755             channelLayout = FFMpegConverter::ConvertAudioVividToOHAudioChannelLayout(
756                 channelLayoutMask, channels - objectNumber);
757             if (channelLayoutMask != static_cast<uint64_t>(channelLayout)) {
758                 MEDIA_LOG_W("Get channel layout failed, use default channel layout");
759             }
760         } else {
761             channelLayout = AudioChannelLayout::UNKNOWN;
762         }
763     } else if (avStream.codecpar->ch_layout.order == AV_CHANNEL_ORDER_AMBISONIC) {
764         int hoaOrder = static_cast<int>(sqrt(channels)) - 1;
765         if (hoaOrder == 1) {
766             channelLayout = AudioChannelLayout::HOA_ORDER1_ACN_SN3D;
767         } else if (hoaOrder == 2) { // hoaOrder is 2
768             channelLayout = AudioChannelLayout::HOA_ORDER2_ACN_SN3D;
769         } else if (hoaOrder == 3) { // hoaOrder is 3
770             channelLayout = AudioChannelLayout::HOA_ORDER3_ACN_SN3D;
771         } else {
772             MEDIA_LOG_W("Get hoa order failed");
773         }
774         format.Set<Tag::AUDIO_HOA_ORDER>(hoaOrder);
775     } else {
776         MEDIA_LOG_W("Get channel layout failed");
777     }
778     format.Set<Tag::AUDIO_OBJECT_NUMBER>(objectNumber);
779     format.Set<Tag::AUDIO_SOUNDBED_CHANNELS_NUMBER>(channels - objectNumber);
780     // 设置一个整个音频内容通道总数
781     format.Set<Tag::AUDIO_OUTPUT_CHANNEL_LAYOUT>(channelLayout);
782     format.Set<Tag::AUDIO_CHANNEL_LAYOUT>(channelLayout);
783     if (channels > 0) {
784         format.Set<Tag::AUDIO_OUTPUT_CHANNELS>(static_cast<uint32_t>(channels));
785         format.Set<Tag::AUDIO_CHANNEL_COUNT>(static_cast<uint32_t>(channels));
786     } else {
787         MEDIA_LOG_D("Parse channel count failed: " PUBLIC_LOG_D32, channels);
788     }
789 }
790 
ParseTimedMetaTrackInfo(const AVStream & avStream,Meta & format)791 void FFmpegFormatHelper::ParseTimedMetaTrackInfo(const AVStream& avStream, Meta &format)
792 {
793     AVDictionaryEntry *valPtr = nullptr;
794     valPtr = av_dict_get(avStream.metadata, "timed_metadata_key", nullptr, AV_DICT_IGNORE_SUFFIX);
795     if (valPtr == nullptr) {
796         MEDIA_LOG_W("Get timed metadata key failed");
797     } else {
798         format.Set<Tag::TIMED_METADATA_KEY>(std::string(valPtr->value));
799     }
800     valPtr = av_dict_get(avStream.metadata, "src_track_id", nullptr, AV_DICT_MATCH_CASE);
801     if (valPtr == nullptr) {
802         MEDIA_LOG_W("Get src track id failed");
803     } else {
804         format.Set<Tag::TIMED_METADATA_SRC_TRACK>(std::stoi(valPtr->value));
805     }
806 }
807 
ParseHvccBoxInfo(const AVStream & avStream,Meta & format)808 void FFmpegFormatHelper::ParseHvccBoxInfo(const AVStream& avStream, Meta &format)
809 {
810     HEVCProfile profile = FFMpegConverter::ConvertFFMpegToOHHEVCProfile(avStream.codecpar->profile);
811     if (profile != HEVCProfile::HEVC_PROFILE_UNKNOW) {
812         format.Set<Tag::VIDEO_H265_PROFILE>(profile);
813         format.Set<Tag::MEDIA_PROFILE>(profile);
814     } else {
815         MEDIA_LOG_D("Parse hevc profile failed: " PUBLIC_LOG_D32, profile);
816     }
817     HEVCLevel level = FFMpegConverter::ConvertFFMpegToOHHEVCLevel(avStream.codecpar->level);
818     if (level != HEVCLevel::HEVC_LEVEL_UNKNOW) {
819         format.Set<Tag::VIDEO_H265_LEVEL>(level);
820         format.Set<Tag::MEDIA_LEVEL>(level);
821     } else {
822         MEDIA_LOG_D("Parse hevc level failed: " PUBLIC_LOG_D32, level);
823     }
824 }
825 
ParseColorBoxInfo(const AVStream & avStream,Meta & format)826 void FFmpegFormatHelper::ParseColorBoxInfo(const AVStream& avStream, Meta &format)
827 {
828     int colorRange = FFMpegConverter::ConvertFFMpegToOHColorRange(avStream.codecpar->color_range);
829     format.Set<Tag::VIDEO_COLOR_RANGE>(static_cast<bool>(colorRange));
830 
831     ColorPrimary colorPrimaries = FFMpegConverter::ConvertFFMpegToOHColorPrimaries(avStream.codecpar->color_primaries);
832     format.Set<Tag::VIDEO_COLOR_PRIMARIES>(colorPrimaries);
833 
834     TransferCharacteristic colorTrans = FFMpegConverter::ConvertFFMpegToOHColorTrans(avStream.codecpar->color_trc);
835     format.Set<Tag::VIDEO_COLOR_TRC>(colorTrans);
836 
837     MatrixCoefficient colorMatrix = FFMpegConverter::ConvertFFMpegToOHColorMatrix(avStream.codecpar->color_space);
838     format.Set<Tag::VIDEO_COLOR_MATRIX_COEFF>(colorMatrix);
839 
840     ChromaLocation chromaLoc = FFMpegConverter::ConvertFFMpegToOHChromaLocation(avStream.codecpar->chroma_location);
841     format.Set<Tag::VIDEO_CHROMA_LOCATION>(chromaLoc);
842 }
843 
ParseHevcInfo(const AVFormatContext & avFormatContext,HevcParseFormat parse,Meta & format)844 void FFmpegFormatHelper::ParseHevcInfo(const AVFormatContext &avFormatContext, HevcParseFormat parse, Meta &format)
845 {
846     if (parse.isHdrVivid) {
847         format.Set<Tag::VIDEO_IS_HDR_VIVID>(true);
848     }
849 
850     format.Set<Tag::VIDEO_COLOR_RANGE>((bool)(parse.colorRange));
851 
852     ColorPrimary colorPrimaries = FFMpegConverter::ConvertFFMpegToOHColorPrimaries(
853         static_cast<AVColorPrimaries>(parse.colorPrimaries));
854     format.Set<Tag::VIDEO_COLOR_PRIMARIES>(colorPrimaries);
855 
856     TransferCharacteristic colorTrans = FFMpegConverter::ConvertFFMpegToOHColorTrans(
857         static_cast<AVColorTransferCharacteristic>(parse.colorTransfer));
858     format.Set<Tag::VIDEO_COLOR_TRC>(colorTrans);
859 
860     MatrixCoefficient colorMatrix = FFMpegConverter::ConvertFFMpegToOHColorMatrix(
861         static_cast<AVColorSpace>(parse.colorMatrixCoeff));
862     format.Set<Tag::VIDEO_COLOR_MATRIX_COEFF>(colorMatrix);
863 
864     ChromaLocation chromaLoc = FFMpegConverter::ConvertFFMpegToOHChromaLocation(
865         static_cast<AVChromaLocation>(parse.chromaLocation));
866     format.Set<Tag::VIDEO_CHROMA_LOCATION>(chromaLoc);
867 
868     HEVCProfile profile = FFMpegConverter::ConvertFFMpegToOHHEVCProfile(static_cast<int>(parse.profile));
869     if (profile != HEVCProfile::HEVC_PROFILE_UNKNOW) {
870         format.Set<Tag::VIDEO_H265_PROFILE>(profile);
871         format.Set<Tag::MEDIA_PROFILE>(profile);
872     } else {
873         MEDIA_LOG_D("Parse hevc profile failed: " PUBLIC_LOG_D32, profile);
874     }
875     HEVCLevel level = FFMpegConverter::ConvertFFMpegToOHHEVCLevel(static_cast<int>(parse.level));
876     if (level != HEVCLevel::HEVC_LEVEL_UNKNOW) {
877         format.Set<Tag::VIDEO_H265_LEVEL>(level);
878         format.Set<Tag::MEDIA_LEVEL>(level);
879     } else {
880         MEDIA_LOG_D("Parse hevc level failed: " PUBLIC_LOG_D32, level);
881     }
882     auto FileType = GetFileTypeByName(avFormatContext);
883     if (FileType == FileType::MPEGTS ||
884         FileType == FileType::FLV) {
885         format.Set<Tag::VIDEO_WIDTH>(static_cast<uint32_t>(parse.picWidInLumaSamples));
886         format.Set<Tag::VIDEO_HEIGHT>(static_cast<uint32_t>(parse.picHetInLumaSamples));
887     }
888 }
889 
ParseInfoFromMetadata(const AVDictionary * metadata,const TagType key,Meta & format)890 void FFmpegFormatHelper::ParseInfoFromMetadata(const AVDictionary* metadata, const TagType key, Meta &format)
891 {
892     MEDIA_LOG_D("Parse " PUBLIC_LOG_S, key.c_str());
893     AVDictionaryEntry *valPtr = nullptr;
894     bool parseFromMoov = false;
895     valPtr = av_dict_get(metadata, g_formatToString[key].c_str(), nullptr, AV_DICT_MATCH_CASE);
896     if (valPtr == nullptr) {
897         valPtr = av_dict_get(metadata, SwitchCase(std::string(key)).c_str(), nullptr, AV_DICT_MATCH_CASE);
898     }
899     if (valPtr == nullptr) {
900         valPtr = av_dict_get(metadata, ("moov_level_meta_key_" + std::string(key)).c_str(),
901             nullptr, AV_DICT_MATCH_CASE);
902         parseFromMoov = true;
903     }
904     if (valPtr == nullptr) {
905         MEDIA_LOG_D("Parse failed");
906         return;
907     }
908     if (parseFromMoov) {
909         if (strlen(valPtr->value) > VALUE_PREFIX_LEN) {
910             format.SetData(key, std::string(valPtr->value + VALUE_PREFIX_LEN));
911         }
912         return;
913     }
914     format.SetData(key, std::string(valPtr->value));
915     if (IsGBK(valPtr->value)) {
916         int inputLen = strlen(valPtr->value);
917         char* utf8Result = new char[MAX_VALUE_LEN + 1];
918         utf8Result[MAX_VALUE_LEN] = '\0';
919         int resultLen = ConvertGBK2UTF8(valPtr->value, inputLen, utf8Result, MAX_VALUE_LEN);
920         if (resultLen >= 0) { // In some case, utf8Result will contains extra characters, extract the valid parts
921             char *subStr = new char[resultLen + 1];
922             int ret = memcpy_s(subStr, resultLen, utf8Result, resultLen);
923             if (ret == EOK) {
924                 subStr[resultLen] = '\0';
925                 format.SetData(key, std::string(subStr));
926             }
927             delete[] subStr;
928         }
929         delete[] utf8Result;
930     }
931 }
932 } // namespace Ffmpeg
933 } // namespace Plugins
934 } // namespace Media
935 } // namespace OHOS