• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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