| /* ----------------------------------------------------------------------------- |
| Software License for The Fraunhofer FDK AAC Codec Library for Android |
| |
| © Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten |
| Forschung e.V. All rights reserved. |
| |
| 1. INTRODUCTION |
| The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software |
| that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding |
| scheme for digital audio. This FDK AAC Codec software is intended to be used on |
| a wide variety of Android devices. |
| |
| AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient |
| general perceptual audio codecs. AAC-ELD is considered the best-performing |
| full-bandwidth communications codec by independent studies and is widely |
| deployed. AAC has been standardized by ISO and IEC as part of the MPEG |
| specifications. |
| |
| Patent licenses for necessary patent claims for the FDK AAC Codec (including |
| those of Fraunhofer) may be obtained through Via Licensing |
| (www.vialicensing.com) or through the respective patent owners individually for |
| the purpose of encoding or decoding bit streams in products that are compliant |
| with the ISO/IEC MPEG audio standards. Please note that most manufacturers of |
| Android devices already license these patent claims through Via Licensing or |
| directly from the patent owners, and therefore FDK AAC Codec software may |
| already be covered under those patent licenses when it is used for those |
| licensed purposes only. |
| |
| Commercially-licensed AAC software libraries, including floating-point versions |
| with enhanced sound quality, are also available from Fraunhofer. Users are |
| encouraged to check the Fraunhofer website for additional applications |
| information and documentation. |
| |
| 2. COPYRIGHT LICENSE |
| |
| Redistribution and use in source and binary forms, with or without modification, |
| are permitted without payment of copyright license fees provided that you |
| satisfy the following conditions: |
| |
| You must retain the complete text of this software license in redistributions of |
| the FDK AAC Codec or your modifications thereto in source code form. |
| |
| You must retain the complete text of this software license in the documentation |
| and/or other materials provided with redistributions of the FDK AAC Codec or |
| your modifications thereto in binary form. You must make available free of |
| charge copies of the complete source code of the FDK AAC Codec and your |
| modifications thereto to recipients of copies in binary form. |
| |
| The name of Fraunhofer may not be used to endorse or promote products derived |
| from this library without prior written permission. |
| |
| You may not charge copyright license fees for anyone to use, copy or distribute |
| the FDK AAC Codec software or your modifications thereto. |
| |
| Your modified versions of the FDK AAC Codec must carry prominent notices stating |
| that you changed the software and the date of any change. For modified versions |
| of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android" |
| must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK |
| AAC Codec Library for Android." |
| |
| 3. NO PATENT LICENSE |
| |
| NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without |
| limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE. |
| Fraunhofer provides no warranty of patent non-infringement with respect to this |
| software. |
| |
| You may use this FDK AAC Codec software or modifications thereto only for |
| purposes that are authorized by appropriate patent licenses. |
| |
| 4. DISCLAIMER |
| |
| This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright |
| holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, |
| including but not limited to the implied warranties of merchantability and |
| fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR |
| CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, |
| or consequential damages, including but not limited to procurement of substitute |
| goods or services; loss of use, data, or profits, or business interruption, |
| however caused and on any theory of liability, whether in contract, strict |
| liability, or tort (including negligence), arising in any way out of the use of |
| this software, even if advised of the possibility of such damage. |
| |
| 5. CONTACT INFORMATION |
| |
| Fraunhofer Institute for Integrated Circuits IIS |
| Attention: Audio and Multimedia Departments - FDK AAC LL |
| Am Wolfsmantel 33 |
| 91058 Erlangen, Germany |
| |
| www.iis.fraunhofer.de/amm |
| amm-info@iis.fraunhofer.de |
| ----------------------------------------------------------------------------- */ |
| |
| /******************* MPEG transport format decoder library ********************* |
| |
| Author(s): Daniel Homm |
| |
| Description: |
| |
| *******************************************************************************/ |
| |
| #include "tpdec_lib.h" |
| #include "tp_data.h" |
| |
| #include "FDK_crc.h" |
| |
| #include "common_fix.h" |
| |
| /** |
| * The following arrays provide the IDs of the consecutive elements for each |
| * channel configuration. Every channel_configuration has to be finalized with |
| * ID_NONE. |
| */ |
| static const MP4_ELEMENT_ID channel_configuration_0[] = {ID_NONE}; |
| static const MP4_ELEMENT_ID channel_configuration_1[] = {ID_SCE, ID_NONE}; |
| static const MP4_ELEMENT_ID channel_configuration_2[] = {ID_CPE, ID_NONE}; |
| static const MP4_ELEMENT_ID channel_configuration_3[] = {ID_SCE, ID_CPE, |
| ID_NONE}; |
| static const MP4_ELEMENT_ID channel_configuration_4[] = {ID_SCE, ID_CPE, ID_SCE, |
| ID_NONE}; |
| static const MP4_ELEMENT_ID channel_configuration_5[] = {ID_SCE, ID_CPE, ID_CPE, |
| ID_NONE}; |
| static const MP4_ELEMENT_ID channel_configuration_6[] = {ID_SCE, ID_CPE, ID_CPE, |
| ID_LFE, ID_NONE}; |
| static const MP4_ELEMENT_ID channel_configuration_7[] = { |
| ID_SCE, ID_CPE, ID_CPE, ID_CPE, ID_LFE, ID_NONE}; |
| static const MP4_ELEMENT_ID channel_configuration_8[] = { |
| ID_NONE}; /* reserved */ |
| static const MP4_ELEMENT_ID channel_configuration_9[] = { |
| ID_NONE}; /* reserved */ |
| static const MP4_ELEMENT_ID channel_configuration_10[] = { |
| ID_NONE}; /* reserved */ |
| static const MP4_ELEMENT_ID channel_configuration_11[] = { |
| ID_SCE, ID_CPE, ID_CPE, ID_SCE, ID_LFE, ID_NONE}; |
| static const MP4_ELEMENT_ID channel_configuration_12[] = { |
| ID_SCE, ID_CPE, ID_CPE, ID_CPE, ID_LFE, ID_NONE}; |
| static const MP4_ELEMENT_ID channel_configuration_13[] = { |
| ID_SCE, ID_CPE, ID_CPE, ID_CPE, ID_CPE, ID_SCE, ID_LFE, ID_LFE, ID_SCE, |
| ID_CPE, ID_CPE, ID_SCE, ID_CPE, ID_SCE, ID_SCE, ID_CPE, ID_NONE}; |
| static const MP4_ELEMENT_ID channel_configuration_14[] = { |
| ID_SCE, ID_CPE, ID_CPE, ID_LAST, ID_CPE, ID_NONE}; |
| |
| static const MP4_ELEMENT_ID *channel_configuration_array[] = { |
| channel_configuration_0, channel_configuration_1, |
| channel_configuration_2, channel_configuration_3, |
| channel_configuration_4, channel_configuration_5, |
| channel_configuration_6, channel_configuration_7, |
| channel_configuration_8, channel_configuration_9, |
| channel_configuration_10, channel_configuration_11, |
| channel_configuration_12, channel_configuration_13, |
| channel_configuration_14}; |
| |
| #define TP_USAC_MAX_CHANNEL_CONFIGURATION_INDEX (13) |
| #define SC_CHANNEL_CONFIG_TAB_SIZE (TP_USAC_MAX_CHANNEL_CONFIGURATION_INDEX + 1) |
| |
| /* channel config structure used for sanity check */ |
| typedef struct { |
| SCHAR nCh; /* number of channels */ |
| SCHAR nSCE; /* number of SCE's */ |
| SCHAR nCPE; /* number of CPE's */ |
| SCHAR nLFE; /* number of LFE's */ |
| } SC_CHANNEL_CONFIG; |
| |
| static const SC_CHANNEL_CONFIG sc_chan_config_tab[SC_CHANNEL_CONFIG_TAB_SIZE] = |
| { |
| /* nCh, nSCE, nCPE, nLFE, cci */ |
| {0, 0, 0, 0}, /* 0 */ |
| {1, 1, 0, 0}, /* 1 */ |
| {2, 0, 1, 0}, /* 2 */ |
| {3, 1, 1, 0}, /* 3 */ |
| {4, 2, 1, 0}, /* 4 */ |
| {5, 1, 2, 0}, /* 5 */ |
| {6, 1, 2, 1}, /* 6 */ |
| {8, 1, 3, 1}, /* 7 */ |
| {2, 2, 0, 0}, /* 8 */ |
| {3, 1, 1, 0}, /* 9 */ |
| {4, 0, 2, 0}, /* 10 */ |
| {7, 2, 2, 1}, /* 11 */ |
| {8, 1, 3, 1}, /* 12 */ |
| {24, 6, 8, 2} /* 13 */ |
| }; |
| |
| void CProgramConfig_Reset(CProgramConfig *pPce) { pPce->elCounter = 0; } |
| |
| void CProgramConfig_Init(CProgramConfig *pPce) { |
| FDKmemclear(pPce, sizeof(CProgramConfig)); |
| pPce->SamplingFrequencyIndex = 0xf; |
| } |
| |
| int CProgramConfig_IsValid(const CProgramConfig *pPce) { |
| return ((pPce->isValid) ? 1 : 0); |
| } |
| |
| #define PCE_HEIGHT_EXT_SYNC (0xAC) |
| |
| /* |
| * Read the extension for height info. |
| * return 0 if successfull, |
| * -1 if the CRC failed, |
| * -2 if invalid HeightInfo. |
| */ |
| static int CProgramConfig_ReadHeightExt(CProgramConfig *pPce, |
| HANDLE_FDK_BITSTREAM bs, |
| int *const bytesAvailable, |
| const UINT alignmentAnchor) { |
| int err = 0; |
| FDK_CRCINFO crcInfo; /* CRC state info */ |
| INT crcReg; |
| FDKcrcInit(&crcInfo, 0x07, 0xFF, 8); |
| crcReg = FDKcrcStartReg(&crcInfo, bs, 0); |
| UINT startAnchor = FDKgetValidBits(bs); |
| |
| FDK_ASSERT(pPce != NULL); |
| FDK_ASSERT(bs != NULL); |
| FDK_ASSERT(bytesAvailable != NULL); |
| |
| if ((startAnchor >= 24) && (*bytesAvailable >= 3) && |
| (FDKreadBits(bs, 8) == PCE_HEIGHT_EXT_SYNC)) { |
| int i; |
| |
| for (i = 0; i < pPce->NumFrontChannelElements; i++) { |
| if ((pPce->FrontElementHeightInfo[i] = (UCHAR)FDKreadBits(bs, 2)) >= |
| PC_NUM_HEIGHT_LAYER) { |
| err = -2; /* height information is out of the valid range */ |
| } |
| } |
| for (i = 0; i < pPce->NumSideChannelElements; i++) { |
| if ((pPce->SideElementHeightInfo[i] = (UCHAR)FDKreadBits(bs, 2)) >= |
| PC_NUM_HEIGHT_LAYER) { |
| err = -2; /* height information is out of the valid range */ |
| } |
| } |
| for (i = 0; i < pPce->NumBackChannelElements; i++) { |
| if ((pPce->BackElementHeightInfo[i] = (UCHAR)FDKreadBits(bs, 2)) >= |
| PC_NUM_HEIGHT_LAYER) { |
| err = -2; /* height information is out of the valid range */ |
| } |
| } |
| FDKbyteAlign(bs, alignmentAnchor); |
| |
| FDKcrcEndReg(&crcInfo, bs, crcReg); |
| if ((USHORT)FDKreadBits(bs, 8) != FDKcrcGetCRC(&crcInfo)) { |
| /* CRC failed */ |
| err = -1; |
| } |
| if (err != 0) { |
| /* Reset whole height information in case an error occured during parsing. |
| The return value ensures that pPce->isValid is set to 0 and implicit |
| channel mapping is used. */ |
| FDKmemclear(pPce->FrontElementHeightInfo, |
| sizeof(pPce->FrontElementHeightInfo)); |
| FDKmemclear(pPce->SideElementHeightInfo, |
| sizeof(pPce->SideElementHeightInfo)); |
| FDKmemclear(pPce->BackElementHeightInfo, |
| sizeof(pPce->BackElementHeightInfo)); |
| } |
| } else { |
| /* No valid extension data found -> restore the initial bitbuffer state */ |
| FDKpushBack(bs, (INT)startAnchor - (INT)FDKgetValidBits(bs)); |
| } |
| |
| /* Always report the bytes read. */ |
| *bytesAvailable -= ((INT)startAnchor - (INT)FDKgetValidBits(bs)) >> 3; |
| |
| return (err); |
| } |
| |
| void CProgramConfig_Read(CProgramConfig *pPce, HANDLE_FDK_BITSTREAM bs, |
| UINT alignmentAnchor) { |
| int i, err = 0; |
| int commentBytes; |
| |
| pPce->NumEffectiveChannels = 0; |
| pPce->NumChannels = 0; |
| pPce->ElementInstanceTag = (UCHAR)FDKreadBits(bs, 4); |
| pPce->Profile = (UCHAR)FDKreadBits(bs, 2); |
| pPce->SamplingFrequencyIndex = (UCHAR)FDKreadBits(bs, 4); |
| pPce->NumFrontChannelElements = (UCHAR)FDKreadBits(bs, 4); |
| pPce->NumSideChannelElements = (UCHAR)FDKreadBits(bs, 4); |
| pPce->NumBackChannelElements = (UCHAR)FDKreadBits(bs, 4); |
| pPce->NumLfeChannelElements = (UCHAR)FDKreadBits(bs, 2); |
| pPce->NumAssocDataElements = (UCHAR)FDKreadBits(bs, 3); |
| pPce->NumValidCcElements = (UCHAR)FDKreadBits(bs, 4); |
| |
| if ((pPce->MonoMixdownPresent = (UCHAR)FDKreadBits(bs, 1)) != 0) { |
| pPce->MonoMixdownElementNumber = (UCHAR)FDKreadBits(bs, 4); |
| } |
| |
| if ((pPce->StereoMixdownPresent = (UCHAR)FDKreadBits(bs, 1)) != 0) { |
| pPce->StereoMixdownElementNumber = (UCHAR)FDKreadBits(bs, 4); |
| } |
| |
| if ((pPce->MatrixMixdownIndexPresent = (UCHAR)FDKreadBits(bs, 1)) != 0) { |
| pPce->MatrixMixdownIndex = (UCHAR)FDKreadBits(bs, 2); |
| pPce->PseudoSurroundEnable = (UCHAR)FDKreadBits(bs, 1); |
| } |
| |
| for (i = 0; i < pPce->NumFrontChannelElements; i++) { |
| pPce->FrontElementIsCpe[i] = (UCHAR)FDKreadBits(bs, 1); |
| pPce->FrontElementTagSelect[i] = (UCHAR)FDKreadBits(bs, 4); |
| pPce->NumChannels += pPce->FrontElementIsCpe[i] ? 2 : 1; |
| } |
| |
| for (i = 0; i < pPce->NumSideChannelElements; i++) { |
| pPce->SideElementIsCpe[i] = (UCHAR)FDKreadBits(bs, 1); |
| pPce->SideElementTagSelect[i] = (UCHAR)FDKreadBits(bs, 4); |
| pPce->NumChannels += pPce->SideElementIsCpe[i] ? 2 : 1; |
| } |
| |
| for (i = 0; i < pPce->NumBackChannelElements; i++) { |
| pPce->BackElementIsCpe[i] = (UCHAR)FDKreadBits(bs, 1); |
| pPce->BackElementTagSelect[i] = (UCHAR)FDKreadBits(bs, 4); |
| pPce->NumChannels += pPce->BackElementIsCpe[i] ? 2 : 1; |
| } |
| |
| pPce->NumEffectiveChannels = pPce->NumChannels; |
| |
| for (i = 0; i < pPce->NumLfeChannelElements; i++) { |
| pPce->LfeElementTagSelect[i] = (UCHAR)FDKreadBits(bs, 4); |
| pPce->NumChannels += 1; |
| } |
| |
| for (i = 0; i < pPce->NumAssocDataElements; i++) { |
| pPce->AssocDataElementTagSelect[i] = (UCHAR)FDKreadBits(bs, 4); |
| } |
| |
| for (i = 0; i < pPce->NumValidCcElements; i++) { |
| pPce->CcElementIsIndSw[i] = (UCHAR)FDKreadBits(bs, 1); |
| pPce->ValidCcElementTagSelect[i] = (UCHAR)FDKreadBits(bs, 4); |
| } |
| |
| FDKbyteAlign(bs, alignmentAnchor); |
| |
| pPce->CommentFieldBytes = (UCHAR)FDKreadBits(bs, 8); |
| commentBytes = pPce->CommentFieldBytes; |
| |
| /* Search for height info extension and read it if available */ |
| err = CProgramConfig_ReadHeightExt(pPce, bs, &commentBytes, alignmentAnchor); |
| |
| for (i = 0; i < commentBytes; i++) { |
| UCHAR text; |
| |
| text = (UCHAR)FDKreadBits(bs, 8); |
| |
| if (i < PC_COMMENTLENGTH) { |
| pPce->Comment[i] = text; |
| } |
| } |
| |
| pPce->isValid = (err) ? 0 : 1; |
| } |
| |
| /* |
| * Compare two program configurations. |
| * Returns the result of the comparison: |
| * -1 - completely different |
| * 0 - completely equal |
| * 1 - different but same channel configuration |
| * 2 - different channel configuration but same number of channels |
| */ |
| int CProgramConfig_Compare(const CProgramConfig *const pPce1, |
| const CProgramConfig *const pPce2) { |
| int result = 0; /* Innocent until proven false. */ |
| |
| if (FDKmemcmp(pPce1, pPce2, sizeof(CProgramConfig)) != |
| 0) { /* Configurations are not completely equal. |
| So look into details and analyse the channel configurations: */ |
| result = -1; |
| |
| if (pPce1->NumChannels == |
| pPce2->NumChannels) { /* Now the logic changes. We first assume to have |
| the same channel configuration and then prove |
| if this assumption is true. */ |
| result = 1; |
| |
| /* Front channels */ |
| if (pPce1->NumFrontChannelElements != pPce2->NumFrontChannelElements) { |
| result = 2; /* different number of front channel elements */ |
| } else { |
| int el, numCh1 = 0, numCh2 = 0; |
| for (el = 0; el < pPce1->NumFrontChannelElements; el += 1) { |
| if (pPce1->FrontElementHeightInfo[el] != |
| pPce2->FrontElementHeightInfo[el]) { |
| result = 2; /* different height info */ |
| break; |
| } |
| numCh1 += pPce1->FrontElementIsCpe[el] ? 2 : 1; |
| numCh2 += pPce2->FrontElementIsCpe[el] ? 2 : 1; |
| } |
| if (numCh1 != numCh2) { |
| result = 2; /* different number of front channels */ |
| } |
| } |
| /* Side channels */ |
| if (pPce1->NumSideChannelElements != pPce2->NumSideChannelElements) { |
| result = 2; /* different number of side channel elements */ |
| } else { |
| int el, numCh1 = 0, numCh2 = 0; |
| for (el = 0; el < pPce1->NumSideChannelElements; el += 1) { |
| if (pPce1->SideElementHeightInfo[el] != |
| pPce2->SideElementHeightInfo[el]) { |
| result = 2; /* different height info */ |
| break; |
| } |
| numCh1 += pPce1->SideElementIsCpe[el] ? 2 : 1; |
| numCh2 += pPce2->SideElementIsCpe[el] ? 2 : 1; |
| } |
| if (numCh1 != numCh2) { |
| result = 2; /* different number of side channels */ |
| } |
| } |
| /* Back channels */ |
| if (pPce1->NumBackChannelElements != pPce2->NumBackChannelElements) { |
| result = 2; /* different number of back channel elements */ |
| } else { |
| int el, numCh1 = 0, numCh2 = 0; |
| for (el = 0; el < pPce1->NumBackChannelElements; el += 1) { |
| if (pPce1->BackElementHeightInfo[el] != |
| pPce2->BackElementHeightInfo[el]) { |
| result = 2; /* different height info */ |
| break; |
| } |
| numCh1 += pPce1->BackElementIsCpe[el] ? 2 : 1; |
| numCh2 += pPce2->BackElementIsCpe[el] ? 2 : 1; |
| } |
| if (numCh1 != numCh2) { |
| result = 2; /* different number of back channels */ |
| } |
| } |
| /* LFE channels */ |
| if (pPce1->NumLfeChannelElements != pPce2->NumLfeChannelElements) { |
| result = 2; /* different number of lfe channels */ |
| } |
| /* LFEs are always SCEs so we don't need to count the channels. */ |
| } |
| } |
| |
| return result; |
| } |
| |
| void CProgramConfig_GetDefault(CProgramConfig *pPce, const UINT channelConfig) { |
| FDK_ASSERT(pPce != NULL); |
| |
| /* Init PCE */ |
| CProgramConfig_Init(pPce); |
| pPce->Profile = |
| 1; /* Set AAC LC because it is the only supported object type. */ |
| |
| switch (channelConfig) { |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
| case 32: /* 7.1 side channel configuration as defined in FDK_audio.h */ |
| pPce->NumFrontChannelElements = 2; |
| pPce->FrontElementIsCpe[0] = 0; |
| pPce->FrontElementIsCpe[1] = 1; |
| pPce->NumSideChannelElements = 1; |
| pPce->SideElementIsCpe[0] = 1; |
| pPce->NumBackChannelElements = 1; |
| pPce->BackElementIsCpe[0] = 1; |
| pPce->NumLfeChannelElements = 1; |
| pPce->NumChannels = 8; |
| pPce->NumEffectiveChannels = 7; |
| pPce->isValid = 1; |
| break; |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
| case 12: /* 3/0/4.1ch surround back */ |
| pPce->BackElementIsCpe[1] = 1; |
| pPce->NumChannels += 1; |
| pPce->NumEffectiveChannels += 1; |
| case 11: /* 3/0/3.1ch */ |
| pPce->NumFrontChannelElements += 2; |
| pPce->FrontElementIsCpe[0] = 0; |
| pPce->FrontElementIsCpe[1] = 1; |
| pPce->NumBackChannelElements += 2; |
| pPce->BackElementIsCpe[0] = 1; |
| pPce->BackElementIsCpe[1] += 0; |
| pPce->NumLfeChannelElements += 1; |
| pPce->NumChannels += 7; |
| pPce->NumEffectiveChannels += 6; |
| pPce->isValid = 1; |
| break; |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
| case 14: /* 2/0/0-3/0/2-0.1ch front height */ |
| pPce->FrontElementHeightInfo[2] = 1; /* Top speaker */ |
| case 7: /* 5/0/2.1ch front */ |
| pPce->NumFrontChannelElements += 1; |
| pPce->FrontElementIsCpe[2] = 1; |
| pPce->NumChannels += 2; |
| pPce->NumEffectiveChannels += 2; |
| case 6: /* 3/0/2.1ch */ |
| pPce->NumLfeChannelElements += 1; |
| pPce->NumChannels += 1; |
| case 5: /* 3/0/2.0ch */ |
| case 4: /* 3/0/1.0ch */ |
| pPce->NumBackChannelElements += 1; |
| pPce->BackElementIsCpe[0] = (channelConfig > 4) ? 1 : 0; |
| pPce->NumChannels += (channelConfig > 4) ? 2 : 1; |
| pPce->NumEffectiveChannels += (channelConfig > 4) ? 2 : 1; |
| case 3: /* 3/0/0.0ch */ |
| pPce->NumFrontChannelElements += 1; |
| pPce->FrontElementIsCpe[1] = 1; |
| pPce->NumChannels += 2; |
| pPce->NumEffectiveChannels += 2; |
| case 1: /* 1/0/0.0ch */ |
| pPce->NumFrontChannelElements += 1; |
| pPce->FrontElementIsCpe[0] = 0; |
| pPce->NumChannels += 1; |
| pPce->NumEffectiveChannels += 1; |
| pPce->isValid = 1; |
| break; |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
| case 2: /* 2/0/0.ch */ |
| pPce->NumFrontChannelElements = 1; |
| pPce->FrontElementIsCpe[0] = 1; |
| pPce->NumChannels += 2; |
| pPce->NumEffectiveChannels += 2; |
| pPce->isValid = 1; |
| break; |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
| default: |
| pPce->isValid = 0; /* To be explicit! */ |
| break; |
| } |
| |
| if (pPce->isValid) { |
| /* Create valid element instance tags */ |
| int el, elTagSce = 0, elTagCpe = 0; |
| |
| for (el = 0; el < pPce->NumFrontChannelElements; el += 1) { |
| pPce->FrontElementTagSelect[el] = |
| (pPce->FrontElementIsCpe[el]) ? elTagCpe++ : elTagSce++; |
| } |
| for (el = 0; el < pPce->NumSideChannelElements; el += 1) { |
| pPce->SideElementTagSelect[el] = |
| (pPce->SideElementIsCpe[el]) ? elTagCpe++ : elTagSce++; |
| } |
| for (el = 0; el < pPce->NumBackChannelElements; el += 1) { |
| pPce->BackElementTagSelect[el] = |
| (pPce->BackElementIsCpe[el]) ? elTagCpe++ : elTagSce++; |
| } |
| elTagSce = 0; |
| for (el = 0; el < pPce->NumLfeChannelElements; el += 1) { |
| pPce->LfeElementTagSelect[el] = elTagSce++; |
| } |
| } |
| } |
| |
| /** |
| * \brief get implicit audio channel type for given channelConfig and MPEG |
| * ordered channel index |
| * \param channelConfig MPEG channelConfiguration from 1 upto 14 |
| * \param index MPEG channel order index |
| * \return audio channel type. |
| */ |
| static void getImplicitAudioChannelTypeAndIndex(AUDIO_CHANNEL_TYPE *chType, |
| UCHAR *chIndex, |
| UINT channelConfig, |
| UINT index) { |
| if (index < 3) { |
| *chType = ACT_FRONT; |
| *chIndex = index; |
| } else { |
| switch (channelConfig) { |
| case 4: /* SCE, CPE, SCE */ |
| case 5: /* SCE, CPE, CPE */ |
| case 6: /* SCE, CPE, CPE, LFE */ |
| switch (index) { |
| case 3: |
| case 4: |
| *chType = ACT_BACK; |
| *chIndex = index - 3; |
| break; |
| case 5: |
| *chType = ACT_LFE; |
| *chIndex = 0; |
| break; |
| } |
| break; |
| case 7: /* SCE,CPE,CPE,CPE,LFE */ |
| switch (index) { |
| case 3: |
| case 4: |
| *chType = ACT_FRONT; |
| *chIndex = index; |
| break; |
| case 5: |
| case 6: |
| *chType = ACT_BACK; |
| *chIndex = index - 5; |
| break; |
| case 7: |
| *chType = ACT_LFE; |
| *chIndex = 0; |
| break; |
| } |
| break; |
| case 11: /* SCE,CPE,CPE,SCE,LFE */ |
| if (index < 6) { |
| *chType = ACT_BACK; |
| *chIndex = index - 3; |
| } else { |
| *chType = ACT_LFE; |
| *chIndex = 0; |
| } |
| break; |
| case 12: /* SCE,CPE,CPE,CPE,LFE */ |
| if (index < 7) { |
| *chType = ACT_BACK; |
| *chIndex = index - 3; |
| } else { |
| *chType = ACT_LFE; |
| *chIndex = 0; |
| } |
| break; |
| case 14: /* SCE,CPE,CPE,LFE,CPE */ |
| switch (index) { |
| case 3: |
| case 4: |
| *chType = ACT_BACK; |
| *chIndex = index - 3; |
| break; |
| case 5: |
| *chType = ACT_LFE; |
| *chIndex = 0; |
| break; |
| case 6: |
| case 7: |
| *chType = ACT_FRONT_TOP; |
| *chIndex = index - 6; /* handle the top layer independently */ |
| break; |
| } |
| break; |
| default: |
| *chType = ACT_NONE; |
| break; |
| } |
| } |
| } |
| |
| int CProgramConfig_LookupElement(CProgramConfig *pPce, UINT channelConfig, |
| const UINT tag, const UINT channelIdx, |
| UCHAR chMapping[], AUDIO_CHANNEL_TYPE chType[], |
| UCHAR chIndex[], const UINT chDescrLen, |
| UCHAR *elMapping, MP4_ELEMENT_ID elList[], |
| MP4_ELEMENT_ID elType) { |
| if (channelConfig > 0) { |
| /* Constant channel mapping must have |
| been set during initialization. */ |
| if (IS_CHANNEL_ELEMENT(elType)) { |
| *elMapping = pPce->elCounter; |
| if (elList[pPce->elCounter] != elType && |
| !IS_USAC_CHANNEL_ELEMENT(elType)) { |
| /* Not in the list */ |
| if ((channelConfig == 2) && |
| (elType == ID_SCE)) { /* This scenario occurs with HE-AAC v2 streams |
| of buggy encoders. In other decoder |
| implementations decoding of this kind of |
| streams is desired. */ |
| channelConfig = 1; |
| } else if ((elList[pPce->elCounter] == ID_LFE) && |
| (elType == |
| ID_SCE)) { /* Decode bitstreams which wrongly use ID_SCE |
| instead of ID_LFE element type. */ |
| ; |
| } else { |
| return 0; |
| } |
| } |
| /* Assume all front channels */ |
| getImplicitAudioChannelTypeAndIndex( |
| &chType[channelIdx], &chIndex[channelIdx], channelConfig, channelIdx); |
| if (elType == ID_CPE || elType == ID_USAC_CPE) { |
| chType[channelIdx + 1] = chType[channelIdx]; |
| chIndex[channelIdx + 1] = chIndex[channelIdx] + 1; |
| } |
| pPce->elCounter++; |
| } |
| /* Accept all non-channel elements, too. */ |
| return 1; |
| } else { |
| if ((!pPce->isValid) || (pPce->NumChannels > chDescrLen)) { |
| /* Implicit channel mapping. */ |
| if (IS_USAC_CHANNEL_ELEMENT(elType)) { |
| *elMapping = pPce->elCounter++; |
| } else if (IS_MP4_CHANNEL_ELEMENT(elType)) { |
| /* Store all channel element IDs */ |
| elList[pPce->elCounter] = elType; |
| *elMapping = pPce->elCounter++; |
| } |
| } else { |
| /* Accept the additional channel(s), only if the tag is in the lists */ |
| int isCpe = 0, i; |
| /* Element counter */ |
| int ec[PC_NUM_HEIGHT_LAYER] = {0}; |
| /* Channel counters */ |
| int cc[PC_NUM_HEIGHT_LAYER] = {0}; |
| int fc[PC_NUM_HEIGHT_LAYER] = {0}; /* front channel counter */ |
| int sc[PC_NUM_HEIGHT_LAYER] = {0}; /* side channel counter */ |
| int bc[PC_NUM_HEIGHT_LAYER] = {0}; /* back channel counter */ |
| int lc = 0; /* lfe channel counter */ |
| |
| /* General MPEG (PCE) composition rules: |
| - Over all: |
| <normal height channels><top height channels><bottom height |
| channels> |
| - Within each height layer: |
| <front channels><side channels><back channels> |
| - Exception: |
| The LFE channels have no height info and thus they are arranged at |
| the very end of the normal height layer channels. |
| */ |
| |
| switch (elType) { |
| case ID_CPE: |
| isCpe = 1; |
| case ID_SCE: |
| /* search in front channels */ |
| for (i = 0; i < pPce->NumFrontChannelElements; i++) { |
| int heightLayer = pPce->FrontElementHeightInfo[i]; |
| if (isCpe == pPce->FrontElementIsCpe[i] && |
| pPce->FrontElementTagSelect[i] == tag) { |
| int h, elIdx = ec[heightLayer], chIdx = cc[heightLayer]; |
| AUDIO_CHANNEL_TYPE aChType = |
| (AUDIO_CHANNEL_TYPE)((heightLayer << 4) | ACT_FRONT); |
| for (h = heightLayer - 1; h >= 0; h -= 1) { |
| int el; |
| /* Count front channels/elements */ |
| for (el = 0; el < pPce->NumFrontChannelElements; el += 1) { |
| if (pPce->FrontElementHeightInfo[el] == h) { |
| elIdx += 1; |
| chIdx += (pPce->FrontElementIsCpe[el]) ? 2 : 1; |
| } |
| } |
| /* Count side channels/elements */ |
| for (el = 0; el < pPce->NumSideChannelElements; el += 1) { |
| if (pPce->SideElementHeightInfo[el] == h) { |
| elIdx += 1; |
| chIdx += (pPce->SideElementIsCpe[el]) ? 2 : 1; |
| } |
| } |
| /* Count back channels/elements */ |
| for (el = 0; el < pPce->NumBackChannelElements; el += 1) { |
| if (pPce->BackElementHeightInfo[el] == h) { |
| elIdx += 1; |
| chIdx += (pPce->BackElementIsCpe[el]) ? 2 : 1; |
| } |
| } |
| if (h == 0) { /* normal height */ |
| elIdx += pPce->NumLfeChannelElements; |
| chIdx += pPce->NumLfeChannelElements; |
| } |
| } |
| chMapping[chIdx] = channelIdx; |
| chType[chIdx] = aChType; |
| chIndex[chIdx] = fc[heightLayer]; |
| if (isCpe) { |
| chMapping[chIdx + 1] = channelIdx + 1; |
| chType[chIdx + 1] = aChType; |
| chIndex[chIdx + 1] = fc[heightLayer] + 1; |
| } |
| *elMapping = elIdx; |
| return 1; |
| } |
| ec[heightLayer] += 1; |
| if (pPce->FrontElementIsCpe[i]) { |
| cc[heightLayer] += 2; |
| fc[heightLayer] += 2; |
| } else { |
| cc[heightLayer] += 1; |
| fc[heightLayer] += 1; |
| } |
| } |
| /* search in side channels */ |
| for (i = 0; i < pPce->NumSideChannelElements; i++) { |
| int heightLayer = pPce->SideElementHeightInfo[i]; |
| if (isCpe == pPce->SideElementIsCpe[i] && |
| pPce->SideElementTagSelect[i] == tag) { |
| int h, elIdx = ec[heightLayer], chIdx = cc[heightLayer]; |
| AUDIO_CHANNEL_TYPE aChType = |
| (AUDIO_CHANNEL_TYPE)((heightLayer << 4) | ACT_SIDE); |
| for (h = heightLayer - 1; h >= 0; h -= 1) { |
| int el; |
| /* Count front channels/elements */ |
| for (el = 0; el < pPce->NumFrontChannelElements; el += 1) { |
| if (pPce->FrontElementHeightInfo[el] == h) { |
| elIdx += 1; |
| chIdx += (pPce->FrontElementIsCpe[el]) ? 2 : 1; |
| } |
| } |
| /* Count side channels/elements */ |
| for (el = 0; el < pPce->NumSideChannelElements; el += 1) { |
| if (pPce->SideElementHeightInfo[el] == h) { |
| elIdx += 1; |
| chIdx += (pPce->SideElementIsCpe[el]) ? 2 : 1; |
| } |
| } |
| /* Count back channels/elements */ |
| for (el = 0; el < pPce->NumBackChannelElements; el += 1) { |
| if (pPce->BackElementHeightInfo[el] == h) { |
| elIdx += 1; |
| chIdx += (pPce->BackElementIsCpe[el]) ? 2 : 1; |
| } |
| } |
| if (h == |
| 0) { /* LFE channels belong to the normal height layer */ |
| elIdx += pPce->NumLfeChannelElements; |
| chIdx += pPce->NumLfeChannelElements; |
| } |
| } |
| chMapping[chIdx] = channelIdx; |
| chType[chIdx] = aChType; |
| chIndex[chIdx] = sc[heightLayer]; |
| if (isCpe) { |
| chMapping[chIdx + 1] = channelIdx + 1; |
| chType[chIdx + 1] = aChType; |
| chIndex[chIdx + 1] = sc[heightLayer] + 1; |
| } |
| *elMapping = elIdx; |
| return 1; |
| } |
| ec[heightLayer] += 1; |
| if (pPce->SideElementIsCpe[i]) { |
| cc[heightLayer] += 2; |
| sc[heightLayer] += 2; |
| } else { |
| cc[heightLayer] += 1; |
| sc[heightLayer] += 1; |
| } |
| } |
| /* search in back channels */ |
| for (i = 0; i < pPce->NumBackChannelElements; i++) { |
| int heightLayer = pPce->BackElementHeightInfo[i]; |
| if (isCpe == pPce->BackElementIsCpe[i] && |
| pPce->BackElementTagSelect[i] == tag) { |
| int h, elIdx = ec[heightLayer], chIdx = cc[heightLayer]; |
| AUDIO_CHANNEL_TYPE aChType = |
| (AUDIO_CHANNEL_TYPE)((heightLayer << 4) | ACT_BACK); |
| for (h = heightLayer - 1; h >= 0; h -= 1) { |
| int el; |
| /* Count front channels/elements */ |
| for (el = 0; el < pPce->NumFrontChannelElements; el += 1) { |
| if (pPce->FrontElementHeightInfo[el] == h) { |
| elIdx += 1; |
| chIdx += (pPce->FrontElementIsCpe[el]) ? 2 : 1; |
| } |
| } |
| /* Count side channels/elements */ |
| for (el = 0; el < pPce->NumSideChannelElements; el += 1) { |
| if (pPce->SideElementHeightInfo[el] == h) { |
| elIdx += 1; |
| chIdx += (pPce->SideElementIsCpe[el]) ? 2 : 1; |
| } |
| } |
| /* Count back channels/elements */ |
| for (el = 0; el < pPce->NumBackChannelElements; el += 1) { |
| if (pPce->BackElementHeightInfo[el] == h) { |
| elIdx += 1; |
| chIdx += (pPce->BackElementIsCpe[el]) ? 2 : 1; |
| } |
| } |
| if (h == 0) { /* normal height */ |
| elIdx += pPce->NumLfeChannelElements; |
| chIdx += pPce->NumLfeChannelElements; |
| } |
| } |
| chMapping[chIdx] = channelIdx; |
| chType[chIdx] = aChType; |
| chIndex[chIdx] = bc[heightLayer]; |
| if (isCpe) { |
| chMapping[chIdx + 1] = channelIdx + 1; |
| chType[chIdx + 1] = aChType; |
| chIndex[chIdx + 1] = bc[heightLayer] + 1; |
| } |
| *elMapping = elIdx; |
| return 1; |
| } |
| ec[heightLayer] += 1; |
| if (pPce->BackElementIsCpe[i]) { |
| cc[heightLayer] += 2; |
| bc[heightLayer] += 2; |
| } else { |
| cc[heightLayer] += 1; |
| bc[heightLayer] += 1; |
| } |
| } |
| break; |
| |
| case ID_LFE: { /* Unfortunately we have to go through all normal height |
| layer elements to get the position of the LFE |
| channels. Start with counting the front |
| channels/elements at normal height */ |
| for (i = 0; i < pPce->NumFrontChannelElements; i += 1) { |
| int heightLayer = pPce->FrontElementHeightInfo[i]; |
| ec[heightLayer] += 1; |
| cc[heightLayer] += (pPce->FrontElementIsCpe[i]) ? 2 : 1; |
| } |
| /* Count side channels/elements at normal height */ |
| for (i = 0; i < pPce->NumSideChannelElements; i += 1) { |
| int heightLayer = pPce->SideElementHeightInfo[i]; |
| ec[heightLayer] += 1; |
| cc[heightLayer] += (pPce->SideElementIsCpe[i]) ? 2 : 1; |
| } |
| /* Count back channels/elements at normal height */ |
| for (i = 0; i < pPce->NumBackChannelElements; i += 1) { |
| int heightLayer = pPce->BackElementHeightInfo[i]; |
| ec[heightLayer] += 1; |
| cc[heightLayer] += (pPce->BackElementIsCpe[i]) ? 2 : 1; |
| } |
| |
| /* search in lfe channels */ |
| for (i = 0; i < pPce->NumLfeChannelElements; i++) { |
| int elIdx = |
| ec[0]; /* LFE channels belong to the normal height layer */ |
| int chIdx = cc[0]; |
| if (pPce->LfeElementTagSelect[i] == tag) { |
| chMapping[chIdx] = channelIdx; |
| *elMapping = elIdx; |
| chType[chIdx] = ACT_LFE; |
| chIndex[chIdx] = lc; |
| return 1; |
| } |
| ec[0] += 1; |
| cc[0] += 1; |
| lc += 1; |
| } |
| } break; |
| |
| /* Non audio elements */ |
| case ID_CCE: |
| /* search in cce channels */ |
| for (i = 0; i < pPce->NumValidCcElements; i++) { |
| if (pPce->ValidCcElementTagSelect[i] == tag) { |
| return 1; |
| } |
| } |
| break; |
| case ID_DSE: |
| /* search associated data elements */ |
| for (i = 0; i < pPce->NumAssocDataElements; i++) { |
| if (pPce->AssocDataElementTagSelect[i] == tag) { |
| return 1; |
| } |
| } |
| break; |
| default: |
| return 0; |
| } |
| return 0; /* not found in any list */ |
| } |
| } |
| |
| return 1; |
| } |
| |
| #define SPEAKER_PLANE_NORMAL 0 |
| #define SPEAKER_PLANE_TOP 1 |
| #define SPEAKER_PLANE_BOTTOM 2 |
| |
| void CProgramConfig_GetChannelDescription(const UINT chConfig, |
| const CProgramConfig *pPce, |
| AUDIO_CHANNEL_TYPE chType[], |
| UCHAR chIndex[]) { |
| FDK_ASSERT(chType != NULL); |
| FDK_ASSERT(chIndex != NULL); |
| |
| if ((chConfig == 0) && (pPce != NULL)) { |
| if (pPce->isValid) { |
| int spkPlane, chIdx = 0; |
| for (spkPlane = SPEAKER_PLANE_NORMAL; spkPlane <= SPEAKER_PLANE_BOTTOM; |
| spkPlane += 1) { |
| int elIdx, grpChIdx = 0; |
| for (elIdx = 0; elIdx < pPce->NumFrontChannelElements; elIdx += 1) { |
| if (pPce->FrontElementHeightInfo[elIdx] == spkPlane) { |
| chType[chIdx] = (AUDIO_CHANNEL_TYPE)((spkPlane << 4) | ACT_FRONT); |
| chIndex[chIdx++] = grpChIdx++; |
| if (pPce->FrontElementIsCpe[elIdx]) { |
| chType[chIdx] = (AUDIO_CHANNEL_TYPE)((spkPlane << 4) | ACT_FRONT); |
| chIndex[chIdx++] = grpChIdx++; |
| } |
| } |
| } |
| grpChIdx = 0; |
| for (elIdx = 0; elIdx < pPce->NumSideChannelElements; elIdx += 1) { |
| if (pPce->SideElementHeightInfo[elIdx] == spkPlane) { |
| chType[chIdx] = (AUDIO_CHANNEL_TYPE)((spkPlane << 4) | ACT_SIDE); |
| chIndex[chIdx++] = grpChIdx++; |
| if (pPce->SideElementIsCpe[elIdx]) { |
| chType[chIdx] = (AUDIO_CHANNEL_TYPE)((spkPlane << 4) | ACT_SIDE); |
| chIndex[chIdx++] = grpChIdx++; |
| } |
| } |
| } |
| grpChIdx = 0; |
| for (elIdx = 0; elIdx < pPce->NumBackChannelElements; elIdx += 1) { |
| if (pPce->BackElementHeightInfo[elIdx] == spkPlane) { |
| chType[chIdx] = (AUDIO_CHANNEL_TYPE)((spkPlane << 4) | ACT_BACK); |
| chIndex[chIdx++] = grpChIdx++; |
| if (pPce->BackElementIsCpe[elIdx]) { |
| chType[chIdx] = (AUDIO_CHANNEL_TYPE)((spkPlane << 4) | ACT_BACK); |
| chIndex[chIdx++] = grpChIdx++; |
| } |
| } |
| } |
| grpChIdx = 0; |
| if (spkPlane == SPEAKER_PLANE_NORMAL) { |
| for (elIdx = 0; elIdx < pPce->NumLfeChannelElements; elIdx += 1) { |
| chType[chIdx] = ACT_LFE; |
| chIndex[chIdx++] = grpChIdx++; |
| } |
| } |
| } |
| } |
| } else { |
| int chIdx; |
| for (chIdx = 0; chIdx < getNumberOfTotalChannels(chConfig); chIdx += 1) { |
| getImplicitAudioChannelTypeAndIndex(&chType[chIdx], &chIndex[chIdx], |
| chConfig, chIdx); |
| } |
| } |
| } |
| |
| int CProgramConfig_GetPceChMap(const CProgramConfig *pPce, UCHAR pceChMap[], |
| const UINT pceChMapLen) { |
| const UCHAR *nElements = &pPce->NumFrontChannelElements; |
| const UCHAR *elHeight[3], *elIsCpe[3]; |
| unsigned chIdx, plane, grp, offset, totCh[3], numCh[3][4]; |
| |
| FDK_ASSERT(pPce != NULL); |
| FDK_ASSERT(pceChMap != NULL); |
| |
| /* Init counter: */ |
| FDKmemclear(totCh, 3 * sizeof(unsigned)); |
| FDKmemclear(numCh, 3 * 4 * sizeof(unsigned)); |
| |
| /* Analyse PCE: */ |
| elHeight[0] = pPce->FrontElementHeightInfo; |
| elIsCpe[0] = pPce->FrontElementIsCpe; |
| elHeight[1] = pPce->SideElementHeightInfo; |
| elIsCpe[1] = pPce->SideElementIsCpe; |
| elHeight[2] = pPce->BackElementHeightInfo; |
| elIsCpe[2] = pPce->BackElementIsCpe; |
| |
| for (plane = 0; plane <= SPEAKER_PLANE_BOTTOM; plane += 1) { |
| for (grp = 0; grp < 3; grp += 1) { /* front, side, back */ |
| unsigned el; |
| for (el = 0; el < nElements[grp]; el += 1) { |
| if (elHeight[grp][el] == plane) { |
| unsigned elCh = elIsCpe[grp][el] ? 2 : 1; |
| numCh[plane][grp] += elCh; |
| totCh[plane] += elCh; |
| } |
| } |
| } |
| if (plane == SPEAKER_PLANE_NORMAL) { |
| unsigned elCh = pPce->NumLfeChannelElements; |
| numCh[plane][grp] += elCh; |
| totCh[plane] += elCh; |
| } |
| } |
| /* Sanity checks: */ |
| chIdx = totCh[SPEAKER_PLANE_NORMAL] + totCh[SPEAKER_PLANE_TOP] + |
| totCh[SPEAKER_PLANE_BOTTOM]; |
| if (chIdx > pceChMapLen) { |
| return -1; |
| } |
| |
| /* Create map: */ |
| offset = grp = 0; |
| unsigned grpThresh = numCh[SPEAKER_PLANE_NORMAL][grp]; |
| for (chIdx = 0; chIdx < totCh[SPEAKER_PLANE_NORMAL]; chIdx += 1) { |
| while ((chIdx >= grpThresh) && (grp < 3)) { |
| offset += numCh[1][grp] + numCh[2][grp]; |
| grp += 1; |
| grpThresh += numCh[SPEAKER_PLANE_NORMAL][grp]; |
| } |
| pceChMap[chIdx] = chIdx + offset; |
| } |
| offset = 0; |
| for (grp = 0; grp < 4; grp += 1) { /* front, side, back and lfe */ |
| offset += numCh[SPEAKER_PLANE_NORMAL][grp]; |
| for (plane = SPEAKER_PLANE_TOP; plane <= SPEAKER_PLANE_BOTTOM; plane += 1) { |
| unsigned mapCh; |
| for (mapCh = 0; mapCh < numCh[plane][grp]; mapCh += 1) { |
| pceChMap[chIdx++] = offset; |
| offset += 1; |
| } |
| } |
| } |
| return 0; |
| } |
| |
| int CProgramConfig_GetElementTable(const CProgramConfig *pPce, |
| MP4_ELEMENT_ID elList[], |
| const INT elListSize, UCHAR *pChMapIdx) { |
| int i, el = 0; |
| |
| FDK_ASSERT(elList != NULL); |
| FDK_ASSERT(pChMapIdx != NULL); |
| FDK_ASSERT(pPce != NULL); |
| |
| *pChMapIdx = 0; |
| |
| if ((elListSize < |
| pPce->NumFrontChannelElements + pPce->NumSideChannelElements + |
| pPce->NumBackChannelElements + pPce->NumLfeChannelElements) || |
| (pPce->NumChannels == 0)) { |
| return 0; |
| } |
| |
| for (i = 0; i < pPce->NumFrontChannelElements; i += 1) { |
| elList[el++] = (pPce->FrontElementIsCpe[i]) ? ID_CPE : ID_SCE; |
| } |
| |
| for (i = 0; i < pPce->NumSideChannelElements; i += 1) { |
| elList[el++] = (pPce->SideElementIsCpe[i]) ? ID_CPE : ID_SCE; |
| } |
| |
| for (i = 0; i < pPce->NumBackChannelElements; i += 1) { |
| elList[el++] = (pPce->BackElementIsCpe[i]) ? ID_CPE : ID_SCE; |
| } |
| |
| for (i = 0; i < pPce->NumLfeChannelElements; i += 1) { |
| elList[el++] = ID_LFE; |
| } |
| |
| /* Find an corresponding channel configuration if possible */ |
| switch (pPce->NumChannels) { |
| case 1: |
| case 2: |
| /* One and two channels have no alternatives. */ |
| *pChMapIdx = pPce->NumChannels; |
| break; |
| case 3: |
| case 4: |
| case 5: |
| case 6: { /* Test if the number of channels can be used as channel config: |
| */ |
| C_ALLOC_SCRATCH_START(tmpPce, CProgramConfig, 1); |
| /* Create a PCE for the config to test ... */ |
| CProgramConfig_GetDefault(tmpPce, pPce->NumChannels); |
| /* ... and compare it with the given one. */ |
| *pChMapIdx = (!(CProgramConfig_Compare(pPce, tmpPce) & 0xE)) |
| ? pPce->NumChannels |
| : 0; |
| /* If compare result is 0 or 1 we can be sure that it is channel |
| * config 11. */ |
| C_ALLOC_SCRATCH_END(tmpPce, CProgramConfig, 1); |
| } break; |
| case 7: { |
| C_ALLOC_SCRATCH_START(tmpPce, CProgramConfig, 1); |
| /* Create a PCE for the config to test ... */ |
| CProgramConfig_GetDefault(tmpPce, 11); |
| /* ... and compare it with the given one. */ |
| *pChMapIdx = (!(CProgramConfig_Compare(pPce, tmpPce) & 0xE)) ? 11 : 0; |
| /* If compare result is 0 or 1 we can be sure that it is channel |
| * config 11. */ |
| C_ALLOC_SCRATCH_END(tmpPce, CProgramConfig, 1); |
| } break; |
| case 8: { /* Try the four possible 7.1ch configurations. One after the |
| other. */ |
| UCHAR testCfg[4] = {32, 14, 12, 7}; |
| C_ALLOC_SCRATCH_START(tmpPce, CProgramConfig, 1); |
| for (i = 0; i < 4; i += 1) { |
| /* Create a PCE for the config to test ... */ |
| CProgramConfig_GetDefault(tmpPce, testCfg[i]); |
| /* ... and compare it with the given one. */ |
| if (!(CProgramConfig_Compare(pPce, tmpPce) & 0xE)) { |
| /* If the compare result is 0 or 1 than the two channel configurations |
| * match. */ |
| /* Explicit mapping of 7.1 side channel configuration to 7.1 rear |
| * channel mapping. */ |
| *pChMapIdx = (testCfg[i] == 32) ? 12 : testCfg[i]; |
| } |
| } |
| C_ALLOC_SCRATCH_END(tmpPce, CProgramConfig, 1); |
| } break; |
| default: |
| /* The PCE does not match any predefined channel configuration. */ |
| *pChMapIdx = 0; |
| break; |
| } |
| |
| return el; |
| } |
| |
| static AUDIO_OBJECT_TYPE getAOT(HANDLE_FDK_BITSTREAM bs) { |
| int tmp = 0; |
| |
| tmp = FDKreadBits(bs, 5); |
| if (tmp == AOT_ESCAPE) { |
| int tmp2 = FDKreadBits(bs, 6); |
| tmp = 32 + tmp2; |
| } |
| |
| return (AUDIO_OBJECT_TYPE)tmp; |
| } |
| |
| static INT getSampleRate(HANDLE_FDK_BITSTREAM bs, UCHAR *index, int nBits) { |
| INT sampleRate; |
| int idx; |
| |
| idx = FDKreadBits(bs, nBits); |
| if (idx == (1 << nBits) - 1) { |
| if (FDKgetValidBits(bs) < 24) { |
| return 0; |
| } |
| sampleRate = FDKreadBits(bs, 24); |
| } else { |
| sampleRate = SamplingRateTable[idx]; |
| } |
| |
| *index = idx; |
| |
| return sampleRate; |
| } |
| |
| static TRANSPORTDEC_ERROR GaSpecificConfig_Parse(CSGaSpecificConfig *self, |
| CSAudioSpecificConfig *asc, |
| HANDLE_FDK_BITSTREAM bs, |
| UINT ascStartAnchor) { |
| TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK; |
| |
| self->m_frameLengthFlag = FDKreadBits(bs, 1); |
| |
| self->m_dependsOnCoreCoder = FDKreadBits(bs, 1); |
| |
| if (self->m_dependsOnCoreCoder) self->m_coreCoderDelay = FDKreadBits(bs, 14); |
| |
| self->m_extensionFlag = FDKreadBits(bs, 1); |
| |
| if (asc->m_channelConfiguration == 0) { |
| CProgramConfig_Read(&asc->m_progrConfigElement, bs, ascStartAnchor); |
| } |
| |
| if ((asc->m_aot == AOT_AAC_SCAL) || (asc->m_aot == AOT_ER_AAC_SCAL)) { |
| self->m_layer = FDKreadBits(bs, 3); |
| } |
| |
| if (self->m_extensionFlag) { |
| if (asc->m_aot == AOT_ER_BSAC) { |
| self->m_numOfSubFrame = FDKreadBits(bs, 5); |
| self->m_layerLength = FDKreadBits(bs, 11); |
| } |
| |
| if ((asc->m_aot == AOT_ER_AAC_LC) || (asc->m_aot == AOT_ER_AAC_LTP) || |
| (asc->m_aot == AOT_ER_AAC_SCAL) || (asc->m_aot == AOT_ER_AAC_LD)) { |
| asc->m_vcb11Flag = FDKreadBits(bs, 1); /* aacSectionDataResilienceFlag */ |
| asc->m_rvlcFlag = |
| FDKreadBits(bs, 1); /* aacScalefactorDataResilienceFlag */ |
| asc->m_hcrFlag = FDKreadBits(bs, 1); /* aacSpectralDataResilienceFlag */ |
| } |
| |
| self->m_extensionFlag3 = FDKreadBits(bs, 1); |
| } |
| return (ErrorStatus); |
| } |
| |
| static INT skipSbrHeader(HANDLE_FDK_BITSTREAM hBs, int isUsac) { |
| /* Dummy parse SbrDfltHeader() */ |
| INT dflt_header_extra1, dflt_header_extra2, bitsToSkip = 0; |
| |
| if (!isUsac) { |
| bitsToSkip = 6; |
| FDKpushFor(hBs, 6); /* amp res 1, xover freq 3, reserved 2 */ |
| } |
| bitsToSkip += 8; |
| FDKpushFor(hBs, 8); /* start / stop freq */ |
| bitsToSkip += 2; |
| dflt_header_extra1 = FDKreadBit(hBs); |
| dflt_header_extra2 = FDKreadBit(hBs); |
| bitsToSkip += 5 * dflt_header_extra1 + 6 * dflt_header_extra2; |
| FDKpushFor(hBs, 5 * dflt_header_extra1 + 6 * dflt_header_extra2); |
| |
| return bitsToSkip; |
| } |
| |
| static INT ld_sbr_header(CSAudioSpecificConfig *asc, const INT dsFactor, |
| HANDLE_FDK_BITSTREAM hBs, CSTpCallBacks *cb) { |
| const int channelConfiguration = asc->m_channelConfiguration; |
| int i = 0, j = 0; |
| INT error = 0; |
| MP4_ELEMENT_ID element = ID_NONE; |
| |
| /* check whether the channelConfiguration is defined in |
| * channel_configuration_array */ |
| if (channelConfiguration < 0 || |
| channelConfiguration > (INT)(sizeof(channel_configuration_array) / |
| sizeof(MP4_ELEMENT_ID **) - |
| 1)) { |
| return TRANSPORTDEC_PARSE_ERROR; |
| } |
| |
| /* read elements of the passed channel_configuration until there is ID_NONE */ |
| while ((element = channel_configuration_array[channelConfiguration][j]) != |
| ID_NONE) { |
| if (element == ID_SCE || element == ID_CPE) { |
| error |= cb->cbSbr( |
| cb->cbSbrData, hBs, asc->m_samplingFrequency / dsFactor, |
| asc->m_extensionSamplingFrequency / dsFactor, |
| asc->m_samplesPerFrame / dsFactor, AOT_ER_AAC_ELD, element, i++, 0, 0, |
| asc->configMode, &asc->SbrConfigChanged, dsFactor); |
| if (error != TRANSPORTDEC_OK) { |
| goto bail; |
| } |
| } |
| j++; |
| } |
| bail: |
| return error; |
| } |
| |
| static TRANSPORTDEC_ERROR EldSpecificConfig_Parse(CSAudioSpecificConfig *asc, |
| HANDLE_FDK_BITSTREAM hBs, |
| CSTpCallBacks *cb) { |
| TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK; |
| CSEldSpecificConfig *esc = &asc->m_sc.m_eldSpecificConfig; |
| ASC_ELD_EXT_TYPE eldExtType; |
| int eldExtLen, len, cnt, ldSbrLen = 0, eldExtLenSum, numSbrHeader = 0, |
| sbrIndex; |
| |
| unsigned char downscale_fill_nibble; |
| |
| FDKmemclear(esc, sizeof(CSEldSpecificConfig)); |
| |
| esc->m_frameLengthFlag = FDKreadBits(hBs, 1); |
| if (esc->m_frameLengthFlag) { |
| asc->m_samplesPerFrame = 480; |
| } else { |
| asc->m_samplesPerFrame = 512; |
| } |
| |
| asc->m_vcb11Flag = FDKreadBits(hBs, 1); |
| asc->m_rvlcFlag = FDKreadBits(hBs, 1); |
| asc->m_hcrFlag = FDKreadBits(hBs, 1); |
| |
| esc->m_sbrPresentFlag = FDKreadBits(hBs, 1); |
| |
| if (esc->m_sbrPresentFlag == 1) { |
| esc->m_sbrSamplingRate = |
| FDKreadBits(hBs, 1); /* 0: single rate, 1: dual rate */ |
| esc->m_sbrCrcFlag = FDKreadBits(hBs, 1); |
| |
| asc->m_extensionSamplingFrequency = asc->m_samplingFrequency |
| << esc->m_sbrSamplingRate; |
| |
| if (cb->cbSbr != NULL) { |
| /* ELD reduced delay mode: LD-SBR initialization has to know the downscale |
| information. Postpone LD-SBR initialization and read ELD extension |
| information first. */ |
| switch (asc->m_channelConfiguration) { |
| case 1: |
| case 2: |
| numSbrHeader = 1; |
| break; |
| case 3: |
| numSbrHeader = 2; |
| break; |
| case 4: |
| case 5: |
| case 6: |
| numSbrHeader = 3; |
| break; |
| case 7: |
| case 11: |
| case 12: |
| case 14: |
| numSbrHeader = 4; |
| break; |
| default: |
| numSbrHeader = 0; |
| break; |
| } |
| for (sbrIndex = 0; sbrIndex < numSbrHeader; sbrIndex++) { |
| ldSbrLen += skipSbrHeader(hBs, 0); |
| } |
| } else { |
| return TRANSPORTDEC_UNSUPPORTED_FORMAT; |
| } |
| } |
| esc->m_useLdQmfTimeAlign = 0; |
| |
| /* new ELD syntax */ |
| eldExtLenSum = FDKgetValidBits(hBs); |
| esc->m_downscaledSamplingFrequency = asc->m_samplingFrequency; |
| /* parse ExtTypeConfigData */ |
| while ( |
| ((eldExtType = (ASC_ELD_EXT_TYPE)FDKreadBits(hBs, 4)) != ELDEXT_TERM) && |
| ((INT)FDKgetValidBits(hBs) >= 0)) { |
| eldExtLen = len = FDKreadBits(hBs, 4); |
| if (len == 0xf) { |
| len = FDKreadBits(hBs, 8); |
| eldExtLen += len; |
| |
| if (len == 0xff) { |
| len = FDKreadBits(hBs, 16); |
| eldExtLen += len; |
| } |
| } |
| |
| switch (eldExtType) { |
| case ELDEXT_LDSAC: |
| esc->m_useLdQmfTimeAlign = 1; |
| if (cb->cbSsc != NULL) { |
| ErrorStatus = (TRANSPORTDEC_ERROR)cb->cbSsc( |
| cb->cbSscData, hBs, asc->m_aot, asc->m_extensionSamplingFrequency, |
| 1, /* stereoConfigIndex */ |
| -1, /* nTimeSlots: read from bitstream */ |
| eldExtLen, asc->configMode, &asc->SacConfigChanged); |
| if (ErrorStatus != TRANSPORTDEC_OK) { |
| return TRANSPORTDEC_PARSE_ERROR; |
| } |
| break; |
| } |
| |
| /* fall-through */ |
| default: |
| for (cnt = 0; cnt < eldExtLen; cnt++) { |
| FDKreadBits(hBs, 8); |
| } |
| break; |
| |
| case ELDEXT_DOWNSCALEINFO: |
| UCHAR tmpDownscaleFreqIdx; |
| esc->m_downscaledSamplingFrequency = |
| getSampleRate(hBs, &tmpDownscaleFreqIdx, 4); |
| if (esc->m_downscaledSamplingFrequency == 0) { |
| return TRANSPORTDEC_PARSE_ERROR; |
| } |
| downscale_fill_nibble = FDKreadBits(hBs, 4); |
| if (downscale_fill_nibble != 0x0) { |
| return TRANSPORTDEC_PARSE_ERROR; |
| } |
| break; |
| } |
| } |
| |
| if ((INT)FDKgetValidBits(hBs) < 0) { |
| return TRANSPORTDEC_PARSE_ERROR; |
| } |
| |
| if (esc->m_sbrPresentFlag == 1 && numSbrHeader != 0) { |
| INT dsFactor = 1; /* Downscale factor must be 1 or even for SBR */ |
| if (esc->m_downscaledSamplingFrequency != 0) { |
| if (asc->m_samplingFrequency % esc->m_downscaledSamplingFrequency != 0) { |
| return TRANSPORTDEC_UNSUPPORTED_FORMAT; |
| } |
| dsFactor = asc->m_samplingFrequency / esc->m_downscaledSamplingFrequency; |
| if (dsFactor != 1 && (dsFactor)&1) { |
| return TRANSPORTDEC_UNSUPPORTED_FORMAT; /* SBR needs an even downscale |
| factor */ |
| } |
| if (dsFactor != 1 && dsFactor != 2 && dsFactor != 4) { |
| dsFactor = 1; /* don't apply dsf for not yet supported even dsfs */ |
| } |
| if ((INT)asc->m_samplesPerFrame % dsFactor != 0) { |
| return TRANSPORTDEC_UNSUPPORTED_FORMAT; /* frameSize/dsf must be an |
| integer number */ |
| } |
| } |
| eldExtLenSum = eldExtLenSum - FDKgetValidBits(hBs); |
| FDKpushBack(hBs, eldExtLenSum + ldSbrLen); |
| if (0 != ld_sbr_header(asc, dsFactor, hBs, cb)) { |
| return TRANSPORTDEC_PARSE_ERROR; |
| } |
| FDKpushFor(hBs, eldExtLenSum); |
| } |
| return (ErrorStatus); |
| } |
| |
| /* |
| Subroutine to store config in UCHAR buffer. Bit stream position does not change. |
| */ |
| static UINT StoreConfigAsBitstream( |
| HANDLE_FDK_BITSTREAM hBs, const INT configSize_bits, /* If < 0 (> 0) config |
| to read is before |
| (after) current bit |
| stream position. */ |
| UCHAR *configTargetBuffer, const USHORT configTargetBufferSize_bytes) { |
| FDK_BITSTREAM usacConf; |
| UINT const nBits = fAbs(configSize_bits); |
| UINT j, tmp; |
| |
| if (nBits > 8 * (UINT)configTargetBufferSize_bytes) { |
| return 1; |
| } |
| FDKmemclear(configTargetBuffer, configTargetBufferSize_bytes); |
| |
| FDKinitBitStream(&usacConf, configTargetBuffer, configTargetBufferSize_bytes, |
| nBits, BS_WRITER); |
| if (configSize_bits < 0) { |
| FDKpushBack(hBs, nBits); |
| } |
| for (j = nBits; j > 31; j -= 32) { |
| tmp = FDKreadBits(hBs, 32); |
| FDKwriteBits(&usacConf, tmp, 32); |
| } |
| if (j > 0) { |
| tmp = FDKreadBits(hBs, j); |
| FDKwriteBits(&usacConf, tmp, j); |
| } |
| FDKsyncCache(&usacConf); |
| if (configSize_bits > 0) { |
| FDKpushBack(hBs, nBits); |
| } |
| |
| return 0; |
| } |
| |
| /* maps coreSbrFrameLengthIndex to coreCoderFrameLength */ |
| static const USHORT usacFrameLength[8] = {768, 1024, 2048, 2048, 4096, 0, 0, 0}; |
| /* maps coreSbrFrameLengthIndex to sbrRatioIndex */ |
| static const UCHAR sbrRatioIndex[8] = {0, 0, 2, 3, 1, 0, 0, 0}; |
| |
| /* |
| subroutine for parsing extension element configuration: |
| UsacExtElementConfig() q.v. ISO/IEC FDIS 23003-3:2011(E) Table 14 |
| rsv603daExtElementConfig() q.v. ISO/IEC DIS 23008-3 Table 13 |
| */ |
| static TRANSPORTDEC_ERROR extElementConfig(CSUsacExtElementConfig *extElement, |
| HANDLE_FDK_BITSTREAM hBs, |
| const CSTpCallBacks *cb, |
| const UCHAR numSignalsInGroup, |
| const UINT coreFrameLength, |
| const int subStreamIndex, |
| const AUDIO_OBJECT_TYPE aot) { |
| TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK; |
| |
| USAC_EXT_ELEMENT_TYPE usacExtElementType = |
| (USAC_EXT_ELEMENT_TYPE)escapedValue(hBs, 4, 8, 16); |
| |
| /* recurve extension elements which are invalid for USAC */ |
| if (aot == AOT_USAC) { |
| switch (usacExtElementType) { |
| case ID_EXT_ELE_FILL: |
| case ID_EXT_ELE_MPEGS: |
| case ID_EXT_ELE_SAOC: |
| case ID_EXT_ELE_AUDIOPREROLL: |
| case ID_EXT_ELE_UNI_DRC: |
| break; |
| default: |
| usacExtElementType = ID_EXT_ELE_UNKNOWN; |
| break; |
| } |
| } |
| |
| extElement->usacExtElementType = usacExtElementType; |
| int usacExtElementConfigLength = escapedValue(hBs, 4, 8, 16); |
| extElement->usacExtElementConfigLength = (USHORT)usacExtElementConfigLength; |
| INT bsAnchor; |
| |
| if (FDKreadBit(hBs)) /* usacExtElementDefaultLengthPresent */ |
| extElement->usacExtElementDefaultLength = escapedValue(hBs, 8, 16, 0) + 1; |
| else |
| extElement->usacExtElementDefaultLength = 0; |
| |
| extElement->usacExtElementPayloadFrag = FDKreadBit(hBs); |
| |
| bsAnchor = (INT)FDKgetValidBits(hBs); |
| |
| switch (usacExtElementType) { |
| case ID_EXT_ELE_UNKNOWN: |
| case ID_EXT_ELE_FILL: |
| break; |
| case ID_EXT_ELE_AUDIOPREROLL: |
| /* No configuration element */ |
| extElement->usacExtElementHasAudioPreRoll = 1; |
| break; |
| case ID_EXT_ELE_UNI_DRC: { |
| if (cb->cbUniDrc != NULL) { |
| ErrorStatus = (TRANSPORTDEC_ERROR)cb->cbUniDrc( |
| cb->cbUniDrcData, hBs, usacExtElementConfigLength, |
| 0, /* uniDrcConfig */ |
| subStreamIndex, 0, aot); |
| if (ErrorStatus != TRANSPORTDEC_OK) { |
| return ErrorStatus; |
| } |
| } |
| } break; |
| default: |
| break; |
| } |
| |
| /* Adjust bit stream position. This is required because of byte alignment and |
| * unhandled extensions. */ |
| { |
| INT left_bits = (usacExtElementConfigLength << 3) - |
| (bsAnchor - (INT)FDKgetValidBits(hBs)); |
| if (left_bits >= 0) { |
| FDKpushFor(hBs, left_bits); |
| } else { |
| /* parsed too many bits */ |
| ErrorStatus = TRANSPORTDEC_PARSE_ERROR; |
| } |
| } |
| |
| return ErrorStatus; |
| } |
| |
| /* |
| subroutine for parsing the USAC / RSVD60 configuration extension: |
| UsacConfigExtension() q.v. ISO/IEC FDIS 23003-3:2011(E) Table 15 |
| rsv603daConfigExtension() q.v. ISO/IEC DIS 23008-3 Table 14 |
| */ |
| static TRANSPORTDEC_ERROR configExtension(CSUsacConfig *usc, |
| HANDLE_FDK_BITSTREAM hBs, |
| const CSTpCallBacks *cb) { |
| TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK; |
| |
| int numConfigExtensions; |
| CONFIG_EXT_ID usacConfigExtType; |
| int usacConfigExtLength; |
| |
| numConfigExtensions = (int)escapedValue(hBs, 2, 4, 8) + 1; |
| for (int confExtIdx = 0; confExtIdx < numConfigExtensions; confExtIdx++) { |
| INT nbits; |
| int loudnessInfoSetConfigExtensionPosition = FDKgetValidBits(hBs); |
| usacConfigExtType = (CONFIG_EXT_ID)escapedValue(hBs, 4, 8, 16); |
| usacConfigExtLength = (int)escapedValue(hBs, 4, 8, 16); |
| |
| /* Start bit position of config extension */ |
| nbits = (INT)FDKgetValidBits(hBs); |
| |
| /* Return an error in case the bitbuffer fill level is too low. */ |
| if (nbits < usacConfigExtLength * 8) { |
| return TRANSPORTDEC_PARSE_ERROR; |
| } |
| |
| switch (usacConfigExtType) { |
| case ID_CONFIG_EXT_FILL: |
| for (int i = 0; i < usacConfigExtLength; i++) { |
| if (FDKreadBits(hBs, 8) != 0xa5) { |
| return TRANSPORTDEC_PARSE_ERROR; |
| } |
| } |
| break; |
| case ID_CONFIG_EXT_LOUDNESS_INFO: { |
| if (cb->cbUniDrc != NULL) { |
| ErrorStatus = (TRANSPORTDEC_ERROR)cb->cbUniDrc( |
| cb->cbUniDrcData, hBs, usacConfigExtLength, |
| 1, /* loudnessInfoSet */ |
| 0, loudnessInfoSetConfigExtensionPosition, AOT_USAC); |
| if (ErrorStatus != TRANSPORTDEC_OK) { |
| return ErrorStatus; |
| } |
| } |
| } break; |
| default: |
| break; |
| } |
| |
| /* Skip remaining bits. If too many bits were parsed, assume error. */ |
| usacConfigExtLength = |
| 8 * usacConfigExtLength - (nbits - (INT)FDKgetValidBits(hBs)); |
| if (usacConfigExtLength < 0) { |
| return TRANSPORTDEC_PARSE_ERROR; |
| } |
| FDKpushFor(hBs, usacConfigExtLength); |
| } |
| |
| return ErrorStatus; |
| } |
| |
| /* This function unifies decoder config parsing of USAC and RSV60: |
| rsv603daDecoderConfig() ISO/IEC DIS 23008-3 Table 8 |
| UsacDecoderConfig() ISO/IEC FDIS 23003-3 Table 6 |
| */ |
| static TRANSPORTDEC_ERROR UsacRsv60DecoderConfig_Parse( |
| CSAudioSpecificConfig *asc, HANDLE_FDK_BITSTREAM hBs, |
| const CSTpCallBacks *cb) { |
| TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK; |
| CSUsacConfig *usc = &asc->m_sc.m_usacConfig; |
| int i, numberOfElements; |
| int channelElementIdx = |
| 0; /* index for elements which contain audio channels (sce, cpe, lfe) */ |
| SC_CHANNEL_CONFIG sc_chan_config = {0, 0, 0, 0}; |
| |
| numberOfElements = (int)escapedValue(hBs, 4, 8, 16) + 1; |
| usc->m_usacNumElements = numberOfElements; |
| if (numberOfElements > TP_USAC_MAX_ELEMENTS) { |
| return TRANSPORTDEC_UNSUPPORTED_FORMAT; |
| } |
| usc->m_nUsacChannels = 0; |
| usc->m_channelConfigurationIndex = asc->m_channelConfiguration; |
| |
| if (asc->m_aot == AOT_USAC) { |
| sc_chan_config = sc_chan_config_tab[usc->m_channelConfigurationIndex]; |
| |
| if (sc_chan_config.nCh > (SCHAR)TP_USAC_MAX_SPEAKERS) { |
| return TRANSPORTDEC_PARSE_ERROR; |
| } |
| } |
| |
| for (i = 0; i < numberOfElements; i++) { |
| MP4_ELEMENT_ID usacElementType = (MP4_ELEMENT_ID)( |
| FDKreadBits(hBs, 2) | USAC_ID_BIT); /* set USAC_ID_BIT to map |
| usacElementType to |
| MP4_ELEMENT_ID enum */ |
| usc->element[i].usacElementType = usacElementType; |
| |
| /* sanity check: update element counter */ |
| if (asc->m_aot == AOT_USAC) { |
| switch (usacElementType) { |
| case ID_USAC_SCE: |
| sc_chan_config.nSCE--; |
| break; |
| case ID_USAC_CPE: |
| sc_chan_config.nCPE--; |
| break; |
| case ID_USAC_LFE: |
| sc_chan_config.nLFE--; |
| break; |
| default: |
| break; |
| } |
| if (usc->m_channelConfigurationIndex) { |
| /* sanity check: no element counter may be smaller zero */ |
| if (sc_chan_config.nCPE < 0 || sc_chan_config.nSCE < 0 || |
| sc_chan_config.nLFE < 0) { |
| return TRANSPORTDEC_PARSE_ERROR; |
| } |
| } |
| } |
| |
| switch (usacElementType) { |
| case ID_USAC_SCE: |
| /* UsacCoreConfig() ISO/IEC FDIS 23003-3 Table 10 */ |
| if (FDKreadBit(hBs)) { /* tw_mdct */ |
| return TRANSPORTDEC_UNSUPPORTED_FORMAT; |
| } |
| usc->element[i].m_noiseFilling = FDKreadBits(hBs, 1); |
| /* end of UsacCoreConfig() */ |
| if (usc->m_sbrRatioIndex > 0) { |
| if (cb->cbSbr == NULL) { |
| return TRANSPORTDEC_UNKOWN_ERROR; |
| } |
| /* SbrConfig() ISO/IEC FDIS 23003-3 Table 11 */ |
| usc->element[i].m_harmonicSBR = FDKreadBit(hBs); |
| usc->element[i].m_interTes = FDKreadBit(hBs); |
| usc->element[i].m_pvc = FDKreadBit(hBs); |
| if (cb->cbSbr(cb->cbSbrData, hBs, asc->m_samplingFrequency, |
| asc->m_extensionSamplingFrequency, |
| asc->m_samplesPerFrame, asc->m_aot, ID_SCE, |
| channelElementIdx, usc->element[i].m_harmonicSBR, |
| usc->element[i].m_stereoConfigIndex, asc->configMode, |
| &asc->SbrConfigChanged, 1)) { |
| return TRANSPORTDEC_PARSE_ERROR; |
| } |
| /* end of SbrConfig() */ |
| } |
| usc->m_nUsacChannels += 1; |
| channelElementIdx++; |
| break; |
| |
| case ID_USAC_CPE: |
| /* UsacCoreConfig() ISO/IEC FDIS 23003-3 Table 10 */ |
| if (FDKreadBit(hBs)) { /* tw_mdct */ |
| return TRANSPORTDEC_UNSUPPORTED_FORMAT; |
| } |
| usc->element[i].m_noiseFilling = FDKreadBits(hBs, 1); |
| /* end of UsacCoreConfig() */ |
| if (usc->m_sbrRatioIndex > 0) { |
| if (cb->cbSbr == NULL) return TRANSPORTDEC_UNKOWN_ERROR; |
| /* SbrConfig() ISO/IEC FDIS 23003-3 */ |
| usc->element[i].m_harmonicSBR = FDKreadBit(hBs); |
| usc->element[i].m_interTes = FDKreadBit(hBs); |
| usc->element[i].m_pvc = FDKreadBit(hBs); |
| { |
| INT bitsToSkip = skipSbrHeader(hBs, 1); |
| /* read stereoConfigIndex */ |
| usc->element[i].m_stereoConfigIndex = FDKreadBits(hBs, 2); |
| /* rewind */ |
| FDKpushBack(hBs, bitsToSkip + 2); |
| } |
| { |
| MP4_ELEMENT_ID el_type = |
| (usc->element[i].m_stereoConfigIndex == 1 || |
| usc->element[i].m_stereoConfigIndex == 2) |
| ? ID_SCE |
| : ID_CPE; |
| if (cb->cbSbr(cb->cbSbrData, hBs, asc->m_samplingFrequency, |
| asc->m_extensionSamplingFrequency, |
| asc->m_samplesPerFrame, asc->m_aot, el_type, |
| channelElementIdx, usc->element[i].m_harmonicSBR, |
| usc->element[i].m_stereoConfigIndex, asc->configMode, |
| &asc->SbrConfigChanged, 1)) { |
| return TRANSPORTDEC_PARSE_ERROR; |
| } |
| } |
| /* end of SbrConfig() */ |
| |
| usc->element[i].m_stereoConfigIndex = |
| FDKreadBits(hBs, 2); /* Needed in RM5 syntax */ |
| |
| if (usc->element[i].m_stereoConfigIndex > 0) { |
| if (cb->cbSsc != NULL) { |
| /* Mps212Config() ISO/IEC FDIS 23003-3 */ |
| if (cb->cbSsc(cb->cbSscData, hBs, asc->m_aot, |
| asc->m_extensionSamplingFrequency, |
| usc->element[i].m_stereoConfigIndex, |
| usc->m_coreSbrFrameLengthIndex, |
| 0, /* don't know the length */ |
| asc->configMode, &asc->SacConfigChanged)) { |
| return TRANSPORTDEC_PARSE_ERROR; |
| } |
| /* end of Mps212Config() */ |
| } else { |
| return TRANSPORTDEC_UNKOWN_ERROR; |
| } |
| } |
| } else { |
| usc->element[i].m_stereoConfigIndex = 0; |
| } |
| usc->m_nUsacChannels += 2; |
| |
| channelElementIdx++; |
| break; |
| |
| case ID_USAC_LFE: |
| usc->element[i].m_noiseFilling = 0; |
| usc->m_nUsacChannels += 1; |
| if (usc->m_sbrRatioIndex > 0) { |
| /* Use SBR for upsampling */ |
| if (cb->cbSbr == NULL) return ErrorStatus = TRANSPORTDEC_UNKOWN_ERROR; |
| usc->element[i].m_harmonicSBR = (UCHAR)0; |
| usc->element[i].m_interTes = (UCHAR)0; |
| usc->element[i].m_pvc = (UCHAR)0; |
| if (cb->cbSbr(cb->cbSbrData, hBs, asc->m_samplingFrequency, |
| asc->m_extensionSamplingFrequency, |
| asc->m_samplesPerFrame, asc->m_aot, ID_LFE, |
| channelElementIdx, usc->element[i].m_harmonicSBR, |
| usc->element[i].m_stereoConfigIndex, asc->configMode, |
| &asc->SbrConfigChanged, 1)) { |
| return ErrorStatus = TRANSPORTDEC_PARSE_ERROR; |
| } |
| } |
| channelElementIdx++; |
| break; |
| |
| case ID_USAC_EXT: |
| ErrorStatus = extElementConfig(&usc->element[i].extElement, hBs, cb, 0, |
| asc->m_samplesPerFrame, 0, asc->m_aot); |
| |
| if (ErrorStatus) { |
| return ErrorStatus; |
| } |
| break; |
| |
| default: |
| /* non USAC-element encountered */ |
| return TRANSPORTDEC_PARSE_ERROR; |
| } |
| } |
| |
| if (asc->m_aot == AOT_USAC) { |
| if (usc->m_channelConfigurationIndex) { |
| /* sanity check: all element counter must be zero */ |
| if (sc_chan_config.nCPE | sc_chan_config.nSCE | sc_chan_config.nLFE) { |
| return TRANSPORTDEC_PARSE_ERROR; |
| } |
| } else { |
| /* sanity check: number of audio channels shall be equal to or smaller |
| * than the accumulated sum of all channels */ |
| if ((INT)(-2 * sc_chan_config.nCPE - sc_chan_config.nSCE - |
| sc_chan_config.nLFE) < (INT)usc->numAudioChannels) { |
| return TRANSPORTDEC_PARSE_ERROR; |
| } |
| } |
| } |
| |
| return ErrorStatus; |
| } |
| |
| /* Mapping of coreSbrFrameLengthIndex defined by Table 70 in ISO/IEC 23003-3 */ |
| static TRANSPORTDEC_ERROR UsacConfig_SetCoreSbrFrameLengthIndex( |
| CSAudioSpecificConfig *asc, int coreSbrFrameLengthIndex) { |
| int sbrRatioIndex_val; |
| |
| if (coreSbrFrameLengthIndex > 4) { |
| return TRANSPORTDEC_PARSE_ERROR; /* reserved values */ |
| } |
| asc->m_sc.m_usacConfig.m_coreSbrFrameLengthIndex = coreSbrFrameLengthIndex; |
| asc->m_samplesPerFrame = usacFrameLength[coreSbrFrameLengthIndex]; |
| sbrRatioIndex_val = sbrRatioIndex[coreSbrFrameLengthIndex]; |
| asc->m_sc.m_usacConfig.m_sbrRatioIndex = sbrRatioIndex_val; |
| |
| if (sbrRatioIndex_val > 0) { |
| asc->m_sbrPresentFlag = 1; |
| asc->m_extensionSamplingFrequency = asc->m_samplingFrequency; |
| asc->m_extensionSamplingFrequencyIndex = asc->m_samplingFrequencyIndex; |
| switch (sbrRatioIndex_val) { |
| case 1: /* sbrRatio = 4:1 */ |
| asc->m_samplingFrequency >>= 2; |
| asc->m_samplesPerFrame >>= 2; |
| break; |
| case 2: /* sbrRatio = 8:3 */ |
| asc->m_samplingFrequency = (asc->m_samplingFrequency * 3) / 8; |
| asc->m_samplesPerFrame = (asc->m_samplesPerFrame * 3) / 8; |
| break; |
| case 3: /* sbrRatio = 2:1 */ |
| asc->m_samplingFrequency >>= 1; |
| asc->m_samplesPerFrame >>= 1; |
| break; |
| default: |
| return TRANSPORTDEC_PARSE_ERROR; |
| } |
| asc->m_samplingFrequencyIndex = |
| getSamplingRateIndex(asc->m_samplingFrequency, 4); |
| } |
| |
| return TRANSPORTDEC_OK; |
| } |
| |
| static TRANSPORTDEC_ERROR UsacConfig_Parse(CSAudioSpecificConfig *asc, |
| HANDLE_FDK_BITSTREAM hBs, |
| CSTpCallBacks *cb) { |
| int usacSamplingFrequency, channelConfigurationIndex, coreSbrFrameLengthIndex; |
| TRANSPORTDEC_ERROR err = TRANSPORTDEC_OK; |
| |
| /* Start bit position of usacConfig */ |
| INT nbits = (INT)FDKgetValidBits(hBs); |
| |
| usacSamplingFrequency = getSampleRate(hBs, &asc->m_samplingFrequencyIndex, 5); |
| asc->m_samplingFrequency = (UINT)usacSamplingFrequency; |
| |
| coreSbrFrameLengthIndex = FDKreadBits(hBs, 3); |
| if (UsacConfig_SetCoreSbrFrameLengthIndex(asc, coreSbrFrameLengthIndex) != |
| TRANSPORTDEC_OK) { |
| return TRANSPORTDEC_PARSE_ERROR; |
| } |
| |
| channelConfigurationIndex = FDKreadBits(hBs, 5); |
| if (channelConfigurationIndex > 2) { |
| return TRANSPORTDEC_PARSE_ERROR; /* only channelConfigurationIndex = [1,2] |
| are supported */ |
| } |
| |
| if (channelConfigurationIndex == 0) { |
| return TRANSPORTDEC_PARSE_ERROR; /* only channelConfigurationIndex = [1,2] |
| are supported */ |
| } |
| asc->m_channelConfiguration = channelConfigurationIndex; |
| |
| err = UsacRsv60DecoderConfig_Parse(asc, hBs, cb); |
| if (err != TRANSPORTDEC_OK) { |
| return err; |
| } |
| |
| if (FDKreadBits(hBs, 1)) { /* usacConfigExtensionPresent */ |
| err = configExtension(&asc->m_sc.m_usacConfig, hBs, cb); |
| if (err != TRANSPORTDEC_OK) { |
| return err; |
| } |
| } |
| |
| /* sanity check whether number of channels signaled in UsacDecoderConfig() |
| matches the number of channels required by channelConfigurationIndex */ |
| if ((channelConfigurationIndex > 0) && |
| (sc_chan_config_tab[channelConfigurationIndex].nCh != |
| asc->m_sc.m_usacConfig.m_nUsacChannels)) { |
| return TRANSPORTDEC_PARSE_ERROR; |
| } |
| |
| /* Copy UsacConfig() to asc->m_sc.m_usacConfig.UsacConfig[] buffer. */ |
| INT configSize_bits = (INT)FDKgetValidBits(hBs) - nbits; |
| StoreConfigAsBitstream(hBs, configSize_bits, |
| asc->m_sc.m_usacConfig.UsacConfig, |
| TP_USAC_MAX_CONFIG_LEN); |
| asc->m_sc.m_usacConfig.UsacConfigBits = fAbs(configSize_bits); |
| |
| return err; |
| } |
| |
| static TRANSPORTDEC_ERROR AudioSpecificConfig_ExtensionParse( |
| CSAudioSpecificConfig *self, HANDLE_FDK_BITSTREAM bs, CSTpCallBacks *cb) { |
| TP_ASC_EXTENSION_ID lastAscExt, ascExtId = ASCEXT_UNKOWN; |
| INT bitsAvailable = (INT)FDKgetValidBits(bs); |
| |
| while (bitsAvailable >= 11) { |
| lastAscExt = ascExtId; |
| ascExtId = (TP_ASC_EXTENSION_ID)FDKreadBits(bs, 11); |
| bitsAvailable -= 11; |
| |
| switch (ascExtId) { |
| case ASCEXT_SBR: /* 0x2b7 */ |
| if ((self->m_extensionAudioObjectType != AOT_SBR) && |
| (bitsAvailable >= 5)) { |
| self->m_extensionAudioObjectType = getAOT(bs); |
| |
| if ((self->m_extensionAudioObjectType == AOT_SBR) || |
| (self->m_extensionAudioObjectType == |
| AOT_ER_BSAC)) { /* Get SBR extension configuration */ |
| self->m_sbrPresentFlag = FDKreadBits(bs, 1); |
| if (self->m_aot == AOT_USAC && self->m_sbrPresentFlag > 0 && |
| self->m_sc.m_usacConfig.m_sbrRatioIndex == 0) { |
| return TRANSPORTDEC_PARSE_ERROR; |
| } |
| |
| if (self->m_sbrPresentFlag == 1) { |
| self->m_extensionSamplingFrequency = getSampleRate( |
| bs, &self->m_extensionSamplingFrequencyIndex, 4); |
| |
| if ((INT)self->m_extensionSamplingFrequency <= 0) { |
| return TRANSPORTDEC_PARSE_ERROR; |
| } |
| } |
| if (self->m_extensionAudioObjectType == AOT_ER_BSAC) { |
| self->m_extensionChannelConfiguration = FDKreadBits(bs, 4); |
| } |
| } |
| /* Update counter because of variable length fields (AOT and sampling |
| * rate) */ |
| bitsAvailable = (INT)FDKgetValidBits(bs); |
| } |
| break; |
| case ASCEXT_PS: /* 0x548 */ |
| if ((lastAscExt == ASCEXT_SBR) && |
| (self->m_extensionAudioObjectType == AOT_SBR) && |
| (bitsAvailable > 0)) { /* Get PS extension configuration */ |
| self->m_psPresentFlag = FDKreadBits(bs, 1); |
| bitsAvailable -= 1; |
| } |
| break; |
| case ASCEXT_MPS: /* 0x76a */ |
| if (self->m_extensionAudioObjectType == AOT_MPEGS) break; |
| case ASCEXT_LDMPS: /* 0x7cc */ |
| if ((ascExtId == ASCEXT_LDMPS) && |
| (self->m_extensionAudioObjectType == AOT_LD_MPEGS)) |
| break; |
| if (bitsAvailable >= 1) { |
| bitsAvailable -= 1; |
| if (FDKreadBits(bs, 1)) { /* self->m_mpsPresentFlag */ |
| int sscLen = FDKreadBits(bs, 8); |
| bitsAvailable -= 8; |
| if (sscLen == 0xFF) { |
| sscLen += FDKreadBits(bs, 16); |
| bitsAvailable -= 16; |
| } |
| FDKpushFor(bs, sscLen); /* Skip SSC to be able to read the next |
| extension if there is one. */ |
| |
| bitsAvailable -= sscLen * 8; |
| } |
| } |
| break; |
| case ASCEXT_SAOC: |
| if ((ascExtId == ASCEXT_SAOC) && |
| (self->m_extensionAudioObjectType == AOT_SAOC)) |
| break; |
| if (FDKreadBits(bs, 1)) { /* saocPresent */ |
| int saocscLen = FDKreadBits(bs, 8); |
| bitsAvailable -= 8; |
| if (saocscLen == 0xFF) { |
| saocscLen += FDKreadBits(bs, 16); |
| bitsAvailable -= 16; |
| } |
| FDKpushFor(bs, saocscLen); |
| bitsAvailable -= saocscLen * 8; |
| } |
| break; |
| default: |
| /* Just ignore anything. */ |
| return TRANSPORTDEC_OK; |
| } |
| } |
| |
| return TRANSPORTDEC_OK; |
| } |
| |
| /* |
| * API Functions |
| */ |
| |
| void AudioSpecificConfig_Init(CSAudioSpecificConfig *asc) { |
| FDKmemclear(asc, sizeof(CSAudioSpecificConfig)); |
| |
| /* Init all values that should not be zero. */ |
| asc->m_aot = AOT_NONE; |
| asc->m_samplingFrequencyIndex = 0xf; |
| asc->m_epConfig = -1; |
| asc->m_extensionAudioObjectType = AOT_NULL_OBJECT; |
| CProgramConfig_Init(&asc->m_progrConfigElement); |
| } |
| |
| TRANSPORTDEC_ERROR AudioSpecificConfig_Parse( |
| CSAudioSpecificConfig *self, HANDLE_FDK_BITSTREAM bs, |
| int fExplicitBackwardCompatible, CSTpCallBacks *cb, UCHAR configMode, |
| UCHAR configChanged, AUDIO_OBJECT_TYPE m_aot) { |
| TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK; |
| UINT ascStartAnchor = FDKgetValidBits(bs); |
| int frameLengthFlag = -1; |
| |
| AudioSpecificConfig_Init(self); |
| |
| self->configMode = configMode; |
| self->AacConfigChanged = configChanged; |
| self->SbrConfigChanged = configChanged; |
| self->SacConfigChanged = configChanged; |
| |
| if (m_aot != AOT_NULL_OBJECT) { |
| self->m_aot = m_aot; |
| } else { |
| self->m_aot = getAOT(bs); |
| self->m_samplingFrequency = |
| getSampleRate(bs, &self->m_samplingFrequencyIndex, 4); |
| if (self->m_samplingFrequency <= 0 || |
| (self->m_samplingFrequency > 96000 && self->m_aot != 39) || |
| self->m_samplingFrequency > 4 * 96000) { |
| return TRANSPORTDEC_PARSE_ERROR; |
| } |
| |
| self->m_channelConfiguration = FDKreadBits(bs, 4); |
| |
| /* SBR extension ( explicit non-backwards compatible mode ) */ |
| self->m_sbrPresentFlag = 0; |
| self->m_psPresentFlag = 0; |
| |
| if (self->m_aot == AOT_SBR || self->m_aot == AOT_PS) { |
| self->m_extensionAudioObjectType = AOT_SBR; |
| |
| self->m_sbrPresentFlag = 1; |
| if (self->m_aot == AOT_PS) { |
| self->m_psPresentFlag = 1; |
| } |
| |
| self->m_extensionSamplingFrequency = |
| getSampleRate(bs, &self->m_extensionSamplingFrequencyIndex, 4); |
| self->m_aot = getAOT(bs); |
| |
| switch (self->m_aot) { |
| case AOT_AAC_LC: |
| break; |
| case AOT_ER_BSAC: |
| break; |
| default: |
| return TRANSPORTDEC_UNSUPPORTED_FORMAT; |
| } |
| |
| if (self->m_aot == AOT_ER_BSAC) { |
| self->m_extensionChannelConfiguration = FDKreadBits(bs, 4); |
| } |
| } else { |
| self->m_extensionAudioObjectType = AOT_NULL_OBJECT; |
| } |
| } |
| |
| /* Parse whatever specific configs */ |
| switch (self->m_aot) { |
| case AOT_AAC_LC: |
| case AOT_AAC_SCAL: |
| case AOT_ER_AAC_LC: |
| case AOT_ER_AAC_LD: |
| case AOT_ER_AAC_SCAL: |
| case AOT_ER_BSAC: |
| if ((ErrorStatus = GaSpecificConfig_Parse(&self->m_sc.m_gaSpecificConfig, |
| self, bs, ascStartAnchor)) != |
| TRANSPORTDEC_OK) { |
| return (ErrorStatus); |
| } |
| frameLengthFlag = self->m_sc.m_gaSpecificConfig.m_frameLengthFlag; |
| break; |
| case AOT_MPEGS: |
| if (cb->cbSsc != NULL) { |
| if (cb->cbSsc(cb->cbSscData, bs, self->m_aot, self->m_samplingFrequency, |
| 1, -1, /* nTimeSlots: read from bitstream */ |
| 0, /* don't know the length */ |
| self->configMode, &self->SacConfigChanged)) { |
| return TRANSPORTDEC_UNSUPPORTED_FORMAT; |
| } |
| } else { |
| return TRANSPORTDEC_UNSUPPORTED_FORMAT; |
| } |
| break; |
| case AOT_ER_AAC_ELD: |
| if ((ErrorStatus = EldSpecificConfig_Parse(self, bs, cb)) != |
| TRANSPORTDEC_OK) { |
| return (ErrorStatus); |
| } |
| frameLengthFlag = self->m_sc.m_eldSpecificConfig.m_frameLengthFlag; |
| self->m_sbrPresentFlag = self->m_sc.m_eldSpecificConfig.m_sbrPresentFlag; |
| self->m_extensionSamplingFrequency = |
| (self->m_sc.m_eldSpecificConfig.m_sbrSamplingRate + 1) * |
| self->m_samplingFrequency; |
| break; |
| case AOT_USAC: |
| if ((ErrorStatus = UsacConfig_Parse(self, bs, cb)) != TRANSPORTDEC_OK) { |
| return (ErrorStatus); |
| } |
| break; |
| |
| default: |
| return TRANSPORTDEC_UNSUPPORTED_FORMAT; |
| } |
| |
| /* Frame length */ |
| switch (self->m_aot) { |
| case AOT_AAC_LC: |
| case AOT_AAC_SCAL: |
| case AOT_ER_AAC_LC: |
| case AOT_ER_AAC_SCAL: |
| case AOT_ER_BSAC: |
| /*case AOT_USAC:*/ |
| if (!frameLengthFlag) |
| self->m_samplesPerFrame = 1024; |
| else |
| self->m_samplesPerFrame = 960; |
| break; |
| case AOT_ER_AAC_LD: |
| if (!frameLengthFlag) |
| self->m_samplesPerFrame = 512; |
| else |
| self->m_samplesPerFrame = 480; |
| break; |
| default: |
| break; |
| } |
| |
| switch (self->m_aot) { |
| case AOT_ER_AAC_LC: |
| case AOT_ER_AAC_LD: |
| case AOT_ER_AAC_ELD: |
| case AOT_ER_AAC_SCAL: |
| case AOT_ER_CELP: |
| case AOT_ER_HVXC: |
| case AOT_ER_BSAC: |
| self->m_epConfig = FDKreadBits(bs, 2); |
| |
| if (self->m_epConfig > 1) { |
| return TRANSPORTDEC_UNSUPPORTED_FORMAT; // EPCONFIG; |
| } |
| break; |
| default: |
| break; |
| } |
| |
| if (fExplicitBackwardCompatible && |
| (self->m_aot == AOT_AAC_LC || self->m_aot == AOT_ER_AAC_LD || |
| self->m_aot == AOT_ER_BSAC)) { |
| ErrorStatus = AudioSpecificConfig_ExtensionParse(self, bs, cb); |
| } |
| |
| /* Copy config() to asc->config[] buffer. */ |
| if ((ErrorStatus == TRANSPORTDEC_OK) && (self->m_aot == AOT_USAC)) { |
| INT configSize_bits = (INT)FDKgetValidBits(bs) - (INT)ascStartAnchor; |
| StoreConfigAsBitstream(bs, configSize_bits, self->config, |
| TP_USAC_MAX_CONFIG_LEN); |
| self->configBits = fAbs(configSize_bits); |
| } |
| |
| return (ErrorStatus); |
| } |
| |
| static TRANSPORTDEC_ERROR Drm_xHEAACDecoderConfig( |
| CSAudioSpecificConfig *asc, HANDLE_FDK_BITSTREAM hBs, int audioMode, |
| CSTpCallBacks *cb /* use cb == NULL to signal config check only mode */ |
| ) { |
| TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK; |
| CSUsacConfig *usc = &asc->m_sc.m_usacConfig; |
| int elemIdx = 0; |
| |
| usc->element[elemIdx].m_stereoConfigIndex = 0; |
| |
| usc->m_usacNumElements = 1; /* Currently all extension elements are skipped |
| -> only one SCE or CPE. */ |
| |
| switch (audioMode) { |
| case 0: /* mono: ID_USAC_SCE */ |
| usc->element[elemIdx].usacElementType = ID_USAC_SCE; |
| usc->m_nUsacChannels = 1; |
| usc->element[elemIdx].m_noiseFilling = FDKreadBits(hBs, 1); |
| if (usc->m_sbrRatioIndex > 0) { |
| if (cb == NULL) { |
| return ErrorStatus; |
| } |
| if (cb->cbSbr != NULL) { |
| usc->element[elemIdx].m_harmonicSBR = FDKreadBit(hBs); |
| usc->element[elemIdx].m_interTes = FDKreadBit(hBs); |
| usc->element[elemIdx].m_pvc = FDKreadBit(hBs); |
| if (cb->cbSbr(cb->cbSbrData, hBs, asc->m_samplingFrequency, |
| asc->m_extensionSamplingFrequency, |
| asc->m_samplesPerFrame, asc->m_aot, ID_SCE, elemIdx, |
| usc->element[elemIdx].m_harmonicSBR, |
| usc->element[elemIdx].m_stereoConfigIndex, |
| asc->configMode, &asc->SbrConfigChanged, 1)) { |
| return ErrorStatus = TRANSPORTDEC_PARSE_ERROR; |
| } |
| } |
| } |
| break; |
| case 2: /* stereo: ID_USAC_CPE */ |
| usc->element[elemIdx].usacElementType = ID_USAC_CPE; |
| usc->m_nUsacChannels = 2; |
| usc->element[elemIdx].m_noiseFilling = FDKreadBits(hBs, 1); |
| if (usc->m_sbrRatioIndex > 0) { |
| usc->element[elemIdx].m_harmonicSBR = FDKreadBit(hBs); |
| usc->element[elemIdx].m_interTes = FDKreadBit(hBs); |
| usc->element[elemIdx].m_pvc = FDKreadBit(hBs); |
| { |
| INT bitsToSkip = skipSbrHeader(hBs, 1); |
| /* read stereoConfigIndex */ |
| usc->element[elemIdx].m_stereoConfigIndex = FDKreadBits(hBs, 2); |
| /* rewind */ |
| FDKpushBack(hBs, bitsToSkip + 2); |
| } |
| /* |
| The application of the following tools is mutually exclusive per audio |
| stream configuration (see clause 5.3.2, xHE-AAC codec configuration): |
| - MPS212 parametric stereo tool with residual coding |
| (stereoConfigIndex>1); and |
| - QMF based Harmonic Transposer (harmonicSBR==1). |
| */ |
| if ((usc->element[elemIdx].m_stereoConfigIndex > 1) && |
| usc->element[elemIdx].m_harmonicSBR) { |
| return ErrorStatus = TRANSPORTDEC_PARSE_ERROR; |
| } |
| /* |
| The 4:1 sbrRatio (sbrRatioIndex==1 in [11]) may only be employed: |
| - in mono operation; or |
| - in stereo operation if parametric stereo (MPS212) without residual |
| coding is applied, i.e. if stereoConfigIndex==1 (see clause 5.3.2, |
| xHE-AAC codec configuration). |
| */ |
| if ((usc->m_sbrRatioIndex == 1) && |
| (usc->element[elemIdx].m_stereoConfigIndex != 1)) { |
| return ErrorStatus = TRANSPORTDEC_PARSE_ERROR; |
| } |
| if (cb == NULL) { |
| return ErrorStatus; |
| } |
| { |
| MP4_ELEMENT_ID el_type = |
| (usc->element[elemIdx].m_stereoConfigIndex == 1 || |
| usc->element[elemIdx].m_stereoConfigIndex == 2) |
| ? ID_SCE |
| : ID_CPE; |
| if (cb->cbSbr == NULL) return ErrorStatus = TRANSPORTDEC_UNKOWN_ERROR; |
| if (cb->cbSbr(cb->cbSbrData, hBs, asc->m_samplingFrequency, |
| asc->m_extensionSamplingFrequency, |
| asc->m_samplesPerFrame, asc->m_aot, el_type, elemIdx, |
| usc->element[elemIdx].m_harmonicSBR, |
| usc->element[elemIdx].m_stereoConfigIndex, |
| asc->configMode, &asc->SbrConfigChanged, 1)) { |
| return ErrorStatus = TRANSPORTDEC_PARSE_ERROR; |
| } |
| } |
| /*usc->element[elemIdx].m_stereoConfigIndex =*/FDKreadBits(hBs, 2); |
| if (usc->element[elemIdx].m_stereoConfigIndex > 0) { |
| if (cb->cbSsc != NULL) { |
| ErrorStatus = (TRANSPORTDEC_ERROR)cb->cbSsc( |
| cb->cbSscData, hBs, |
| AOT_DRM_USAC, /* syntax differs from MPEG Mps212Config() */ |
| asc->m_extensionSamplingFrequency, |
| usc->element[elemIdx].m_stereoConfigIndex, |
| usc->m_coreSbrFrameLengthIndex, 0, /* don't know the length */ |
| asc->configMode, &asc->SacConfigChanged); |
| } else { |
| /* ErrorStatus = TRANSPORTDEC_UNSUPPORTED_FORMAT; */ |
| } |
| } |
| } |
| break; |
| default: |
| return TRANSPORTDEC_PARSE_ERROR; |
| } |
| |
| return ErrorStatus; |
| } |
| |
| TRANSPORTDEC_ERROR Drm_xHEAACStaticConfig( |
| CSAudioSpecificConfig *asc, HANDLE_FDK_BITSTREAM bs, int audioMode, |
| CSTpCallBacks *cb /* use cb == NULL to signal config check only mode */ |
| ) { |
| int coreSbrFrameLengthIndexDrm = FDKreadBits(bs, 2); |
| if (UsacConfig_SetCoreSbrFrameLengthIndex( |
| asc, coreSbrFrameLengthIndexDrm + 1) != TRANSPORTDEC_OK) { |
| return TRANSPORTDEC_PARSE_ERROR; |
| } |
| |
| asc->m_channelConfiguration = (audioMode) ? 2 : 1; |
| |
| if (Drm_xHEAACDecoderConfig(asc, bs, audioMode, cb) != TRANSPORTDEC_OK) { |
| return TRANSPORTDEC_PARSE_ERROR; |
| } |
| |
| return TRANSPORTDEC_OK; |
| } |
| |
| /* Mapping of DRM audio sampling rate field to MPEG usacSamplingFrequencyIndex |
| */ |
| const UCHAR mapSr2MPEGIdx[8] = { |
| 0x1b, /* 9.6 kHz */ |
| 0x09, /* 12.0 kHz */ |
| 0x08, /* 16.0 kHz */ |
| 0x17, /* 19.2 kHz */ |
| 0x06, /* 24.0 kHz */ |
| 0x05, /* 32.0 kHz */ |
| 0x12, /* 38.4 kHz */ |
| 0x03 /* 48.0 kHz */ |
| }; |
| |
| TRANSPORTDEC_ERROR DrmRawSdcAudioConfig_Parse( |
| CSAudioSpecificConfig *self, HANDLE_FDK_BITSTREAM bs, |
| CSTpCallBacks *cb, /* use cb == NULL to signal config check only mode */ |
| UCHAR configMode, UCHAR configChanged) { |
| TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK; |
| |
| AudioSpecificConfig_Init(self); |
| |
| if ((INT)FDKgetValidBits(bs) < 16) { |
| ErrorStatus = TRANSPORTDEC_PARSE_ERROR; |
| goto bail; |
| } else { |
| /* DRM - Audio information data entity - type 9 |
| - Short Id 2 bits (not part of the config buffer) |
| - Stream Id 2 bits (not part of the config buffer) |
| - audio coding 2 bits |
| - SBR flag 1 bit |
| - audio mode 2 bits |
| - audio sampling rate 3 bits |
| - text flag 1 bit |
| - enhancement flag 1 bit |
| - coder field 5 bits |
| - rfa 1 bit */ |
| |
| int audioCoding, audioMode, cSamplingFreq, coderField, sfIdx, sbrFlag; |
| |
| self->configMode = configMode; |
| self->AacConfigChanged = configChanged; |
| self->SbrConfigChanged = configChanged; |
| self->SacConfigChanged = configChanged; |
| |
| /* Read the SDC field */ |
| audioCoding = FDKreadBits(bs, 2); |
| sbrFlag = FDKreadBits(bs, 1); |
| audioMode = FDKreadBits(bs, 2); |
| cSamplingFreq = FDKreadBits(bs, 3); /* audio sampling rate */ |
| |
| FDKreadBits(bs, 2); /* Text and enhancement flag */ |
| coderField = FDKreadBits(bs, 5); |
| FDKreadBits(bs, 1); /* rfa */ |
| |
| /* Evaluate configuration and fill the ASC */ |
| if (audioCoding == 3) { |
| sfIdx = (int)mapSr2MPEGIdx[cSamplingFreq]; |
| sbrFlag = 0; /* rfa */ |
| } else { |
| switch (cSamplingFreq) { |
| case 0: /* 8 kHz */ |
| sfIdx = 11; |
| break; |
| case 1: /* 12 kHz */ |
| sfIdx = 9; |
| break; |
| case 2: /* 16 kHz */ |
| sfIdx = 8; |
| break; |
| case 3: /* 24 kHz */ |
| sfIdx = 6; |
| break; |
| case 5: /* 48 kHz */ |
| sfIdx = 3; |
| break; |
| case 4: /* reserved */ |
| case 6: /* reserved */ |
| case 7: /* reserved */ |
| default: |
| ErrorStatus = TRANSPORTDEC_PARSE_ERROR; |
| goto bail; |
| } |
| } |
| |
| self->m_samplingFrequencyIndex = sfIdx; |
| self->m_samplingFrequency = SamplingRateTable[sfIdx]; |
| |
| if (sbrFlag) { |
| UINT i; |
| int tmp = -1; |
| self->m_sbrPresentFlag = 1; |
| self->m_extensionAudioObjectType = AOT_SBR; |
| self->m_extensionSamplingFrequency = self->m_samplingFrequency << 1; |
| for (i = 0; |
| i < (sizeof(SamplingRateTable) / sizeof(SamplingRateTable[0])); |
| i++) { |
| if (SamplingRateTable[i] == self->m_extensionSamplingFrequency) { |
| tmp = i; |
| break; |
| } |
| } |
| self->m_extensionSamplingFrequencyIndex = tmp; |
| } |
| |
| switch (audioCoding) { |
| case 0: /* AAC */ |
| if ((coderField >> 2) && (audioMode != 1)) { |
| self->m_aot = AOT_DRM_SURROUND; /* Set pseudo AOT for Drm Surround */ |
| } else { |
| self->m_aot = AOT_DRM_AAC; /* Set pseudo AOT for Drm AAC */ |
| } |
| switch (audioMode) { |
| case 1: /* parametric stereo */ |
| self->m_psPresentFlag = 1; |
| case 0: /* mono */ |
| self->m_channelConfiguration = 1; |
| break; |
| case 2: /* stereo */ |
| self->m_channelConfiguration = 2; |
| break; |
| default: |
| ErrorStatus = TRANSPORTDEC_PARSE_ERROR; |
| goto bail; |
| } |
| self->m_vcb11Flag = 1; |
| self->m_hcrFlag = 1; |
| self->m_samplesPerFrame = 960; |
| self->m_epConfig = 1; |
| break; |
| case 1: /* CELP */ |
| self->m_aot = AOT_ER_CELP; |
| self->m_channelConfiguration = 1; |
| break; |
| case 2: /* HVXC */ |
| self->m_aot = AOT_ER_HVXC; |
| self->m_channelConfiguration = 1; |
| break; |
| case 3: /* xHE-AAC */ |
| { |
| /* payload is MPEG conform -> no pseudo DRM AOT needed */ |
| self->m_aot = AOT_USAC; |
| } |
| switch (audioMode) { |
| case 0: /* mono */ |
| case 2: /* stereo */ |
| /* codec specific config 8n bits */ |
| ErrorStatus = Drm_xHEAACStaticConfig(self, bs, audioMode, cb); |
| break; |
| default: |
| ErrorStatus = TRANSPORTDEC_PARSE_ERROR; |
| goto bail; |
| } |
| break; |
| default: |
| ErrorStatus = TRANSPORTDEC_PARSE_ERROR; |
| self->m_aot = AOT_NONE; |
| break; |
| } |
| |
| if (self->m_psPresentFlag && !self->m_sbrPresentFlag) { |
| ErrorStatus = TRANSPORTDEC_PARSE_ERROR; |
| goto bail; |
| } |
| } |
| |
| bail: |
| return (ErrorStatus); |
| } |