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