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