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