summaryrefslogtreecommitdiffstats
path: root/fdk-aac/libMpegTPEnc/src/tpenc_asc.cpp
diff options
context:
space:
mode:
authorMatthias P. Braendli <matthias.braendli@mpb.li>2019-11-11 11:38:02 +0100
committerMatthias P. Braendli <matthias.braendli@mpb.li>2019-11-11 11:38:02 +0100
commit0e5af65c467b2423a0b857ae3ad98c91acc1e190 (patch)
treed07f69550d8886271e44fe79c4dcfb299cafbd38 /fdk-aac/libMpegTPEnc/src/tpenc_asc.cpp
parentefe406d9724f959c8bc2a31802559ca6d41fd897 (diff)
downloadODR-AudioEnc-0e5af65c467b2423a0b857ae3ad98c91acc1e190.tar.gz
ODR-AudioEnc-0e5af65c467b2423a0b857ae3ad98c91acc1e190.tar.bz2
ODR-AudioEnc-0e5af65c467b2423a0b857ae3ad98c91acc1e190.zip
Include patched FDK-AAC in the repository
The initial idea was to get the DAB+ patch into upstream, but since that follows the android source releases, there is no place for a custom DAB+ patch there. So instead of having to maintain a patched fdk-aac that has to have the same .so version as the distribution package on which it is installed, we prefer having a separate fdk-aac-dab library to avoid collision. At that point, there's no reason to keep fdk-aac in a separate repository, as odr-audioenc is the only tool that needs DAB+ encoding support. Including it here simplifies installation, and makes it consistent with toolame-dab, also shipped in this repository. DAB+ decoding support (needed by ODR-SourceCompanion, dablin, etisnoop, welle.io and others) can be done using upstream FDK-AAC.
Diffstat (limited to 'fdk-aac/libMpegTPEnc/src/tpenc_asc.cpp')
-rw-r--r--fdk-aac/libMpegTPEnc/src/tpenc_asc.cpp996
1 files changed, 996 insertions, 0 deletions
diff --git a/fdk-aac/libMpegTPEnc/src/tpenc_asc.cpp b/fdk-aac/libMpegTPEnc/src/tpenc_asc.cpp
new file mode 100644
index 0000000..0b484a0
--- /dev/null
+++ b/fdk-aac/libMpegTPEnc/src/tpenc_asc.cpp
@@ -0,0 +1,996 @@
+/* -----------------------------------------------------------------------------
+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, 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, 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;
+}