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