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_utils.h"
17
18 #include <algorithm>
19
20 #include "foundation/log.h"
21 #include "libavutil/channel_layout.h"
22 #include "plugin/common/plugin_audio_tags.h"
23 #include "plugin/common/plugin_time.h"
24 #include "utils/utils.h"
25
26 namespace OHOS {
27 namespace Media {
28 namespace Plugin {
29 namespace Ffmpeg {
30 // Internal definitions
31 namespace {
32 // Histreamer channel layout to ffmpeg channel layout
33 std::map<AudioChannelLayout, uint64_t> g_toFFMPEGChannelLayout = {
34 {AudioChannelLayout::MONO, AV_CH_LAYOUT_MONO},
35 {AudioChannelLayout::STEREO, AV_CH_LAYOUT_STEREO},
36 {AudioChannelLayout::CH_2POINT1, AV_CH_LAYOUT_2POINT1},
37 {AudioChannelLayout::CH_2_1, AV_CH_LAYOUT_2_1},
38 {AudioChannelLayout::SURROUND, AV_CH_LAYOUT_SURROUND},
39 {AudioChannelLayout::CH_3POINT1, AV_CH_LAYOUT_3POINT1},
40 {AudioChannelLayout::CH_4POINT0, AV_CH_LAYOUT_4POINT0},
41 {AudioChannelLayout::CH_4POINT1, AV_CH_LAYOUT_4POINT1},
42 {AudioChannelLayout::CH_2_2, AV_CH_LAYOUT_2_2},
43 {AudioChannelLayout::QUAD, AV_CH_LAYOUT_QUAD},
44 {AudioChannelLayout::CH_5POINT0, AV_CH_LAYOUT_5POINT0},
45 {AudioChannelLayout::CH_5POINT1, AV_CH_LAYOUT_5POINT1},
46 {AudioChannelLayout::CH_5POINT0_BACK, AV_CH_LAYOUT_5POINT0_BACK},
47 {AudioChannelLayout::CH_5POINT1_BACK, AV_CH_LAYOUT_5POINT1_BACK},
48 {AudioChannelLayout::CH_6POINT0, AV_CH_LAYOUT_6POINT0},
49 {AudioChannelLayout::CH_6POINT0_FRONT, AV_CH_LAYOUT_6POINT0_FRONT},
50 {AudioChannelLayout::HEXAGONAL, AV_CH_LAYOUT_HEXAGONAL},
51 {AudioChannelLayout::CH_6POINT1, AV_CH_LAYOUT_6POINT1},
52 {AudioChannelLayout::CH_6POINT1_BACK, AV_CH_LAYOUT_6POINT1_BACK},
53 {AudioChannelLayout::CH_6POINT1_FRONT, AV_CH_LAYOUT_6POINT1_FRONT},
54 {AudioChannelLayout::CH_7POINT0, AV_CH_LAYOUT_7POINT0},
55 {AudioChannelLayout::CH_7POINT0_FRONT, AV_CH_LAYOUT_7POINT0_FRONT},
56 {AudioChannelLayout::CH_7POINT1, AV_CH_LAYOUT_7POINT1},
57 {AudioChannelLayout::CH_7POINT1_WIDE, AV_CH_LAYOUT_7POINT1_WIDE},
58 {AudioChannelLayout::CH_7POINT1_WIDE_BACK, AV_CH_LAYOUT_7POINT1_WIDE_BACK},
59 {AudioChannelLayout::OCTAGONAL, AV_CH_LAYOUT_OCTAGONAL},
60 {AudioChannelLayout::HEXADECAGONAL, AV_CH_LAYOUT_HEXADECAGONAL},
61 {AudioChannelLayout::STEREO_DOWNMIX, AV_CH_LAYOUT_STEREO_DOWNMIX},
62 };
63
64 // ffmpeg channel layout to histreamer channel layout
65 std::map<uint64_t, AudioChannelMasks> g_fromFFMPEGChannelLayout = {
66 {AV_CH_FRONT_LEFT, AudioChannelMasks::FRONT_LEFT},
67 {AV_CH_FRONT_RIGHT, AudioChannelMasks::FRONT_RIGHT},
68 {AV_CH_FRONT_CENTER, AudioChannelMasks::FRONT_CENTER},
69 {AV_CH_LOW_FREQUENCY, AudioChannelMasks::LOW_FREQUENCY},
70 {AV_CH_BACK_LEFT, AudioChannelMasks::BACK_LEFT},
71 {AV_CH_BACK_RIGHT, AudioChannelMasks::BACK_RIGHT},
72 {AV_CH_FRONT_LEFT_OF_CENTER, AudioChannelMasks::FRONT_LEFT_OF_CENTER},
73 {AV_CH_FRONT_RIGHT_OF_CENTER, AudioChannelMasks::FRONT_RIGHT_OF_CENTER},
74 {AV_CH_BACK_CENTER, AudioChannelMasks::BACK_CENTER},
75 {AV_CH_SIDE_LEFT, AudioChannelMasks::SIDE_LEFT},
76 {AV_CH_SIDE_RIGHT, AudioChannelMasks::SIDE_RIGHT},
77 {AV_CH_TOP_CENTER, AudioChannelMasks::TOP_CENTER},
78 {AV_CH_TOP_FRONT_LEFT, AudioChannelMasks::TOP_FRONT_LEFT},
79 {AV_CH_TOP_FRONT_CENTER, AudioChannelMasks::TOP_FRONT_CENTER},
80 {AV_CH_TOP_FRONT_RIGHT, AudioChannelMasks::TOP_FRONT_RIGHT},
81 {AV_CH_TOP_BACK_LEFT, AudioChannelMasks::TOP_BACK_LEFT},
82 {AV_CH_TOP_BACK_CENTER, AudioChannelMasks::TOP_BACK_CENTER},
83 {AV_CH_TOP_BACK_RIGHT, AudioChannelMasks::TOP_BACK_RIGHT},
84 {AV_CH_STEREO_LEFT, AudioChannelMasks::STEREO_LEFT},
85 {AV_CH_STEREO_RIGHT, AudioChannelMasks::STEREO_RIGHT},
86 };
87 const std::map<std::string, Tag> g_tagMap = {
88 {"title", Tag::MEDIA_TITLE},
89 {"artist", Tag::MEDIA_ARTIST},
90 {"lyricist", Tag::MEDIA_LYRICIST},
91 {"album", Tag::MEDIA_ALBUM},
92 {"album-artist", Tag::MEDIA_ALBUM_ARTIST},
93 {"date", Tag::MEDIA_DATE},
94 {"comment", Tag::MEDIA_COMMENT},
95 {"genre", Tag::MEDIA_GENRE},
96 {"copyright", Tag::MEDIA_COPYRIGHT},
97 {"language", Tag::MEDIA_LANGUAGE},
98 {"description", Tag::MEDIA_DESCRIPTION},
99 {"lyrics", Tag::MEDIA_LYRICS},
100 };
101 const std::vector<std::pair<AudioAacProfile, int32_t>> g_AacProfileMap = {
102 {AudioAacProfile::MAIN, FF_PROFILE_AAC_MAIN},
103 {AudioAacProfile::LC, FF_PROFILE_AAC_LOW},
104 {AudioAacProfile::SSR, FF_PROFILE_AAC_SSR},
105 {AudioAacProfile::LTP, FF_PROFILE_AAC_LTP},
106 {AudioAacProfile::HE, FF_PROFILE_AAC_HE},
107 {AudioAacProfile::HE_PS, FF_PROFILE_AAC_HE_V2},
108 {AudioAacProfile::LD, FF_PROFILE_AAC_LD},
109 {AudioAacProfile::ELD, FF_PROFILE_AAC_ELD},
110 };
111 } // namespace
112
AVStrError(int errnum)113 std::string AVStrError(int errnum)
114 {
115 char errbuf[AV_ERROR_MAX_STRING_SIZE] = {0};
116 av_strerror(errnum, errbuf, AV_ERROR_MAX_STRING_SIZE);
117 return std::string(errbuf);
118 }
119
ConvertTimeFromFFmpeg(int64_t pts,AVRational base)120 uint64_t ConvertTimeFromFFmpeg(int64_t pts, AVRational base)
121 {
122 uint64_t out;
123 if (pts == AV_NOPTS_VALUE) {
124 out = static_cast<uint64_t>(-1);
125 } else {
126 AVRational bq = {1, HST_SECOND};
127 out = av_rescale_q(pts, base, bq);
128 }
129 return out;
130 }
131
ConvertTimeToFFmpeg(int64_t timestampUs,AVRational base)132 int64_t ConvertTimeToFFmpeg(int64_t timestampUs, AVRational base)
133 {
134 int64_t result;
135 if (base.num == 0) {
136 result = AV_NOPTS_VALUE;
137 } else {
138 AVRational bq = {1, HST_SECOND};
139 result = av_rescale_q(timestampUs, bq, base);
140 }
141 return result;
142 }
143
FillAVPicture(AVFrame * picture,uint8_t * ptr,enum AVPixelFormat pixFmt,int width,int height)144 int FillAVPicture(AVFrame* picture, uint8_t* ptr, enum AVPixelFormat pixFmt, int width, int height)
145 {
146 (void)picture;
147 (void)ptr;
148 (void)pixFmt;
149 (void)width;
150 (void)height;
151 return 0;
152 }
153
GetAVPictureSize(int pixFmt,int width,int height)154 int GetAVPictureSize(int pixFmt, int width, int height)
155 {
156 AVFrame dummy;
157 return FillAVPicture(&dummy, nullptr, static_cast<AVPixelFormat>(pixFmt), width, height);
158 }
159
RemoveDelimiter(const char * str,char delimiter)160 std::string RemoveDelimiter(const char* str, char delimiter)
161 {
162 std::string tmp(str);
163 RemoveDelimiter(delimiter, tmp);
164 return tmp;
165 }
166
RemoveDelimiter(char delimiter,std::string & str)167 void RemoveDelimiter(char delimiter, std::string& str)
168 {
169 for (auto it = std::find(str.begin(), str.end(), delimiter); it != str.end();) {
170 it = str.erase(it);
171 if (*it != delimiter) {
172 it = std::find(it, str.end(), delimiter);
173 }
174 }
175 }
176
ReplaceDelimiter(const std::string & delmiters,char newDelimiter,std::string & str)177 void ReplaceDelimiter(const std::string& delmiters, char newDelimiter, std::string& str)
178 {
179 for (auto it = str.begin(); it != str.end(); ++it) {
180 if (delmiters.find(newDelimiter) != std::string::npos) {
181 *it = newDelimiter;
182 }
183 }
184 }
185
SplitString(const char * str,char delimiter)186 std::vector<std::string> SplitString(const char* str, char delimiter)
187 {
188 std::vector<std::string> rtv;
189 if (str) {
190 SplitString(std::string(str), delimiter).swap(rtv);
191 }
192 return rtv;
193 }
194
SplitString(const std::string & str,char delimiter)195 std::vector<std::string> SplitString(const std::string& str, char delimiter)
196 {
197 if (str.empty()) {
198 return {};
199 }
200 std::vector<std::string> rtv;
201 std::string::size_type startPos = 0;
202 std::string::size_type endPos = str.find_first_of(delimiter, startPos);
203 while (startPos != endPos) {
204 rtv.emplace_back(str.substr(startPos, endPos - startPos));
205 if (endPos == std::string::npos) {
206 break;
207 }
208 startPos = endPos + 1;
209 endPos = str.find_first_of(delimiter, startPos);
210 }
211 return rtv;
212 }
213
Trans2Format(AVSampleFormat sampleFormat)214 AudioSampleFormat Trans2Format(AVSampleFormat sampleFormat)
215 {
216 switch (sampleFormat) {
217 case AV_SAMPLE_FMT_U8:
218 return AudioSampleFormat::U8;
219 case AV_SAMPLE_FMT_U8P:
220 return AudioSampleFormat::U8P;
221 case AV_SAMPLE_FMT_S16:
222 return AudioSampleFormat::S16;
223 case AV_SAMPLE_FMT_S16P:
224 return AudioSampleFormat::S16P;
225 case AV_SAMPLE_FMT_S32:
226 return AudioSampleFormat::S32;
227 case AV_SAMPLE_FMT_S32P:
228 return AudioSampleFormat::S32P;
229 case AV_SAMPLE_FMT_FLT:
230 return AudioSampleFormat::F32;
231 case AV_SAMPLE_FMT_FLTP:
232 return AudioSampleFormat::F32P;
233 case AV_SAMPLE_FMT_DBL:
234 return AudioSampleFormat::F64;
235 case AV_SAMPLE_FMT_DBLP:
236 return AudioSampleFormat::F64P;
237 default:
238 return AudioSampleFormat::S16;
239 }
240 }
241
Trans2FFmepgFormat(AudioSampleFormat sampleFormat)242 AVSampleFormat Trans2FFmepgFormat(AudioSampleFormat sampleFormat)
243 {
244 switch (sampleFormat) {
245 case AudioSampleFormat::U8:
246 return AVSampleFormat::AV_SAMPLE_FMT_U8;
247 case AudioSampleFormat::U8P:
248 return AVSampleFormat::AV_SAMPLE_FMT_U8P;
249 case AudioSampleFormat::S16:
250 return AVSampleFormat::AV_SAMPLE_FMT_S16;
251 case AudioSampleFormat::S16P:
252 return AVSampleFormat::AV_SAMPLE_FMT_S16P;
253 case AudioSampleFormat::S32:
254 return AVSampleFormat::AV_SAMPLE_FMT_S32;
255 case AudioSampleFormat::S32P:
256 return AVSampleFormat::AV_SAMPLE_FMT_S32P;
257 case AudioSampleFormat::F32:
258 return AVSampleFormat::AV_SAMPLE_FMT_FLT;
259 case AudioSampleFormat::F32P:
260 return AVSampleFormat::AV_SAMPLE_FMT_FLTP;
261 case AudioSampleFormat::F64:
262 return AVSampleFormat::AV_SAMPLE_FMT_DBL;
263 case AudioSampleFormat::F64P:
264 return AVSampleFormat::AV_SAMPLE_FMT_DBLP;
265 default:
266 return AV_SAMPLE_FMT_NONE;
267 }
268 }
269
ConvertChannelLayoutFromFFmpeg(int channels,uint64_t ffChannelLayout)270 AudioChannelLayout ConvertChannelLayoutFromFFmpeg(int channels, uint64_t ffChannelLayout)
271 {
272 uint64_t channelLayout = 0;
273 uint64_t mask = 1;
274 for (uint8_t bitPos = 0, channelNum = 0; (bitPos < 64) && (channelNum < channels); ++bitPos) { // 64
275 mask = 1ULL << bitPos;
276 if (!(mask & ffChannelLayout)) {
277 continue;
278 }
279 channelNum++;
280 auto it = g_fromFFMPEGChannelLayout.find(mask);
281 if (it != g_fromFFMPEGChannelLayout.end()) {
282 channelLayout |= static_cast<uint64_t>(it->second);
283 } else {
284 MEDIA_LOG_W("unsupported audio channel layout: %" PUBLIC_LOG PRIu64, mask);
285 }
286 }
287 auto ret = static_cast<AudioChannelLayout>(channelLayout);
288 if (ffChannelLayout == 0) {
289 if (channels == 1) {
290 ret = AudioChannelLayout::MONO;
291 }
292 if (channels == 2) { // 2
293 ret = AudioChannelLayout::STEREO;
294 }
295 }
296 return ret;
297 }
298
ConvertChannelLayoutToFFmpeg(AudioChannelLayout channelLayout)299 uint64_t ConvertChannelLayoutToFFmpeg(AudioChannelLayout channelLayout)
300 {
301 auto it = g_toFFMPEGChannelLayout.find(channelLayout);
302 if (it == g_toFFMPEGChannelLayout.end()) {
303 MEDIA_LOG_E("ConvertChannelLayoutToFFmpeg, unexpected audio channel layout: %" PUBLIC_LOG PRIu64,
304 OHOS::Media::to_underlying(channelLayout));
305 return 0;
306 }
307 return it->second;
308 }
FindAvMetaNameByTag(Tag tag,std::string & metaName)309 bool FindAvMetaNameByTag(Tag tag, std::string& metaName)
310 {
311 for (const auto& pair : g_tagMap) {
312 if (pair.second == tag) {
313 metaName = pair.first;
314 return true;
315 }
316 }
317 return false;
318 }
FindTagByAvMetaName(const std::string & metaName,Tag & tag)319 bool FindTagByAvMetaName(const std::string& metaName, Tag& tag)
320 {
321 auto ite = g_tagMap.find(metaName);
322 if (ite == std::end(g_tagMap)) {
323 return false;
324 }
325 tag = ite->second;
326 return true;
327 }
ConvAacProfileFromFfmpeg(int32_t ffmpegProfile)328 AudioAacProfile ConvAacProfileFromFfmpeg (int32_t ffmpegProfile)
329 {
330 auto ite = std::find_if(g_AacProfileMap.begin(), g_AacProfileMap.end(),
331 [&] (const std::pair<AudioAacProfile, int32_t>& tmp) -> bool {
332 return tmp.second == ffmpegProfile;
333 });
334 return ite == g_AacProfileMap.end() ? AudioAacProfile::NONE : ite->first;
335 }
ConvAacProfileToFfmpeg(AudioAacProfile profile)336 int32_t ConvAacProfileToFfmpeg (AudioAacProfile profile)
337 {
338 auto ite = std::find_if(g_AacProfileMap.begin(), g_AacProfileMap.end(),
339 [&] (const std::pair<AudioAacProfile, int32_t>& tmp) -> bool {
340 return tmp.first == profile;
341 });
342 return ite == g_AacProfileMap.end() ? FF_PROFILE_UNKNOWN : ite->second;
343 }
344 } // namespace Ffmpeg
345 } // namespace Plugin
346 } // namespace Media
347 } // namespace OHOS
348