| /* ----------------------------------------------------------------------------- |
| 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 encoder library ********************* |
| |
| Author(s): |
| |
| Description: |
| |
| *******************************************************************************/ |
| |
| #include "tp_data.h" |
| |
| #include "tpenc_lib.h" |
| #include "tpenc_asc.h" |
| #include "FDK_bitstream.h" |
| #include "genericStds.h" |
| |
| #include "FDK_crc.h" |
| |
| #define PCE_HEIGHT_EXT_SYNC (0xAC) |
| #define HEIGHT_NORMAL 0 |
| #define HEIGHT_TOP 1 |
| #define HEIGHT_BOTTOM 2 |
| #define MAX_FRONT_ELEMENTS 8 |
| #define MAX_SIDE_ELEMENTS 3 |
| #define MAX_BACK_ELEMENTS 4 |
| |
| /** |
| * Describe additional PCE height information for front, side and back channel |
| * elements. |
| */ |
| typedef struct { |
| UCHAR |
| num_front_height_channel_elements[2]; /*!< Number of front channel |
| elements in top [0] and bottom |
| [1] plane. */ |
| UCHAR num_side_height_channel_elements[2]; /*!< Number of side channel |
| elements in top [0] and bottom |
| [1] plane. */ |
| UCHAR num_back_height_channel_elements[2]; /*!< Number of back channel |
| elements in top [0] and bottom |
| [1] plane. */ |
| } PCE_HEIGHT_NUM; |
| |
| /** |
| * Describe a PCE based on placed channel elements and element type sequence. |
| */ |
| typedef struct { |
| UCHAR num_front_channel_elements; /*!< Number of front channel elements. */ |
| UCHAR num_side_channel_elements; /*!< Number of side channel elements. */ |
| UCHAR num_back_channel_elements; /*!< Number of back channel elements. */ |
| UCHAR num_lfe_channel_elements; /*!< Number of lfe channel elements. */ |
| const MP4_ELEMENT_ID |
| *pEl_type; /*!< List contains sequence describing the elements |
| in present channel mode. (MPEG order) */ |
| const PCE_HEIGHT_NUM *pHeight_num; |
| } PCE_CONFIGURATION; |
| |
| /** |
| * Map an incoming channel mode to a existing PCE configuration entry. |
| */ |
| typedef struct { |
| CHANNEL_MODE channel_mode; /*!< Present channel mode. */ |
| PCE_CONFIGURATION |
| pce_configuration; /*!< Program config element description. */ |
| |
| } CHANNEL_CONFIGURATION; |
| |
| /** |
| * The following arrays provide the IDs of the consecutive elements for each |
| * mode. |
| */ |
| static const MP4_ELEMENT_ID elType_1[] = {ID_SCE}; |
| static const MP4_ELEMENT_ID elType_2[] = {ID_CPE}; |
| static const MP4_ELEMENT_ID elType_1_2[] = {ID_SCE, ID_CPE}; |
| static const MP4_ELEMENT_ID elType_1_2_1[] = {ID_SCE, ID_CPE, ID_SCE}; |
| static const MP4_ELEMENT_ID elType_1_2_2[] = {ID_SCE, ID_CPE, ID_CPE}; |
| static const MP4_ELEMENT_ID elType_1_2_2_1[] = {ID_SCE, ID_CPE, ID_CPE, ID_LFE}; |
| static const MP4_ELEMENT_ID elType_1_2_2_2_1[] = {ID_SCE, ID_CPE, ID_CPE, |
| ID_CPE, ID_LFE}; |
| static const MP4_ELEMENT_ID elType_6_1[] = {ID_SCE, ID_CPE, ID_CPE, ID_SCE, |
| ID_LFE}; |
| static const MP4_ELEMENT_ID elType_7_1_back[] = {ID_SCE, ID_CPE, ID_CPE, ID_CPE, |
| ID_LFE}; |
| static const MP4_ELEMENT_ID elType_7_1_top_front[] = {ID_SCE, ID_CPE, ID_CPE, |
| ID_LFE, ID_CPE}; |
| static const MP4_ELEMENT_ID elType_7_1_rear_surround[] = { |
| ID_SCE, ID_CPE, ID_CPE, ID_CPE, ID_LFE}; |
| static const MP4_ELEMENT_ID elType_7_1_front_center[] = {ID_SCE, ID_CPE, ID_CPE, |
| ID_CPE, ID_LFE}; |
| |
| /** |
| * The following arrays provide information on how many front, side and back |
| * elements are assigned to the top or bottom plane for each mode that comprises |
| * height information. |
| */ |
| static const PCE_HEIGHT_NUM heightNum_7_1_top_front = {{1, 0}, {0, 0}, {0, 0}}; |
| |
| /** |
| * \brief Table contains all supported channel modes and according PCE |
| configuration description. |
| * |
| * The mode identifier is followed by the number of front, side, back, and LFE |
| elements. |
| * These are followed by a pointer to the IDs of the consecutive elements |
| (ID_SCE, ID_CPE, ID_LFE). |
| * |
| * For some modes (MODE_7_1_TOP_FRONT and MODE_22_2) additional height |
| information is transmitted. |
| * In this case the additional pointer provides information on how many front, |
| side and back elements |
| * are assigned to the top or bottom plane.The elements are arranged in the |
| following order: normal height (front, side, back, LFE), top height (front, |
| side, back), bottom height (front, side, back). |
| * |
| * |
| * E.g. MODE_7_1_TOP_FRONT means: |
| * - 3 elements are front channel elements. |
| * - 0 elements are side channel elements. |
| * - 1 element is back channel element. |
| * - 1 element is an LFE channel element. |
| * - the element order is ID_SCE, ID_CPE, ID_CPE, |
| ID_LFE, ID_CPE. |
| * - 1 of the front elements is in the top plane. |
| * |
| * This leads to the following mapping for the cconsecutive elements in the |
| MODE_7_1_TOP_FRONT bitstream: |
| * - ID_SCE -> normal height front, |
| - ID_CPE -> normal height front, |
| - ID_CPE -> normal height back, |
| - ID_LFE -> normal height LFE, |
| - ID_CPE -> top height front. |
| */ |
| static const CHANNEL_CONFIGURATION pceConfigTab[] = { |
| {MODE_1, |
| {1, 0, 0, 0, elType_1, |
| NULL}}, /* don't transmit height information in this mode */ |
| {MODE_2, |
| {1, 0, 0, 0, elType_2, |
| NULL}}, /* don't transmit height information in this mode */ |
| {MODE_1_2, |
| {2, 0, 0, 0, elType_1_2, |
| NULL}}, /* don't transmit height information in this mode */ |
| {MODE_1_2_1, |
| {2, 0, 1, 0, elType_1_2_1, |
| NULL}}, /* don't transmit height information in this mode */ |
| {MODE_1_2_2, |
| {2, 0, 1, 0, elType_1_2_2, |
| NULL}}, /* don't transmit height information in this mode */ |
| {MODE_1_2_2_1, |
| {2, 0, 1, 1, elType_1_2_2_1, |
| NULL}}, /* don't transmit height information in this mode */ |
| {MODE_1_2_2_2_1, |
| {3, 0, 1, 1, elType_1_2_2_2_1, |
| NULL}}, /* don't transmit height information in this mode */ |
| |
| {MODE_6_1, |
| {2, 0, 2, 1, elType_6_1, |
| NULL}}, /* don't transmit height information in this mode */ |
| {MODE_7_1_BACK, |
| {2, 0, 2, 1, elType_7_1_back, |
| NULL}}, /* don't transmit height information in this mode */ |
| {MODE_7_1_TOP_FRONT, |
| {3, 0, 1, 1, elType_7_1_top_front, &heightNum_7_1_top_front}}, |
| |
| {MODE_7_1_REAR_SURROUND, |
| {2, 0, 2, 1, elType_7_1_rear_surround, |
| NULL}}, /* don't transmit height information in this mode */ |
| {MODE_7_1_FRONT_CENTER, |
| {3, 0, 1, 1, elType_7_1_front_center, |
| NULL}} /* don't transmit height information in this mode */ |
| }; |
| |
| /** |
| * \brief Get program config element description for existing channel mode. |
| * |
| * \param channel_mode Current channel mode. |
| * |
| * \return |
| * - Pointer to PCE_CONFIGURATION entry, on success. |
| * - NULL, on failure. |
| */ |
| static const PCE_CONFIGURATION *getPceEntry(const CHANNEL_MODE channel_mode) { |
| UINT i; |
| const PCE_CONFIGURATION *pce_config = NULL; |
| |
| for (i = 0; i < (sizeof(pceConfigTab) / sizeof(CHANNEL_CONFIGURATION)); i++) { |
| if (pceConfigTab[i].channel_mode == channel_mode) { |
| pce_config = &pceConfigTab[i].pce_configuration; |
| break; |
| } |
| } |
| |
| return pce_config; |
| } |
| |
| int getChannelConfig(const CHANNEL_MODE channel_mode, |
| const UCHAR channel_config_zero) { |
| INT chan_config = 0; |
| |
| if (channel_config_zero != 0) { |
| chan_config = 0; |
| } else { |
| switch (channel_mode) { |
| case MODE_1: |
| chan_config = 1; |
| break; |
| case MODE_2: |
| chan_config = 2; |
| break; |
| case MODE_1_2: |
| chan_config = 3; |
| break; |
| case MODE_1_2_1: |
| chan_config = 4; |
| break; |
| case MODE_1_2_2: |
| chan_config = 5; |
| break; |
| case MODE_1_2_2_1: |
| chan_config = 6; |
| break; |
| case MODE_1_2_2_2_1: |
| chan_config = 7; |
| break; |
| case MODE_6_1: |
| chan_config = 11; |
| break; |
| case MODE_7_1_BACK: |
| chan_config = 12; |
| break; |
| case MODE_7_1_TOP_FRONT: |
| chan_config = 14; |
| break; |
| default: |
| chan_config = 0; |
| } |
| } |
| |
| return chan_config; |
| } |
| |
| CHANNEL_MODE transportEnc_GetChannelMode(int noChannels) { |
| CHANNEL_MODE chMode; |
| |
| if (noChannels <= 8 && noChannels > 0) |
| chMode = (CHANNEL_MODE)( |
| (noChannels == 8) ? 7 |
| : noChannels); /* see : iso/mpeg4 v1 audio subpart1*/ |
| else |
| chMode = MODE_UNKNOWN; |
| |
| return chMode; |
| } |
| |
| int transportEnc_writePCE(HANDLE_FDK_BITSTREAM hBs, CHANNEL_MODE channelMode, |
| INT sampleRate, int instanceTagPCE, int profile, |
| int matrixMixdownA, int pseudoSurroundEnable, |
| UINT alignAnchor) { |
| int sampleRateIndex, i; |
| const PCE_CONFIGURATION *config = NULL; |
| const MP4_ELEMENT_ID *pEl_list = NULL; |
| UCHAR cpeCnt = 0, sceCnt = 0, lfeCnt = 0, frntCnt = 0, sdCnt = 0, bckCnt = 0, |
| isCpe = 0, tag = 0, normalFrontEnd = 0, normalSideEnd = 0, |
| normalBackEnd = 0, topFrontEnd = 0, topSideEnd = 0, topBackEnd = 0, |
| bottomFrontEnd = 0, bottomSideEnd = 0; |
| #ifdef FDK_ASSERT_ENABLE |
| UCHAR bottomBackEnd = 0; |
| #endif |
| enum elementDepth { FRONT, SIDE, BACK } elDepth; |
| |
| sampleRateIndex = getSamplingRateIndex(sampleRate, 4); |
| if (sampleRateIndex == 15) { |
| return -1; |
| } |
| |
| if ((config = getPceEntry(channelMode)) == NULL) { |
| return -1; |
| } |
| |
| FDK_ASSERT(config->num_front_channel_elements <= MAX_FRONT_ELEMENTS); |
| FDK_ASSERT(config->num_side_channel_elements <= MAX_SIDE_ELEMENTS); |
| FDK_ASSERT(config->num_back_channel_elements <= MAX_BACK_ELEMENTS); |
| |
| UCHAR frontIsCpe[MAX_FRONT_ELEMENTS] = {0}, |
| frontTag[MAX_FRONT_ELEMENTS] = {0}, sideIsCpe[MAX_SIDE_ELEMENTS] = {0}, |
| sideTag[MAX_SIDE_ELEMENTS] = {0}, backIsCpe[MAX_BACK_ELEMENTS] = {0}, |
| backTag[MAX_BACK_ELEMENTS] = {0}; |
| |
| /* Write general information */ |
| |
| FDKwriteBits(hBs, instanceTagPCE, 4); /* Element instance tag */ |
| FDKwriteBits(hBs, profile, 2); /* Object type */ |
| FDKwriteBits(hBs, sampleRateIndex, 4); /* Sample rate index*/ |
| |
| FDKwriteBits(hBs, config->num_front_channel_elements, |
| 4); /* Front channel Elements */ |
| FDKwriteBits(hBs, config->num_side_channel_elements, |
| 4); /* No Side Channel Elements */ |
| FDKwriteBits(hBs, config->num_back_channel_elements, |
| 4); /* No Back channel Elements */ |
| FDKwriteBits(hBs, config->num_lfe_channel_elements, |
| 2); /* No Lfe channel elements */ |
| |
| FDKwriteBits(hBs, 0, 3); /* No assoc data elements */ |
| FDKwriteBits(hBs, 0, 4); /* No valid cc elements */ |
| FDKwriteBits(hBs, 0, 1); /* Mono mixdown present */ |
| FDKwriteBits(hBs, 0, 1); /* Stereo mixdown present */ |
| |
| if (matrixMixdownA != 0 && |
| ((channelMode == MODE_1_2_2) || (channelMode == MODE_1_2_2_1))) { |
| FDKwriteBits(hBs, 1, 1); /* Matrix mixdown present */ |
| FDKwriteBits(hBs, (matrixMixdownA - 1) & 0x3, 2); /* matrix_mixdown_idx */ |
| FDKwriteBits(hBs, (pseudoSurroundEnable) ? 1 : 0, |
| 1); /* pseudo_surround_enable */ |
| } else { |
| FDKwriteBits(hBs, 0, 1); /* Matrix mixdown not present */ |
| } |
| |
| if (config->pHeight_num != NULL) { |
| /* we have up to three different height levels, and in each height level we |
| * may have front, side and back channels. We need to know where each |
| * section ends to correctly count the tags */ |
| normalFrontEnd = config->num_front_channel_elements - |
| config->pHeight_num->num_front_height_channel_elements[0] - |
| config->pHeight_num->num_front_height_channel_elements[1]; |
| normalSideEnd = normalFrontEnd + config->num_side_channel_elements - |
| config->pHeight_num->num_side_height_channel_elements[0] - |
| config->pHeight_num->num_side_height_channel_elements[1]; |
| normalBackEnd = normalSideEnd + config->num_back_channel_elements - |
| config->pHeight_num->num_back_height_channel_elements[0] - |
| config->pHeight_num->num_back_height_channel_elements[1]; |
| |
| topFrontEnd = |
| normalBackEnd + config->num_lfe_channel_elements + |
| config->pHeight_num->num_front_height_channel_elements[0]; /* only |
| normal |
| height |
| LFEs |
| assumed */ |
| topSideEnd = |
| topFrontEnd + config->pHeight_num->num_side_height_channel_elements[0]; |
| topBackEnd = |
| topSideEnd + config->pHeight_num->num_back_height_channel_elements[0]; |
| |
| bottomFrontEnd = |
| topBackEnd + config->pHeight_num->num_front_height_channel_elements[1]; |
| bottomSideEnd = bottomFrontEnd + |
| config->pHeight_num->num_side_height_channel_elements[1]; |
| #ifdef FDK_ASSERT_ENABLE |
| bottomBackEnd = bottomSideEnd + |
| config->pHeight_num->num_back_height_channel_elements[1]; |
| #endif |
| |
| } else { |
| /* we have only one height level, so we don't care about top or bottom */ |
| normalFrontEnd = config->num_front_channel_elements; |
| normalSideEnd = normalFrontEnd + config->num_side_channel_elements; |
| normalBackEnd = normalSideEnd + config->num_back_channel_elements; |
| } |
| |
| /* assign cpe and tag information to either front, side or back channels */ |
| |
| pEl_list = config->pEl_type; |
| |
| for (i = 0; i < config->num_front_channel_elements + |
| config->num_side_channel_elements + |
| config->num_back_channel_elements + |
| config->num_lfe_channel_elements; |
| i++) { |
| if (*pEl_list == ID_LFE) { |
| pEl_list++; |
| continue; |
| } |
| isCpe = (*pEl_list++ == ID_CPE) ? 1 : 0; |
| tag = (isCpe) ? cpeCnt++ : sceCnt++; |
| |
| if (i < normalFrontEnd) |
| elDepth = FRONT; |
| else if (i < normalSideEnd) |
| elDepth = SIDE; |
| else if (i < normalBackEnd) |
| elDepth = BACK; |
| else if (i < topFrontEnd) |
| elDepth = FRONT; |
| else if (i < topSideEnd) |
| elDepth = SIDE; |
| else if (i < topBackEnd) |
| elDepth = BACK; |
| else if (i < bottomFrontEnd) |
| elDepth = FRONT; |
| else if (i < bottomSideEnd) |
| elDepth = SIDE; |
| else { |
| elDepth = BACK; |
| FDK_ASSERT(i < bottomBackEnd); /* won't fail if implementation of pce |
| configuration table is correct */ |
| } |
| |
| switch (elDepth) { |
| case FRONT: |
| FDK_ASSERT(frntCnt < config->num_front_channel_elements); |
| frontIsCpe[frntCnt] = isCpe; |
| frontTag[frntCnt++] = tag; |
| break; |
| case SIDE: |
| FDK_ASSERT(sdCnt < config->num_side_channel_elements); |
| sideIsCpe[sdCnt] = isCpe; |
| sideTag[sdCnt++] = tag; |
| break; |
| case BACK: |
| FDK_ASSERT(bckCnt < config->num_back_channel_elements); |
| backIsCpe[bckCnt] = isCpe; |
| backTag[bckCnt++] = tag; |
| break; |
| } |
| } |
| |
| /* Write front channel isCpe and tags */ |
| for (i = 0; i < config->num_front_channel_elements; i++) { |
| FDKwriteBits(hBs, frontIsCpe[i], 1); |
| FDKwriteBits(hBs, frontTag[i], 4); |
| } |
| /* Write side channel isCpe and tags */ |
| for (i = 0; i < config->num_side_channel_elements; i++) { |
| FDKwriteBits(hBs, sideIsCpe[i], 1); |
| FDKwriteBits(hBs, sideTag[i], 4); |
| } |
| /* Write back channel isCpe and tags */ |
| for (i = 0; i < config->num_back_channel_elements; i++) { |
| FDKwriteBits(hBs, backIsCpe[i], 1); |
| FDKwriteBits(hBs, backTag[i], 4); |
| } |
| /* Write LFE information */ |
| for (i = 0; i < config->num_lfe_channel_elements; i++) { |
| FDKwriteBits(hBs, lfeCnt++, 4); /* LFE channel Instance Tag. */ |
| } |
| |
| /* - num_valid_cc_elements always 0. |
| - num_assoc_data_elements always 0. */ |
| |
| /* Byte alignment: relative to alignAnchor |
| ADTS: align with respect to the first bit of the raw_data_block() |
| ADIF: align with respect to the first bit of the header |
| LATM: align with respect to the first bit of the ASC */ |
| FDKbyteAlign(hBs, alignAnchor); /* Alignment */ |
| |
| /* Write comment information */ |
| |
| if (config->pHeight_num != NULL) { |
| /* embed height information in comment field */ |
| |
| INT commentBytes = |
| 1 /* PCE_HEIGHT_EXT_SYNC */ |
| + ((((config->num_front_channel_elements + |
| config->num_side_channel_elements + |
| config->num_back_channel_elements) |
| << 1) + |
| 7) >> |
| 3) /* 2 bit height info per element, round up to full bytes */ |
| + 1; /* CRC */ |
| |
| FDKwriteBits(hBs, commentBytes, 8); /* comment size. */ |
| |
| FDK_CRCINFO crcInfo; /* CRC state info */ |
| INT crcReg; |
| |
| FDKcrcInit(&crcInfo, 0x07, 0xFF, 8); |
| crcReg = FDKcrcStartReg(&crcInfo, hBs, 0); |
| |
| FDKwriteBits(hBs, PCE_HEIGHT_EXT_SYNC, 8); /* indicate height extension */ |
| |
| /* front channel height information */ |
| for (i = 0; |
| i < config->num_front_channel_elements - |
| config->pHeight_num->num_front_height_channel_elements[0] - |
| config->pHeight_num->num_front_height_channel_elements[1]; |
| i++) |
| FDKwriteBits(hBs, HEIGHT_NORMAL, 2); |
| for (i = 0; i < config->pHeight_num->num_front_height_channel_elements[0]; |
| i++) |
| FDKwriteBits(hBs, HEIGHT_TOP, 2); |
| for (i = 0; i < config->pHeight_num->num_front_height_channel_elements[1]; |
| i++) |
| FDKwriteBits(hBs, HEIGHT_BOTTOM, 2); |
| |
| /* side channel height information */ |
| for (i = 0; |
| i < config->num_side_channel_elements - |
| config->pHeight_num->num_side_height_channel_elements[0] - |
| config->pHeight_num->num_side_height_channel_elements[1]; |
| i++) |
| FDKwriteBits(hBs, HEIGHT_NORMAL, 2); |
| for (i = 0; i < config->pHeight_num->num_side_height_channel_elements[0]; |
| i++) |
| FDKwriteBits(hBs, HEIGHT_TOP, 2); |
| for (i = 0; i < config->pHeight_num->num_side_height_channel_elements[1]; |
| i++) |
| FDKwriteBits(hBs, HEIGHT_BOTTOM, 2); |
| |
| /* back channel height information */ |
| for (i = 0; |
| i < config->num_back_channel_elements - |
| config->pHeight_num->num_back_height_channel_elements[0] - |
| config->pHeight_num->num_back_height_channel_elements[1]; |
| i++) |
| FDKwriteBits(hBs, HEIGHT_NORMAL, 2); |
| for (i = 0; i < config->pHeight_num->num_back_height_channel_elements[0]; |
| i++) |
| FDKwriteBits(hBs, HEIGHT_TOP, 2); |
| for (i = 0; i < config->pHeight_num->num_back_height_channel_elements[1]; |
| i++) |
| FDKwriteBits(hBs, HEIGHT_BOTTOM, 2); |
| |
| FDKbyteAlign(hBs, alignAnchor); /* Alignment */ |
| |
| FDKcrcEndReg(&crcInfo, hBs, crcReg); |
| FDKwriteBits(hBs, FDKcrcGetCRC(&crcInfo), 8); |
| |
| } else { |
| FDKwriteBits(hBs, 0, |
| 8); /* Do no write any comment or height information. */ |
| } |
| |
| return 0; |
| } |
| |
| int transportEnc_GetPCEBits(CHANNEL_MODE channelMode, int matrixMixdownA, |
| int bits) { |
| const PCE_CONFIGURATION *config = NULL; |
| |
| if ((config = getPceEntry(channelMode)) == NULL) { |
| return -1; /* unsupported channelmapping */ |
| } |
| |
| bits += |
| 4 + 2 + 4; /* Element instance tag + Object type + Sample rate index */ |
| bits += 4 + 4 + 4 + 2; /* No (front + side + back + lfe channel) elements */ |
| bits += 3 + 4; /* No (assoc data + valid cc) elements */ |
| bits += 1 + 1 + 1; /* Mono + Stereo + Matrix mixdown present */ |
| |
| if (matrixMixdownA != 0 && |
| ((channelMode == MODE_1_2_2) || (channelMode == MODE_1_2_2_1))) { |
| bits += 3; /* matrix_mixdown_idx + pseudo_surround_enable */ |
| } |
| |
| bits += (1 + 4) * (INT)config->num_front_channel_elements; |
| bits += (1 + 4) * (INT)config->num_side_channel_elements; |
| bits += (1 + 4) * (INT)config->num_back_channel_elements; |
| bits += (4) * (INT)config->num_lfe_channel_elements; |
| |
| /* - num_valid_cc_elements always 0. |
| - num_assoc_data_elements always 0. */ |
| |
| if ((bits % 8) != 0) { |
| bits += (8 - (bits % 8)); /* Alignment */ |
| } |
| |
| bits += 8; /* Comment field bytes */ |
| |
| if (config->pHeight_num != NULL) { |
| /* Comment field (height extension) */ |
| |
| bits += |
| 8 /* PCE_HEIGHT_EXT_SYNC */ |
| + |
| ((config->num_front_channel_elements + |
| config->num_side_channel_elements + config->num_back_channel_elements) |
| << 1) /* 2 bit height info per element */ |
| + 8; /* CRC */ |
| |
| if ((bits % 8) != 0) { |
| bits += (8 - (bits % 8)); /* Alignment */ |
| } |
| } |
| |
| return bits; |
| } |
| |
| static void writeAot(HANDLE_FDK_BITSTREAM hBitstreamBuffer, |
| AUDIO_OBJECT_TYPE aot) { |
| int tmp = (int)aot; |
| |
| if (tmp > 31) { |
| FDKwriteBits(hBitstreamBuffer, AOT_ESCAPE, 5); |
| FDKwriteBits(hBitstreamBuffer, tmp - 32, 6); /* AudioObjectType */ |
| } else { |
| FDKwriteBits(hBitstreamBuffer, tmp, 5); |
| } |
| } |
| |
| static void writeSampleRate(HANDLE_FDK_BITSTREAM hBs, int sampleRate, |
| int nBits) { |
| int srIdx = getSamplingRateIndex(sampleRate, nBits); |
| |
| FDKwriteBits(hBs, srIdx, nBits); |
| if (srIdx == (1 << nBits) - 1) { |
| FDKwriteBits(hBs, sampleRate, 24); |
| } |
| } |
| |
| static int transportEnc_writeGASpecificConfig(HANDLE_FDK_BITSTREAM asc, |
| CODER_CONFIG *config, int extFlg, |
| UINT alignAnchor) { |
| int aot = config->aot; |
| int samplesPerFrame = config->samplesPerFrame; |
| |
| /* start of GASpecificConfig according to ISO/IEC 14496-3 Subpart 4, 4.4.1 */ |
| FDKwriteBits(asc, |
| ((samplesPerFrame == 960 || samplesPerFrame == 480) ? 1 : 0), |
| 1); /* frameLengthFlag: 1 for a 960/480 (I)MDCT, 0 for a 1024/512 |
| (I)MDCT*/ |
| FDKwriteBits(asc, 0, |
| 1); /* dependsOnCoreCoder: Sampling Rate Coder Specific, see in |
| ISO/IEC 14496-3 Subpart 4, 4.4.1 */ |
| FDKwriteBits(asc, extFlg, |
| 1); /* Extension Flag: Shall be 1 for aot = 17,19,20,21,22,23 */ |
| |
| /* Write PCE if channel config is not 1-7 */ |
| if (getChannelConfig(config->channelMode, config->channelConfigZero) == 0) { |
| transportEnc_writePCE(asc, config->channelMode, config->samplingRate, 0, 1, |
| config->matrixMixdownA, |
| (config->flags & CC_PSEUDO_SURROUND) ? 1 : 0, |
| alignAnchor); |
| } |
| if ((aot == AOT_AAC_SCAL) || (aot == AOT_ER_AAC_SCAL)) { |
| FDKwriteBits(asc, 0, 3); /* layerNr */ |
| } |
| if (extFlg) { |
| if (aot == AOT_ER_BSAC) { |
| FDKwriteBits(asc, config->BSACnumOfSubFrame, 5); /* numOfSubFrame */ |
| FDKwriteBits(asc, config->BSAClayerLength, 11); /* layer_length */ |
| } |
| if ((aot == AOT_ER_AAC_LC) || (aot == AOT_ER_AAC_LTP) || |
| (aot == AOT_ER_AAC_SCAL) || (aot == AOT_ER_AAC_LD)) { |
| FDKwriteBits(asc, (config->flags & CC_VCB11) ? 1 : 0, |
| 1); /* aacSectionDataResillienceFlag */ |
| FDKwriteBits(asc, (config->flags & CC_RVLC) ? 1 : 0, |
| 1); /* aacScaleFactorDataResillienceFlag */ |
| FDKwriteBits(asc, (config->flags & CC_HCR) ? 1 : 0, |
| 1); /* aacSpectralDataResillienceFlag */ |
| } |
| FDKwriteBits(asc, 0, 1); /* extensionFlag3: reserved. Shall be '0' */ |
| } |
| return 0; |
| } |
| |
| static int transportEnc_writeELDSpecificConfig(HANDLE_FDK_BITSTREAM hBs, |
| CODER_CONFIG *config, |
| int epConfig, |
| CSTpCallBacks *cb) { |
| UINT frameLengthFlag = 0; |
| switch (config->samplesPerFrame) { |
| case 512: |
| case 256: |
| case 128: |
| case 64: |
| frameLengthFlag = 0; |
| break; |
| case 480: |
| case 240: |
| case 160: |
| case 120: |
| case 60: |
| frameLengthFlag = 1; |
| break; |
| } |
| |
| FDKwriteBits(hBs, frameLengthFlag, 1); |
| |
| FDKwriteBits(hBs, (config->flags & CC_VCB11) ? 1 : 0, 1); |
| FDKwriteBits(hBs, (config->flags & CC_RVLC) ? 1 : 0, 1); |
| FDKwriteBits(hBs, (config->flags & CC_HCR) ? 1 : 0, 1); |
| |
| FDKwriteBits(hBs, (config->flags & CC_SBR) ? 1 : 0, 1); /* SBR header flag */ |
| if ((config->flags & CC_SBR)) { |
| FDKwriteBits(hBs, (config->samplingRate == config->extSamplingRate) ? 0 : 1, |
| 1); /* Samplerate Flag */ |
| FDKwriteBits(hBs, (config->flags & CC_SBRCRC) ? 1 : 0, 1); /* SBR CRC flag*/ |
| |
| if (cb->cbSbr != NULL) { |
| const PCE_CONFIGURATION *pPce; |
| int e, sbrElementIndex = 0; |
| |
| pPce = getPceEntry(config->channelMode); |
| |
| for (e = 0; e < pPce->num_front_channel_elements + |
| pPce->num_side_channel_elements + |
| pPce->num_back_channel_elements + |
| pPce->num_lfe_channel_elements; |
| e++) { |
| if ((pPce->pEl_type[e] == ID_SCE) || (pPce->pEl_type[e] == ID_CPE)) { |
| cb->cbSbr(cb->cbSbrData, hBs, 0, 0, 0, config->aot, pPce->pEl_type[e], |
| sbrElementIndex, 0, 0, 0, NULL, 1); |
| sbrElementIndex++; |
| } |
| } |
| } |
| } |
| |
| if ((config->flags & CC_SAC) && (cb->cbSsc != NULL)) { |
| FDKwriteBits(hBs, ELDEXT_LDSAC, 4); |
| |
| const INT eldExtLen = |
| (cb->cbSsc(cb->cbSscData, NULL, config->aot, config->extSamplingRate, 0, |
| 0, 0, 0, NULL) + |
| 7) >> |
| 3; |
| INT cnt = eldExtLen; |
| |
| if (cnt < 0xF) { |
| FDKwriteBits(hBs, cnt, 4); |
| } else { |
| FDKwriteBits(hBs, 0xF, 4); |
| cnt -= 0xF; |
| |
| if (cnt < 0xFF) { |
| FDKwriteBits(hBs, cnt, 8); |
| } else { |
| FDKwriteBits(hBs, 0xFF, 8); |
| cnt -= 0xFF; |
| |
| FDK_ASSERT(cnt <= 0xFFFF); |
| FDKwriteBits(hBs, cnt, 16); |
| } |
| } |
| |
| cb->cbSsc(cb->cbSscData, hBs, config->aot, config->extSamplingRate, 0, 0, 0, |
| 0, NULL); |
| } |
| |
| if (config->downscaleSamplingRate != 0 && |
| config->downscaleSamplingRate != config->extSamplingRate) { |
| /* downscale active */ |
| |
| /* eldExtLenDsc: Number of bytes for the ELD downscale extension (srIdx |
| needs 1 byte |
| + downscaleSamplingRate needs additional 3 bytes) */ |
| int eldExtLenDsc = 1; |
| int downscaleSamplingRate = config->downscaleSamplingRate; |
| FDKwriteBits(hBs, ELDEXT_DOWNSCALEINFO, 4); /* ELDEXT_DOWNSCALEINFO */ |
| |
| if ((downscaleSamplingRate != 96000) && (downscaleSamplingRate != 88200) && |
| (downscaleSamplingRate != 64000) && (downscaleSamplingRate != 48000) && |
| (downscaleSamplingRate != 44100) && (downscaleSamplingRate != 32000) && |
| (downscaleSamplingRate != 24000) && (downscaleSamplingRate != 22050) && |
| (downscaleSamplingRate != 16000) && (downscaleSamplingRate != 12000) && |
| (downscaleSamplingRate != 11025) && (downscaleSamplingRate != 8000) && |
| (downscaleSamplingRate != 7350)) { |
| eldExtLenDsc = 4; /* length extends to 4 if downscaleSamplingRate's value |
| is not one of the listed values */ |
| } |
| |
| FDKwriteBits(hBs, eldExtLenDsc, 4); |
| writeSampleRate(hBs, downscaleSamplingRate, 4); |
| FDKwriteBits(hBs, 0x0, 4); /* fill_nibble */ |
| } |
| |
| FDKwriteBits(hBs, ELDEXT_TERM, 4); /* ELDEXT_TERM */ |
| |
| return 0; |
| } |
| |
| static int transportEnc_writeUsacSpecificConfig(HANDLE_FDK_BITSTREAM hBs, |
| int extFlag, CODER_CONFIG *cc, |
| CSTpCallBacks *cb) { |
| FDK_BITSTREAM usacConf; |
| int usacConfigBits = cc->rawConfigBits; |
| |
| if ((usacConfigBits <= 0) || |
| ((usacConfigBits + 7) / 8 > (int)sizeof(cc->rawConfig))) { |
| return TRANSPORTENC_UNSUPPORTED_FORMAT; |
| } |
| FDKinitBitStream(&usacConf, cc->rawConfig, BUFSIZE_DUMMY_VALUE, |
| usacConfigBits, BS_READER); |
| |
| for (; usacConfigBits > 0; usacConfigBits--) { |
| UINT tmp = FDKreadBit(&usacConf); |
| FDKwriteBits(hBs, tmp, 1); |
| } |
| FDKsyncCache(hBs); |
| |
| return TRANSPORTENC_OK; |
| } |
| |
| int transportEnc_writeASC(HANDLE_FDK_BITSTREAM asc, CODER_CONFIG *config, |
| CSTpCallBacks *cb) { |
| UINT extFlag = 0; |
| int err; |
| int epConfig = 0; |
| |
| /* Required for the PCE. */ |
| UINT alignAnchor = FDKgetValidBits(asc); |
| |
| /* Extension Flag: Shall be 1 for aot = 17,19,20,21,22,23,39 */ |
| switch (config->aot) { |
| case AOT_ER_AAC_LC: |
| case AOT_ER_AAC_LTP: |
| case AOT_ER_AAC_SCAL: |
| case AOT_ER_TWIN_VQ: |
| case AOT_ER_BSAC: |
| case AOT_ER_AAC_LD: |
| case AOT_ER_AAC_ELD: |
| case AOT_USAC: |
| extFlag = 1; |
| break; |
| default: |
| break; |
| } |
| |
| if (config->sbrSignaling == SIG_EXPLICIT_HIERARCHICAL && config->sbrPresent) |
| writeAot(asc, config->extAOT); |
| else |
| writeAot(asc, config->aot); |
| |
| /* In case of USAC it is the output not the core sampling rate */ |
| writeSampleRate(asc, config->samplingRate, 4); |
| |
| /* Try to guess a reasonable channel mode if not given */ |
| if (config->channelMode == MODE_INVALID) { |
| config->channelMode = transportEnc_GetChannelMode(config->noChannels); |
| if (config->channelMode == MODE_INVALID) return -1; |
| } |
| |
| FDKwriteBits( |
| asc, getChannelConfig(config->channelMode, config->channelConfigZero), 4); |
| |
| if (config->sbrSignaling == SIG_EXPLICIT_HIERARCHICAL && config->sbrPresent) { |
| writeSampleRate(asc, config->extSamplingRate, 4); |
| writeAot(asc, config->aot); |
| } |
| |
| switch (config->aot) { |
| case AOT_AAC_MAIN: |
| case AOT_AAC_LC: |
| case AOT_AAC_SSR: |
| case AOT_AAC_LTP: |
| case AOT_AAC_SCAL: |
| case AOT_TWIN_VQ: |
| case AOT_ER_AAC_LC: |
| case AOT_ER_AAC_LTP: |
| case AOT_ER_AAC_SCAL: |
| case AOT_ER_TWIN_VQ: |
| case AOT_ER_BSAC: |
| case AOT_ER_AAC_LD: |
| err = |
| transportEnc_writeGASpecificConfig(asc, config, extFlag, alignAnchor); |
| if (err) return err; |
| break; |
| case AOT_ER_AAC_ELD: |
| err = transportEnc_writeELDSpecificConfig(asc, config, epConfig, cb); |
| if (err) return err; |
| break; |
| case AOT_USAC: |
| err = transportEnc_writeUsacSpecificConfig(asc, extFlag, config, cb); |
| if (err) { |
| return err; |
| } |
| break; |
| default: |
| return -1; |
| } |
| |
| switch (config->aot) { |
| case AOT_ER_AAC_LC: |
| case AOT_ER_AAC_LTP: |
| case AOT_ER_AAC_SCAL: |
| case AOT_ER_TWIN_VQ: |
| case AOT_ER_BSAC: |
| case AOT_ER_AAC_LD: |
| case AOT_ER_CELP: |
| case AOT_ER_HVXC: |
| case AOT_ER_HILN: |
| case AOT_ER_PARA: |
| case AOT_ER_AAC_ELD: |
| FDKwriteBits(asc, 0, 2); /* epconfig 0 */ |
| break; |
| default: |
| break; |
| } |
| |
| /* backward compatible explicit signaling of extension AOT */ |
| if (config->sbrSignaling == SIG_EXPLICIT_BW_COMPATIBLE) { |
| TP_ASC_EXTENSION_ID ascExtId = ASCEXT_UNKOWN; |
| |
| if (config->sbrPresent) { |
| ascExtId = ASCEXT_SBR; |
| FDKwriteBits(asc, ascExtId, 11); |
| writeAot(asc, config->extAOT); |
| FDKwriteBits(asc, 1, 1); /* sbrPresentFlag=1 */ |
| writeSampleRate(asc, config->extSamplingRate, 4); |
| if (config->psPresent) { |
| ascExtId = ASCEXT_PS; |
| FDKwriteBits(asc, ascExtId, 11); |
| FDKwriteBits(asc, 1, 1); /* psPresentFlag=1 */ |
| } |
| } |
| } |
| |
| /* Make sure all bits are sync'ed */ |
| FDKsyncCache(asc); |
| |
| return 0; |
| } |