1 /*
2 * Copyright (c) 2021-2021 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 #include "ffmpeg_track_meta.h"
17 #include "foundation/log.h"
18 #include "utils/constants.h"
19 #include "utils/type_define.h"
20 #include "plugins/ffmpeg_adapter/utils/aac_audio_config_parser.h"
21 #include "plugins/ffmpeg_adapter/utils/ffmpeg_utils.h"
22 #ifdef VIDEO_SUPPORT
23 #include "plugins/ffmpeg_adapter/utils/avc_config_data_parser.h"
24 #endif
25
26 namespace OHOS {
27 namespace Media {
28 namespace Plugin {
29 namespace Ffmpeg {
30 namespace {
31 using ConvertFunc = void (*)(const AVStream& avStream, const std::shared_ptr<AVCodecContext>& context, TagMap& meta);
32
33 struct StreamConvertor {
34 AVCodecID codecId;
35 ConvertFunc convertor;
36 };
37
38 StreamConvertor g_streamConvertors[] = {{AV_CODEC_ID_PCM_S16LE, ConvertRawAudioStreamToMetaInfo},
39 {AV_CODEC_ID_PCM_S16BE, ConvertRawAudioStreamToMetaInfo},
40 {AV_CODEC_ID_PCM_U16LE, ConvertRawAudioStreamToMetaInfo},
41 {AV_CODEC_ID_PCM_U16BE, ConvertRawAudioStreamToMetaInfo},
42 {AV_CODEC_ID_PCM_S8, ConvertRawAudioStreamToMetaInfo},
43 {AV_CODEC_ID_PCM_U8, ConvertRawAudioStreamToMetaInfo},
44 {AV_CODEC_ID_MP1, ConvertMP1StreamToMetaInfo},
45 {AV_CODEC_ID_MP2, ConvertMP2StreamToMetaInfo},
46 {AV_CODEC_ID_MP3, ConvertMP3StreamToMetaInfo},
47 {AV_CODEC_ID_AAC, ConvertAACStreamToMetaInfo},
48 {AV_CODEC_ID_AAC_LATM, ConvertAACLatmStreamToMetaInfo},
49 #ifdef VIDEO_SUPPORT
50 {AV_CODEC_ID_H264, ConvertAVCStreamToMetaInfo}
51 #endif
52 };
53
IsPcmStream(const AVStream & avStream)54 bool IsPcmStream(const AVStream& avStream)
55 {
56 auto codecId = avStream.codecpar->codec_id;
57 return codecId == AV_CODEC_ID_PCM_S16LE || codecId == AV_CODEC_ID_PCM_S16BE || codecId == AV_CODEC_ID_PCM_U16LE ||
58 codecId == AV_CODEC_ID_PCM_U16BE || codecId == AV_CODEC_ID_PCM_S8 || codecId == AV_CODEC_ID_PCM_U8;
59 }
60
ConvertCommonAudioStreamToMetaInfo(const AVStream & avStream,const std::shared_ptr<AVCodecContext> & context,TagMap & meta)61 void ConvertCommonAudioStreamToMetaInfo(const AVStream& avStream, const std::shared_ptr<AVCodecContext>& context,
62 TagMap& meta)
63 {
64 meta.insert({Tag::TRACK_ID, static_cast<uint32_t>(avStream.index)});
65 if (context->channels != -1) {
66 meta.insert({Tag::AUDIO_SAMPLE_RATE, static_cast<uint32_t>(context->sample_rate)});
67 meta.insert({Tag::AUDIO_CHANNELS, static_cast<uint32_t>(context->channels)});
68 meta.insert(
69 {Tag::AUDIO_CHANNEL_LAYOUT, ConvertChannelLayoutFromFFmpeg(context->channels, context->channel_layout)});
70 // ffmpeg defaults to 1024 samples per frame for planar PCM in each buffer (one for each channel).
71 uint32_t samplesPerFrame = 1024;
72 if (!IsPcmStream(avStream)) {
73 samplesPerFrame = static_cast<uint32_t>(context->frame_size);
74 }
75 meta.insert({Tag::AUDIO_SAMPLE_PER_FRAME, samplesPerFrame});
76 meta.insert({Tag::AUDIO_SAMPLE_FORMAT, Trans2Format(context->sample_fmt)});
77 meta.insert({Tag::MEDIA_BITRATE, static_cast<int64_t>(context->bit_rate)});
78 }
79 }
80 } // namespace
81
ConvertRawAudioStreamToMetaInfo(const AVStream & avStream,const std::shared_ptr<AVCodecContext> & context,TagMap & meta)82 void ConvertRawAudioStreamToMetaInfo(const AVStream& avStream, const std::shared_ptr<AVCodecContext>& context,
83 TagMap& meta)
84 {
85 meta.insert({Tag::MIME, std::string(MEDIA_MIME_AUDIO_RAW)});
86 ConvertCommonAudioStreamToMetaInfo(avStream, context, meta);
87 }
88
ConvertMP1StreamToMetaInfo(const AVStream & avStream,const std::shared_ptr<AVCodecContext> & context,TagMap & meta)89 void ConvertMP1StreamToMetaInfo(const AVStream& avStream, const std::shared_ptr<AVCodecContext>& context, TagMap& meta)
90 {
91 meta.insert({Tag::MIME, std::string(MEDIA_MIME_AUDIO_MPEG)});
92 ConvertCommonAudioStreamToMetaInfo(avStream, context, meta);
93 meta.insert({Tag::AUDIO_MPEG_VERSION, static_cast<uint32_t>(1)});
94 meta.insert({Tag::AUDIO_MPEG_LAYER, static_cast<uint32_t>(1)});
95 }
96
ConvertMP2StreamToMetaInfo(const AVStream & avStream,const std::shared_ptr<AVCodecContext> & context,TagMap & meta)97 void ConvertMP2StreamToMetaInfo(const AVStream& avStream, const std::shared_ptr<AVCodecContext>& context, TagMap& meta)
98 {
99 meta.insert({Tag::MIME, std::string(MEDIA_MIME_AUDIO_MPEG)});
100 ConvertCommonAudioStreamToMetaInfo(avStream, context, meta);
101 meta.insert({Tag::AUDIO_MPEG_VERSION, static_cast<uint32_t>(1)});
102 meta.insert({Tag::AUDIO_MPEG_LAYER, static_cast<uint32_t>(2)}); // 2
103 }
104
ConvertMP3StreamToMetaInfo(const AVStream & avStream,const std::shared_ptr<AVCodecContext> & context,TagMap & meta)105 void ConvertMP3StreamToMetaInfo(const AVStream& avStream, const std::shared_ptr<AVCodecContext>& context, TagMap& meta)
106 {
107 meta.insert({Tag::MIME, std::string(MEDIA_MIME_AUDIO_MPEG)});
108 ConvertCommonAudioStreamToMetaInfo(avStream, context, meta);
109 meta.insert({Tag::AUDIO_MPEG_VERSION, static_cast<uint32_t>(1)});
110 meta.insert({Tag::AUDIO_MPEG_LAYER, static_cast<uint32_t>(3)}); // 3
111 }
112
ConvertAACStreamToMetaInfo(const AVStream & avStream,const std::shared_ptr<AVCodecContext> & context,TagMap & meta)113 void ConvertAACStreamToMetaInfo(const AVStream& avStream, const std::shared_ptr<AVCodecContext>& context, TagMap& meta)
114 {
115 meta.insert({Tag::MIME, std::string(MEDIA_MIME_AUDIO_AAC)});
116 ConvertCommonAudioStreamToMetaInfo(avStream, context, meta);
117 meta.insert({Tag::AUDIO_MPEG_VERSION, static_cast<uint32_t>(4)}); // 4
118 meta.insert({Tag::AUDIO_AAC_PROFILE, AudioAacProfile::LC});
119 if (context->extradata_size > 0) {
120 std::vector<uint8_t> codecConfig;
121 codecConfig.assign(context->extradata, context->extradata + context->extradata_size);
122 meta.insert({Tag::MEDIA_CODEC_CONFIG, std::move(codecConfig)});
123 AACAudioConfigParser parser(context->extradata, context->extradata_size);
124 if (!parser.ParseConfigs()) {
125 return;
126 }
127 meta.insert({Tag::AUDIO_AAC_LEVEL, parser.GetLevel()});
128 auto profile = parser.GetProfile();
129 if (profile != AudioAacProfile::NONE) {
130 meta.insert({Tag::AUDIO_AAC_PROFILE, profile});
131 }
132 } else {
133 meta.insert({Tag::AUDIO_AAC_STREAM_FORMAT, AudioAacStreamFormat::MP4ADTS});
134 }
135 }
136
ConvertAACLatmStreamToMetaInfo(const AVStream & avStream,const std::shared_ptr<AVCodecContext> & context,TagMap & meta)137 void ConvertAACLatmStreamToMetaInfo(const AVStream& avStream, const std::shared_ptr<AVCodecContext>& context,
138 TagMap& meta)
139 {
140 meta.insert({Tag::MIME, std::string(MEDIA_MIME_AUDIO_AAC_LATM)});
141 meta.insert({Tag::TRACK_ID, static_cast<uint32_t>(avStream.index)});
142 if (context->channels != -1) {
143 meta.insert({Tag::AUDIO_SAMPLE_RATE, static_cast<uint32_t>(context->sample_rate)});
144 meta.insert({Tag::AUDIO_CHANNELS, static_cast<uint32_t>(context->channels)});
145 meta.insert({Tag::AUDIO_SAMPLE_FORMAT, Trans2Format(context->sample_fmt)});
146 meta.insert(
147 {Tag::AUDIO_CHANNEL_LAYOUT, ConvertChannelLayoutFromFFmpeg(context->channels, context->channel_layout)});
148 meta.insert({Tag::AUDIO_SAMPLE_PER_FRAME, static_cast<uint32_t>(context->frame_size)});
149 meta.insert({Tag::MEDIA_BITRATE, static_cast<int64_t>(context->bit_rate)});
150 }
151 meta.insert({Tag::AUDIO_MPEG_VERSION, static_cast<uint32_t>(4)}); // 4
152 meta.insert({Tag::AUDIO_AAC_STREAM_FORMAT, AudioAacStreamFormat::MP4LOAS});
153 }
154
155 #ifdef VIDEO_SUPPORT
ConvertAVCStreamToMetaInfo(const AVStream & avStream,const std::shared_ptr<AVCodecContext> & context,TagMap & meta)156 void ConvertAVCStreamToMetaInfo(const AVStream& avStream, const std::shared_ptr<AVCodecContext>& context, TagMap& meta)
157 {
158 meta.insert({Tag::MIME, std::string(MEDIA_MIME_VIDEO_AVC)});
159 meta.insert({Tag::TRACK_ID, static_cast<uint32_t>(avStream.index)});
160 meta.insert({Tag::MEDIA_BITRATE, context->bit_rate});
161 meta.insert({Tag::VIDEO_WIDTH, static_cast<uint32_t>(context->width)});
162 meta.insert({Tag::VIDEO_HEIGHT, static_cast<uint32_t>(context->height)});
163 if (context->extradata_size > 0) {
164 AVCConfigDataParser parser(context->extradata, context->extradata_size);
165 if (!parser.ParseConfigData()) {
166 return;
167 }
168 std::shared_ptr<uint8_t> cfgData = nullptr;
169 size_t cfgDataSize = 0;
170 if (parser.GetNewConfigData(cfgData, cfgDataSize) && (cfgData != nullptr) && (cfgDataSize != 0)) {
171 std::vector<uint8_t> codecConfig;
172 codecConfig.assign(cfgData.get(), cfgData.get() + cfgDataSize);
173 meta.insert({Tag::MEDIA_CODEC_CONFIG, std::move(codecConfig)});
174 }
175 }
176 }
177 #endif
178
ConvertAVStreamToMetaInfo(const AVStream & avStream,const std::shared_ptr<AVCodecContext> & context,TagMap & meta)179 void ConvertAVStreamToMetaInfo(const AVStream& avStream, const std::shared_ptr<AVCodecContext>& context, TagMap& meta)
180 {
181 meta.clear();
182 auto codecId = avStream.codecpar->codec_id;
183 for (auto& streamConvertor : g_streamConvertors) {
184 if (streamConvertor.codecId == codecId) {
185 streamConvertor.convertor(avStream, context, meta);
186 return;
187 }
188 }
189 MEDIA_LOG_E("unsupported codec id: %" PUBLIC_LOG "d", codecId);
190 }
191 } // namespace Ffmpeg
192 } // namespace Plugin
193 } // namespace Media
194 } // namespace OHOS
195