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 #define HST_LOG_TAG "AACAudioConfigParser"
17
18 #include "aac_audio_config_parser.h"
19 #include "bit_reader.h"
20 #include "foundation/log.h"
21
22 namespace OHOS {
23 namespace Media {
24 namespace Plugin {
25 namespace Ffmpeg {
AACAudioConfigParser(const uint8_t * audioConfig,size_t len)26 AACAudioConfigParser::AACAudioConfigParser(const uint8_t* audioConfig, size_t len)
27 : bitReader_(audioConfig, len), isConfigValid_(false)
28 {
29 }
30
ParseConfigs()31 bool AACAudioConfigParser::ParseConfigs()
32 {
33 isConfigValid_ = ParseObjectTypeFull();
34 isConfigValid_ = isConfigValid_ && ParseLevel();
35 isConfigValid_ = isConfigValid_ && ParseProfile();
36 if (!isConfigValid_) {
37 Reset();
38 MEDIA_LOG_E("ParseAudioObjectTypeFull failed");
39 }
40 return isConfigValid_;
41 }
42
GetLevel() const43 uint32_t AACAudioConfigParser::GetLevel() const
44 {
45 return audioConfig_.level;
46 }
47
GetProfile() const48 AudioAacProfile AACAudioConfigParser::GetProfile() const
49 {
50 return audioConfig_.profile;
51 }
52
Reset()53 void AACAudioConfigParser::Reset()
54 {
55 audioConfig_.audioObjectType = 0xFF; // 0xFF
56 audioConfig_.channelConfig = 0xFF; // 0xFF
57 audioConfig_.sampleRate = 0;
58 audioConfig_.level = 0;
59 audioConfig_.profile = AudioAacProfile::NONE;
60 }
61
ParseObjectType()62 bool AACAudioConfigParser::ParseObjectType()
63 {
64 uint8_t audioObjectType = 0;
65 if (!bitReader_.ReadBits(5, audioObjectType)) { // 5
66 return false;
67 }
68 if (audioObjectType == 31) { // 31
69 if (!bitReader_.ReadBits(6, audioObjectType)) { // 6
70 return false;
71 }
72 audioObjectType += 32; // 32
73 }
74 audioConfig_.audioObjectType = audioObjectType;
75 return true;
76 }
77
ParseSampleRate()78 bool AACAudioConfigParser::ParseSampleRate()
79 {
80 uint8_t sampleFreqIndex = 0;
81 uint32_t sampleRate = 0;
82 if (!bitReader_.ReadBits(4, sampleFreqIndex)) { // 4
83 return false;
84 }
85 if (sampleFreqIndex == 0xf) {
86 if (!bitReader_.ReadBits(24, sampleRate)) { // 24
87 return false;
88 }
89 } else {
90 const uint32_t sampleRates[] = {96000, 88200, 64000, 48000, 44100, 32000, 24000,
91 22050, 16000, 12000, 11025, 8000, 7350};
92 if (sampleFreqIndex < sizeof(sampleRates) / sizeof(uint32_t)) {
93 sampleRate = sampleRates[sampleFreqIndex];
94 } else {
95 return false;
96 }
97 }
98 audioConfig_.sampleRate = sampleRate;
99 return true;
100 }
101
ParseChannel()102 bool AACAudioConfigParser::ParseChannel()
103 {
104 return bitReader_.ReadBits(4, audioConfig_.channelConfig); // 4
105 }
106
107 /**
108 * object type, sample rate, channel need to be parsed in the following order.
109 * @return TRUE if parse successfully, False otherwise.
110 */
ParseObjectTypeFull()111 bool AACAudioConfigParser::ParseObjectTypeFull()
112 {
113 if (!ParseObjectType() || !ParseSampleRate() || !ParseChannel()) {
114 return false;
115 }
116 // 5 indicates SBR extension (i.e. HE-AAC), 29 indicates PS extension
117 if (audioConfig_.audioObjectType == 5 || audioConfig_.audioObjectType == 29) { // 5 29
118 return ParseSampleRate() && ParseObjectType();
119 }
120 return true;
121 }
122
123 /**
124 * Extract Number of single channel elements, channel pair elements, low frequency elements,
125 * independently switched coupling channel elements, and dependently switched coupling channel
126 * elements.
127 * Note: The 2 CCE types are ignored for now as they require us to actually
128 * parse the first frame, and they are rarely found in actual streams.
129 * @param sceCnt number of single channel elements
130 * @param cpeCnt number of channel pair elements
131 * @param lfeCnt number of low frequency elements
132 * @param indepCce number of independently switched coupling channel elements
133 * @param depCce number of dependently switched coupling channel elements
134 */
ExtractChannelElements(int & sceCnt,int & cpeCnt,int & lfeCnt,int & indepCce,int & depCce)135 bool AACAudioConfigParser::ExtractChannelElements(int& sceCnt, int& cpeCnt, int& lfeCnt, int& indepCce, int& depCce)
136 {
137 indepCce = 0;
138 depCce = 0;
139 switch (audioConfig_.channelConfig) {
140 case 0:
141 MEDIA_LOG_W("Found a stream with channel configuration in the "
142 "AudioSpecificConfig. Please file a bug with a link to the media if "
143 "possible.");
144 return false;
145 case 1: /* front center */
146 sceCnt = 1;
147 break;
148 case 2: // 2 front left and right
149 cpeCnt = 1;
150 break;
151 case 3: // 3 front left, right, and center
152 sceCnt = 1;
153 cpeCnt = 1;
154 break;
155 case 4: // 4 front left, right, and center; rear surround
156 sceCnt = 2; // 2
157 cpeCnt = 1;
158 break;
159 case 5: // 5 front left, right, and center; rear left and right surround
160 sceCnt = 1;
161 cpeCnt = 2; // 2
162 break;
163 case 6: // 6 front left, right, center and LFE; rear left and right surround
164 sceCnt = 1;
165 cpeCnt = 2; // 2
166 break;
167 case 7: // 7
168 case 12: // 12
169 case 14: // 14
170 /* front left, right, center and LFE; outside front left and right;
171 * rear left and right surround */
172 sceCnt = 1;
173 cpeCnt = 3; // 3
174 lfeCnt = 1;
175 break;
176 case 11: // 11
177 sceCnt = 2; // 2
178 cpeCnt = 2; // 2
179 lfeCnt = 1;
180 break;
181 default:
182 MEDIA_LOG_W("Unknown channel config in header: " PUBLIC_LOG_D32, audioConfig_.channelConfig);
183 return false;
184 }
185 return true;
186 }
187
188 /**
189 * Extract Processor and RAM Complexity Units (calculated and "reference" for single channel)
190 * @param refPcu
191 * @param refRcu
192 * @return
193 */
ExtractReferencePRCU(int & refPcu,int & refRcu)194 bool AACAudioConfigParser::ExtractReferencePRCU(int& refPcu, int& refRcu)
195 {
196 switch (audioConfig_.audioObjectType) {
197 case 0: /* NULL */
198 MEDIA_LOG_W("profile 0 is not a valid profile");
199 return false;
200 case 2: // 2, LC
201 refPcu = 3; // 3
202 refRcu = 3; // 3
203 break;
204 case 3: // 3, SSR
205 refPcu = 4; // 4
206 refRcu = 3; // 3
207 break;
208 case 4: // 4, LTP
209 refPcu = 4; // 4
210 refRcu = 4; // 4
211 break;
212 case 1: /* Main */
213 default:
214 /* Other than a couple of ER profiles, Main is the worst-case */
215 refPcu = 5; // 5
216 refRcu = 5; // 5
217 break;
218 }
219 return true;
220 }
221
222 /**
223 * calculate profile from channelcnt, pcu, and rcu.
224 * @param channelCnt number of channels
225 * @param pcu processor complexity unit
226 * @param rcu ram complexity unit
227 * @return profile calculated result, true or false.
228 */
CalculateProfile(int channelCnt,int pcu,int rcu)229 bool AACAudioConfigParser::CalculateProfile(int channelCnt, int pcu, int rcu)
230 {
231 #define AAC_PROFILE_VALUE_RANGE(maxChannelCnt, maxSampleRate, maxPcu, maxRcu) \
232 channelCnt <= (maxChannelCnt) && audioConfig_.sampleRate <= (maxSampleRate) && pcu <= (maxPcu) && rcu <= (maxRcu)
233
234 int ret = -1; // -1
235 if (audioConfig_.audioObjectType == 2) { // 2
236 /* AAC LC => return the level as per the 'AAC Profile' */
237 if (AAC_PROFILE_VALUE_RANGE(2, 24000, 3, 5)) { // 2 24000 3 5
238 ret = 1; // 1
239 } else if (AAC_PROFILE_VALUE_RANGE(2, 48000, 6, 5)) { // 2 48000 6 5
240 ret = 2; // 2
241 } else if (AAC_PROFILE_VALUE_RANGE(5, 48000, 19, 15)) { // 5 48000 19 15
242 ret = 4; // 4
243 } else if (AAC_PROFILE_VALUE_RANGE(5, 96000, 38, 15)) { // 5 96000 38 15
244 ret = 5; // 5
245 } else if (AAC_PROFILE_VALUE_RANGE(7, 48000, 25, 19)) { // 7 48000 25 19
246 ret = 6; // 6
247 } else if (AAC_PROFILE_VALUE_RANGE(7, 96000, 50, 19)) { // 7 96000 50 19
248 ret = 7; // 7
249 }
250 } else {
251 /* Return the level as per the 'Main Profile' */
252 if (pcu < 40 && rcu < 20) { // 40 20
253 ret = 1;
254 } else if (pcu < 80 && rcu < 64) { // 80 64
255 ret = 2; // 2
256 } else if (pcu < 160 && rcu < 128) { // 160 128
257 ret = 3; // 3
258 } else if (pcu < 320 && rcu < 256) { // 320 256
259 ret = 4; // 4
260 }
261 }
262 MEDIA_LOG_W("determined level: profile=" PUBLIC_LOG_U8 ", sampleRate=" PUBLIC_LOG_U32 ", channel_config="
263 PUBLIC_LOG_U8 ", pcu=" PUBLIC_LOG_D32 ",rcu=" PUBLIC_LOG_D32,
264 audioConfig_.audioObjectType, audioConfig_.sampleRate, audioConfig_.channelConfig, pcu, rcu);
265 audioConfig_.level = static_cast<uint32_t>(ret);
266 return ret != -1;
267 }
268
269 /**
270 * Determines the level of a stream as defined in ISO/IEC 14496-3. For AAC LC
271 * streams, the constraints from the AAC audio profile are applied. For AAC
272 * Main, LTP, SSR and others, the Main profile is used.
273 *
274 * The @audioConfig parameter follows the following format, starting from the
275 * most significant bit of the first byte:
276 *
277 * * Bit 0:4 contains the AudioObjectType (if this is 0x5, then the
278 * real AudioObjectType is carried after the rate and channel data)
279 * * Bit 5:8 contains the sample frequency index (if this is 0xf, then the
280 * next 24 bits define the actual sample frequency, and subsequent
281 * fields are appropriately shifted).
282 * * Bit 9:12 contains the channel configuration
283 *
284 * Returns: TRUE if level can be set, FALSE otherwise.
285 */
ParseLevel()286 bool AACAudioConfigParser::ParseLevel()
287 {
288 int sceCnt = 0;
289 int cpeCnt = 0;
290 int lfeCnt = 0;
291 int indepCce = 0;
292 int depCce = 0;
293 if (!ExtractChannelElements(sceCnt, cpeCnt, lfeCnt, indepCce, depCce)) {
294 return false;
295 }
296 int refPcu = 0;
297 int refRcu = 0;
298 if (!ExtractReferencePRCU(refPcu, refRcu)) {
299 return false;
300 }
301 int tmp = (static_cast<float>(audioConfig_.sampleRate) / 48000) * refPcu; // 48000
302 int pcu = tmp * ((2 * cpeCnt) + sceCnt + lfeCnt + indepCce + (0.3 * depCce)); // 48000 2 0.3
303 int rcu = (static_cast<float>(refRcu)) * (sceCnt + (0.5 * lfeCnt) + (0.5 * indepCce) + (0.4 * depCce)); // 0.5 0.4
304 if (cpeCnt < 2) { // 2
305 rcu += (refRcu + (refRcu - 1)) * cpeCnt;
306 } else {
307 rcu += (refRcu + (refRcu - 1) * ((2 * cpeCnt) - 1)); // 2
308 }
309 int channelCnt = sceCnt + (2 * cpeCnt); // 2
310 return CalculateProfile(channelCnt, pcu, rcu);
311 }
312
ParseProfile()313 bool AACAudioConfigParser::ParseProfile()
314 {
315 bool ret = true;
316 switch (audioConfig_.audioObjectType) {
317 case 1:
318 audioConfig_.profile = AudioAacProfile::MAIN;
319 break;
320 case 2: // 2
321 audioConfig_.profile = AudioAacProfile::LC;
322 break;
323 case 3: // 3
324 audioConfig_.profile = AudioAacProfile::SSR;
325 break;
326 case 4: // 4
327 audioConfig_.profile = AudioAacProfile::LTP;
328 break;
329 default:
330 audioConfig_.profile = AudioAacProfile::NONE;
331 MEDIA_LOG_W("ParseProfile failed due to invalid profile index: " PUBLIC_LOG_U8,
332 audioConfig_.audioObjectType);
333 break;
334 }
335 return ret;
336 }
337 } // namespace Ffmpeg
338 } // namespace Plugin
339 } // namespace Media
340 } // namespace OHOS
341