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