aboutsummaryrefslogtreecommitdiffstats
path: root/libAACenc/src/aacenc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libAACenc/src/aacenc.cpp')
-rw-r--r--libAACenc/src/aacenc.cpp952
1 files changed, 952 insertions, 0 deletions
diff --git a/libAACenc/src/aacenc.cpp b/libAACenc/src/aacenc.cpp
new file mode 100644
index 0000000..5ab7192
--- /dev/null
+++ b/libAACenc/src/aacenc.cpp
@@ -0,0 +1,952 @@
+/*************************** Fast MPEG AAC Audio Encoder **********************
+
+ (C) Copyright Fraunhofer IIS (1999)
+ All Rights Reserved
+
+ Please be advised that this software and/or program delivery is
+ Confidential Information of Fraunhofer and subject to and covered by the
+
+ Fraunhofer IIS Software Evaluation Agreement
+ between Google Inc. and Fraunhofer
+ effective and in full force since March 1, 2012.
+
+ You may use this software and/or program only under the terms and
+ conditions described in the above mentioned Fraunhofer IIS Software
+ Evaluation Agreement. Any other and/or further use requires a separate agreement.
+
+
+ This software and/or program is protected by copyright law and international
+ treaties. Any reproduction or distribution of this software and/or program,
+ or any portion of it, may result in severe civil and criminal penalties, and
+ will be prosecuted to the maximum extent possible under law.
+
+ $Id$
+ Initial author: M. Schug / A. Groeschel
+ contents/description: fast aac coder functions
+
+******************************************************************************/
+
+#include "aacenc.h"
+
+#include "bitenc.h"
+#include "interface.h"
+#include "psy_configuration.h"
+#include "psy_main.h"
+#include "qc_main.h"
+#include "bandwidth.h"
+#include "channel_map.h"
+#include "tns_func.h"
+#include "aacEnc_ram.h"
+
+#include "genericStds.h"
+
+
+
+
+static AAC_ENCODER_ERROR FDKaacEnc_InitCheckAncillary(INT bitRate,
+ INT framelength,
+ INT ancillaryRate,
+ INT *ancillaryBitsPerFrame,
+ INT sampleRate);
+
+/**
+ * For calculating average bitrate of an access unit 32 bit data width is not sufficient
+ * in worst case. Therefore use scaling of the samplingrate parameter to keep complete information.
+ */
+typedef struct {
+ INT samplingRate;
+ UCHAR scalingFactor;
+} SR_SCALING_TAB;
+
+static const SR_SCALING_TAB samplingRateScalingTable[] =
+{
+ { 8000, 5 }, { 11025, 0 }, { 12000, 5 }, { 16000, 5 },
+ { 22050, 1 }, { 24000, 5 }, { 32000, 5 }, { 44100, 2 },
+ { 48000, 5 }, { 64000, 5 }, { 88200, 3 }, { 96000, 5 }
+};
+
+/**
+ * Get maximal scaling factor without losing samplingrate accuracy.
+ *
+ * \param samplingRate Samplingrate to be used.
+ * \return scaling value.
+ */
+static int GetSrSf(const INT samplingRate)
+{
+ int i, result = 0;
+
+ for (i=0; i<(int)(sizeof(samplingRateScalingTable)/sizeof(SR_SCALING_TAB)); i++) {
+ if ( samplingRateScalingTable[i].samplingRate == samplingRate ) {
+ result = samplingRateScalingTable[i].scalingFactor;
+ break;
+ }
+ }
+ return result;
+}
+
+#define MIN_BUFSIZE_PER_EFF_CHAN 6144
+
+typedef struct
+{
+ AACENC_BITRATE_MODE bitrateMode;
+ int chanBitrate[2]; /* mono/stereo settings */
+} CONFIG_TAB_ENTRY_VBR;
+
+static const CONFIG_TAB_ENTRY_VBR configTabVBR[] = {
+ {AACENC_BR_MODE_CBR, { 0, 0}} ,
+ {AACENC_BR_MODE_VBR_1, { 32000, 20000}} ,
+ {AACENC_BR_MODE_VBR_2, { 40000, 32000}} ,
+ {AACENC_BR_MODE_VBR_3, { 56000, 48000}} ,
+ {AACENC_BR_MODE_VBR_4, { 72000, 64000}} ,
+ {AACENC_BR_MODE_VBR_5, {112000, 96000}}
+};
+
+/*-----------------------------------------------------------------------------
+
+ functionname: FDKaacEnc_GetVBRBitrate
+ description: Get VBR bitrate from vbr quality
+ input params: int vbrQuality (VBR0, VBR1, VBR2)
+ channelMode
+ returns: vbr bitrate
+
+ ------------------------------------------------------------------------------*/
+INT FDKaacEnc_GetVBRBitrate(INT bitrateMode, CHANNEL_MODE channelMode)
+{
+ INT bitrate = 0;
+ INT monoStereoMode = 0; /* default mono */
+
+ if (FDKaacEnc_GetMonoStereoMode(channelMode)==EL_MODE_STEREO) {
+ monoStereoMode = 1;
+ }
+
+ switch((AACENC_BITRATE_MODE)bitrateMode){
+ case AACENC_BR_MODE_VBR_1:
+ case AACENC_BR_MODE_VBR_2:
+ case AACENC_BR_MODE_VBR_3:
+ case AACENC_BR_MODE_VBR_4:
+ case AACENC_BR_MODE_VBR_5:
+ bitrate = configTabVBR[bitrateMode].chanBitrate[monoStereoMode];
+ break;
+ case AACENC_BR_MODE_INVALID:
+ case AACENC_BR_MODE_CBR:
+ case AACENC_BR_MODE_SFR:
+ case AACENC_BR_MODE_FF:
+ default:
+ bitrate = 0;
+ break;
+ }
+
+ /* convert channel bitrate to overall bitrate*/
+ bitrate *= FDKaacEnc_GetChannelModeConfiguration(channelMode)->nChannelsEff;
+
+ return bitrate;
+}
+
+/**
+ * \brief Convert encoder bitreservoir value for transport library.
+ *
+ * \param bitrateMode Bitratemode used in current encoder instance. Se ::AACENC_BITRATE_MODE
+ * \param bitresTotal Encoder bitreservoir level in bits.
+ *
+ * \return Corrected bitreservoir level used in transport library.
+ */
+static INT FDKaacEnc_EncBitresToTpBitres(
+ const AACENC_BITRATE_MODE bitrateMode,
+ const INT bitresTotal
+ )
+{
+ INT transporBitreservoir = 0;
+
+ switch (bitrateMode) {
+ case AACENC_BR_MODE_CBR:
+ transporBitreservoir = bitresTotal; /* encoder bitreservoir level */
+ break;
+ case AACENC_BR_MODE_VBR_1:
+ case AACENC_BR_MODE_VBR_2:
+ case AACENC_BR_MODE_VBR_3:
+ case AACENC_BR_MODE_VBR_4:
+ case AACENC_BR_MODE_VBR_5:
+ transporBitreservoir = FDK_INT_MAX; /* signal variable bitrate */
+ break;
+ case AACENC_BR_MODE_FF:
+ case AACENC_BR_MODE_SFR:
+ transporBitreservoir = 0; /* super framing and fixed framing */
+ break; /* without bitreservoir signaling */
+ default:
+ case AACENC_BR_MODE_INVALID:
+ transporBitreservoir = 0; /* invalid configuration*/
+ FDK_ASSERT(0);
+ }
+
+ return transporBitreservoir;
+}
+
+/*-----------------------------------------------------------------------------
+
+ functionname: FDKaacEnc_AacInitDefaultConfig
+ description: gives reasonable default configuration
+ returns: ---
+
+ ------------------------------------------------------------------------------*/
+void FDKaacEnc_AacInitDefaultConfig(AACENC_CONFIG *config)
+{
+ /* make thepre initialization of the structs flexible */
+ FDKmemclear(config, sizeof(AACENC_CONFIG));
+
+ /* default ancillary */
+ config->anc_Rate = 0; /* no ancillary data */
+ config->ancDataBitRate = 0; /* no additional consumed bitrate */
+
+ /* default configurations */
+ config->bitRate = -1; /* bitrate must be set*/
+ config->averageBits = -1; /* instead of bitrate/s we can configure bits/superframe */
+ config->bitrateMode = 0;
+ config->bandWidth = 0; /* get bandwidth from table */
+ config->useTns = TNS_ENABLE_MASK; /* tns enabled completly */
+ config->usePns = 1; /* depending on channelBitrate this might be set to 0 later */
+ config->useIS = 1; /* Intensity Stereo Configuration */
+ config->framelength = DEFAULT_FRAMELENGTH; /* used frame size */
+ config->syntaxFlags = 0; /* default syntax with no specialities */
+ config->epConfig = -1; /* no ER syntax -> no additional error protection */
+ config->nSubFrames = 1; /* default, no sub frames */
+ config->channelOrder = CH_ORDER_MPEG; /* Use MPEG channel ordering. */
+ config->channelMode = MODE_UNKNOWN;
+ config->minBitsPerFrame = -1; /* minum number of bits in each AU */
+ config->maxBitsPerFrame = -1; /* minum number of bits in each AU */
+ config->bitreservoir = -1; /* default, uninitialized value */
+
+ /* init tabs in fixpoint_math */
+ InitLdInt();
+ InitInvSqrtTab();
+}
+
+
+/*---------------------------------------------------------------------------
+
+ functionname: FDKaacEnc_Open
+ description: allocate and initialize a new encoder instance
+ returns: error code
+
+ ---------------------------------------------------------------------------*/
+AAC_ENCODER_ERROR FDKaacEnc_Open(HANDLE_AAC_ENC *phAacEnc,
+ const INT nElements,
+ const INT nChannels,
+ const INT nSubFrames)
+{
+ AAC_ENCODER_ERROR ErrorStatus;
+ AAC_ENC *hAacEnc = NULL;
+ UCHAR *dynamicRAM = NULL;
+
+ if (phAacEnc==NULL) {
+ return AAC_ENC_INVALID_HANDLE;
+ }
+
+ /* allocate encoder structure */
+ hAacEnc = GetRam_aacEnc_AacEncoder();
+ if (hAacEnc == NULL) {
+ ErrorStatus = AAC_ENC_NO_MEMORY;
+ goto bail;
+ }
+ FDKmemclear(hAacEnc, sizeof(AAC_ENC));
+
+ hAacEnc->dynamic_RAM = GetAACdynamic_RAM();
+ dynamicRAM = (UCHAR*)hAacEnc->dynamic_RAM;
+
+ /* allocate the Psy aud Psy Out structure */
+ ErrorStatus = FDKaacEnc_PsyNew(&hAacEnc->psyKernel,
+ nElements,
+ nChannels
+ ,dynamicRAM
+ );
+ if (ErrorStatus != AAC_ENC_OK)
+ goto bail;
+
+ ErrorStatus = FDKaacEnc_PsyOutNew(hAacEnc->psyOut,
+ nElements,
+ nChannels,
+ nSubFrames
+ ,dynamicRAM
+ );
+ if (ErrorStatus != AAC_ENC_OK)
+ goto bail;
+
+ /* allocate the Q&C Out structure */
+ ErrorStatus = FDKaacEnc_QCOutNew(hAacEnc->qcOut,
+ nElements,
+ nChannels,
+ nSubFrames
+ ,dynamicRAM
+ );
+ if (ErrorStatus != AAC_ENC_OK)
+ goto bail;
+
+ /* allocate the Q&C kernel */
+ ErrorStatus = FDKaacEnc_QCNew(&hAacEnc->qcKernel,
+ nElements
+ ,dynamicRAM
+ );
+ if (ErrorStatus != AAC_ENC_OK)
+ goto bail;
+
+ hAacEnc->maxChannels = nChannels;
+ hAacEnc->maxElements = nElements;
+ hAacEnc->maxFrames = nSubFrames;
+
+bail:
+ *phAacEnc = hAacEnc;
+ return ErrorStatus;
+}
+
+
+AAC_ENCODER_ERROR FDKaacEnc_Initialize(HANDLE_AAC_ENC hAacEnc,
+ AACENC_CONFIG *config, /* pre-initialized config struct */
+ HANDLE_TRANSPORTENC hTpEnc,
+ ULONG initFlags)
+{
+ AAC_ENCODER_ERROR ErrorStatus;
+ INT psyBitrate, tnsMask; //INT profile = 1;
+ CHANNEL_MAPPING *cm = NULL;
+
+ INT qmbfac, qbw;
+ FIXP_DBL mbfac, bw_ratio;
+ QC_INIT qcInit;
+ INT averageBitsPerFrame = 0;
+
+ if (config==NULL)
+ return AAC_ENC_INVALID_HANDLE;
+
+ /******************* sanity checks *******************/
+
+ /* check config structure */
+ if (config->nChannels < 1 || config->nChannels > (6)) {
+ return AAC_ENC_UNSUPPORTED_CHANNELCONFIG;
+ }
+
+ /* check sample rate */
+ switch (config->sampleRate)
+ {
+ case 8000:
+ case 11025:
+ case 12000:
+ case 16000:
+ case 22050:
+ case 24000:
+ case 32000:
+ case 44100:
+ case 48000:
+ case 64000:
+ case 88200:
+ case 96000:
+ break;
+ default:
+ return AAC_ENC_UNSUPPORTED_SAMPLINGRATE;
+ }
+
+ /* bitrate has to be set */
+ if (config->bitRate==-1) {
+ return AAC_ENC_UNSUPPORTED_BITRATE;
+ }
+
+ /* check bit rate */
+
+ /* check if bitRate is not too low or high */
+ averageBitsPerFrame = (config->bitRate*(config->framelength>>GetSrSf(config->sampleRate))) / (config->sampleRate>>GetSrSf(config->sampleRate)) / config->nSubFrames;
+
+ /* assume minimum static bits of 40 in each channel. */
+ if ( (averageBitsPerFrame <= ((40*config->nChannels) + transportEnc_GetStaticBits(hTpEnc, averageBitsPerFrame))) ||
+ ( ((config->bitRate*(config->framelength>>GetSrSf(config->sampleRate)))) >
+ ((FDKaacEnc_GetChannelModeConfiguration(config->channelMode)->nChannelsEff * MIN_BUFSIZE_PER_EFF_CHAN))*(config->sampleRate>>GetSrSf(config->sampleRate)) )
+ )
+ {
+ return AAC_ENC_UNSUPPORTED_BITRATE;
+ }
+
+ if (config->syntaxFlags & AC_ER_VCB11) {
+ return AAC_ENC_UNSUPPORTED_ER_FORMAT;
+ }
+ if (config->syntaxFlags & AC_ER_HCR) {
+ return AAC_ENC_UNSUPPORTED_ER_FORMAT;
+ }
+
+ /* check frame length */
+ switch (config->framelength)
+ {
+ case 1024:
+ if ( config->audioObjectType != AOT_AAC_LC
+ && config->audioObjectType != AOT_SBR
+ && config->audioObjectType != AOT_PS
+ && config->audioObjectType != AOT_ER_AAC_LC
+ && config->audioObjectType != AOT_AAC_SCAL )
+ {
+ return AAC_ENC_INVALID_FRAME_LENGTH;
+ }
+ break;
+ case 512:
+ case 480:
+ if ( config->audioObjectType != AOT_ER_AAC_LD
+ && config->audioObjectType != AOT_ER_AAC_ELD )
+ {
+ return AAC_ENC_INVALID_FRAME_LENGTH;
+ }
+ break;
+ default:
+ return AAC_ENC_INVALID_FRAME_LENGTH;
+ }
+
+ if (config->anc_Rate != 0) {
+
+ ErrorStatus = FDKaacEnc_InitCheckAncillary(config->bitRate,
+ config->framelength,
+ config->anc_Rate,
+ &hAacEnc->ancillaryBitsPerFrame,
+ config->sampleRate);
+ if (ErrorStatus != AAC_ENC_OK)
+ goto bail;
+
+
+ /* update estimated consumed bitrate */
+ config->ancDataBitRate += ( (hAacEnc->ancillaryBitsPerFrame * config->sampleRate) / config->framelength );
+
+ }
+
+ /* maximal allowed DSE bytes in frame */
+ {
+ /* fixpoint calculation*/
+ INT q_res, encBitrate, sc;
+ FIXP_DBL tmp = fDivNorm(config->framelength, config->sampleRate, &q_res);
+ encBitrate = (config->bitRate/*-config->ancDataBitRate*/)- (INT)(config->nChannels*8000);
+ sc = CountLeadingBits(encBitrate);
+ config->maxAncBytesPerAU = FDKmin( (256), FDKmax(0,(INT)(fMultDiv2(tmp, (FIXP_DBL)(encBitrate<<sc))>>(-q_res+sc-1+3))) );
+ }
+
+ /* bind config to hAacEnc->config */
+ hAacEnc->config = config;
+
+ /* set hAacEnc->bitrateMode */
+ hAacEnc->bitrateMode = (AACENC_BITRATE_MODE)config->bitrateMode;
+
+ hAacEnc->encoderMode = config->channelMode;
+
+ ErrorStatus = FDKaacEnc_InitChannelMapping(hAacEnc->encoderMode, config->channelOrder, &hAacEnc->channelMapping);
+ if (ErrorStatus != AAC_ENC_OK)
+ goto bail;
+
+ cm = &hAacEnc->channelMapping;
+
+ ErrorStatus = FDKaacEnc_DetermineBandWidth(&hAacEnc->config->bandWidth,
+ config->bandWidth,
+ config->bitRate - config->ancDataBitRate,
+ hAacEnc->bitrateMode,
+ config->sampleRate,
+ config->framelength,
+ cm,
+ hAacEnc->encoderMode);
+ if (ErrorStatus != AAC_ENC_OK)
+ goto bail;
+
+ hAacEnc->bandwidth90dB = (INT)hAacEnc->config->bandWidth;
+
+ tnsMask = config->useTns ? TNS_ENABLE_MASK : 0x0;
+ psyBitrate = config->bitRate - config->ancDataBitRate;
+
+ ErrorStatus = FDKaacEnc_psyInit(hAacEnc->psyKernel,
+ hAacEnc->psyOut,
+ hAacEnc->maxFrames,
+ hAacEnc->maxChannels,
+ config->audioObjectType,
+ cm);
+ if (ErrorStatus != AAC_ENC_OK)
+ goto bail;
+
+ ErrorStatus = FDKaacEnc_psyMainInit(hAacEnc->psyKernel,
+ config->audioObjectType,
+ cm,
+ config->sampleRate,
+ config->framelength,
+ psyBitrate,
+ tnsMask,
+ hAacEnc->bandwidth90dB,
+ config->usePns,
+ config->useIS,
+ config->syntaxFlags,
+ initFlags);
+ if (ErrorStatus != AAC_ENC_OK)
+ goto bail;
+
+ ErrorStatus = FDKaacEnc_QCOutInit(hAacEnc->qcOut, hAacEnc->maxFrames, cm);
+ if (ErrorStatus != AAC_ENC_OK)
+ goto bail;
+
+
+
+ qcInit.channelMapping = &hAacEnc->channelMapping;
+ qcInit.sceCpe = 0;
+
+ {
+ int maxBitres;
+ qcInit.averageBits = (averageBitsPerFrame+7)&~7;
+ maxBitres = (MIN_BUFSIZE_PER_EFF_CHAN*cm->nChannelsEff) - qcInit.averageBits;
+ qcInit.bitRes = (config->bitreservoir!=-1) ? FDKmin(config->bitreservoir, maxBitres) : maxBitres;
+
+ qcInit.maxBits = fixMin(MIN_BUFSIZE_PER_EFF_CHAN*cm->nChannelsEff, ((averageBitsPerFrame+7)&~7)+qcInit.bitRes);
+ qcInit.maxBits = (config->maxBitsPerFrame!=-1) ? fixMin(qcInit.maxBits, config->maxBitsPerFrame) : qcInit.maxBits;
+
+ qcInit.minBits = fixMax(0, ((averageBitsPerFrame-1)&~7)-qcInit.bitRes-transportEnc_GetStaticBits(hTpEnc, ((averageBitsPerFrame+7)&~7)+qcInit.bitRes));
+ qcInit.minBits = (config->minBitsPerFrame!=-1) ? fixMax(qcInit.minBits, config->minBitsPerFrame) : qcInit.minBits;
+ }
+
+ qcInit.nSubFrames = config->nSubFrames;
+ qcInit.padding.paddingRest = config->sampleRate;
+
+ /* Calc meanPe */
+ bw_ratio = fDivNorm((FIXP_DBL)hAacEnc->bandwidth90dB, (FIXP_DBL)(config->sampleRate>>1), &qbw);
+ qbw = DFRACT_BITS-1-qbw;
+ /* qcInit.meanPe = 10.0f * FRAME_LEN_LONG * hAacEnc->bandwidth90dB/(config->sampleRate/2.0f); */
+ qcInit.meanPe = fMult(bw_ratio, (FIXP_DBL)((10*config->framelength)<<16)) >> (qbw-15);
+
+ /* Calc maxBitFac */
+ mbfac = fDivNorm((MIN_BUFSIZE_PER_EFF_CHAN-744)*cm->nChannelsEff, qcInit.averageBits/qcInit.nSubFrames, &qmbfac);
+ qmbfac = DFRACT_BITS-1-qmbfac;
+ qcInit.maxBitFac = (qmbfac > 24) ? (mbfac >> (qmbfac - 24)):(mbfac << (24 - qmbfac));
+
+ switch(config->bitrateMode){
+ case AACENC_BR_MODE_CBR:
+ qcInit.bitrateMode = QCDATA_BR_MODE_CBR;
+ break;
+ case AACENC_BR_MODE_VBR_1:
+ qcInit.bitrateMode = QCDATA_BR_MODE_VBR_1;
+ break;
+ case AACENC_BR_MODE_VBR_2:
+ qcInit.bitrateMode = QCDATA_BR_MODE_VBR_2;
+ break;
+ case AACENC_BR_MODE_VBR_3:
+ qcInit.bitrateMode = QCDATA_BR_MODE_VBR_3;
+ break;
+ case AACENC_BR_MODE_VBR_4:
+ qcInit.bitrateMode = QCDATA_BR_MODE_VBR_4;
+ break;
+ case AACENC_BR_MODE_VBR_5:
+ qcInit.bitrateMode = QCDATA_BR_MODE_VBR_5;
+ break;
+ case AACENC_BR_MODE_SFR:
+ qcInit.bitrateMode = QCDATA_BR_MODE_SFR;
+ break;
+ case AACENC_BR_MODE_FF:
+ qcInit.bitrateMode = QCDATA_BR_MODE_FF;
+ break;
+ default:
+ ErrorStatus = AAC_ENC_UNSUPPORTED_BITRATE_MODE;
+ goto bail;
+ }
+
+ qcInit.invQuant = (config->useRequant)?2:0;
+
+ /* maxIterations should be set to the maximum number of requantization iterations that are
+ * allowed before the crash recovery functionality is activated. This setting should be adjusted
+ * to the processing power available, i.e. to the processing power headroom in one frame that is
+ * still left after normal encoding without requantization. Please note that if activated this
+ * functionality is used most likely only in cases where the encoder is operating beyond
+ * recommended settings, i.e. the audio quality is suboptimal anyway. Activating the crash
+ * recovery does not further reduce audio quality significantly in these cases. */
+ if ( (config->audioObjectType == AOT_ER_AAC_LD) || (config->audioObjectType == AOT_ER_AAC_ELD) ) {
+ qcInit.maxIterations = 2;
+ }
+ else
+ {
+ qcInit.maxIterations = 5;
+ }
+
+ qcInit.bitrate = config->bitRate - config->ancDataBitRate;
+
+ qcInit.staticBits = transportEnc_GetStaticBits(hTpEnc, qcInit.averageBits/qcInit.nSubFrames);
+
+ ErrorStatus = FDKaacEnc_QCInit(hAacEnc->qcKernel, &qcInit);
+ if (ErrorStatus != AAC_ENC_OK)
+ goto bail;
+
+ /* Map virtual aot's to intern aot used in bitstream writer. */
+ switch (hAacEnc->config->audioObjectType) {
+ case AOT_MP2_AAC_LC:
+ case AOT_DABPLUS_AAC_LC:
+ hAacEnc->aot = AOT_AAC_LC;
+ break;
+ case AOT_MP2_SBR:
+ case AOT_DABPLUS_SBR:
+ hAacEnc->aot = AOT_SBR;
+ break;
+ case AOT_MP2_PS:
+ case AOT_DABPLUS_PS:
+ hAacEnc->aot = AOT_PS;
+ break;
+ default:
+ hAacEnc->aot = hAacEnc->config->audioObjectType;
+ }
+
+ /* common things */
+
+ return AAC_ENC_OK;
+
+bail:
+
+ return ErrorStatus;
+}
+
+
+/*---------------------------------------------------------------------------
+
+ functionname: FDKaacEnc_EncodeFrame
+ description: encodes one frame
+ returns: error code
+
+ ---------------------------------------------------------------------------*/
+AAC_ENCODER_ERROR FDKaacEnc_EncodeFrame( HANDLE_AAC_ENC hAacEnc, /* encoder handle */
+ HANDLE_TRANSPORTENC hTpEnc,
+ INT_PCM* RESTRICT inputBuffer,
+ INT* nOutBytes,
+ AACENC_EXT_PAYLOAD extPayload[MAX_TOTAL_EXT_PAYLOADS]
+ )
+{
+ AAC_ENCODER_ERROR ErrorStatus;
+ int el, n, c=0;
+ UCHAR extPayloadUsed[MAX_TOTAL_EXT_PAYLOADS];
+
+ CHANNEL_MAPPING *cm = &hAacEnc->channelMapping;
+
+
+
+ PSY_OUT *psyOut = hAacEnc->psyOut[c];
+ QC_OUT *qcOut = hAacEnc->qcOut[c];
+
+ FDKmemclear(extPayloadUsed, MAX_TOTAL_EXT_PAYLOADS * sizeof(UCHAR));
+
+ qcOut->elementExtBits = 0; /* sum up all extended bit of each element */
+ qcOut->staticBits = 0; /* sum up side info bits of each element */
+ qcOut->totalNoRedPe = 0; /* sum up PE */
+
+ /* advance psychoacoustics */
+ for (el=0; el<cm->nElements; el++) {
+ ELEMENT_INFO elInfo = cm->elInfo[el];
+
+ if ( (elInfo.elType == ID_SCE)
+ || (elInfo.elType == ID_CPE)
+ || (elInfo.elType == ID_LFE) )
+ {
+ int ch;
+
+ /* update pointer!*/
+ for(ch=0;ch<elInfo.nChannelsInEl;ch++) {
+ PSY_OUT_CHANNEL *psyOutChan = psyOut->psyOutElement[el]->psyOutChannel[ch];
+ QC_OUT_CHANNEL *qcOutChan = qcOut->qcElement[el]->qcOutChannel[ch];
+
+ psyOutChan->mdctSpectrum = qcOutChan->mdctSpectrum;
+ psyOutChan->sfbSpreadEnergy = qcOutChan->sfbSpreadEnergy;
+ psyOutChan->sfbEnergy = qcOutChan->sfbEnergy;
+ psyOutChan->sfbEnergyLdData = qcOutChan->sfbEnergyLdData;
+ psyOutChan->sfbMinSnrLdData = qcOutChan->sfbMinSnrLdData;
+ psyOutChan->sfbThresholdLdData = qcOutChan->sfbThresholdLdData;
+
+ }
+
+ FDKaacEnc_psyMain(elInfo.nChannelsInEl,
+ hAacEnc->psyKernel->psyElement[el],
+ hAacEnc->psyKernel->psyDynamic,
+ hAacEnc->psyKernel->psyConf,
+ psyOut->psyOutElement[el],
+ inputBuffer,
+ cm->elInfo[el].ChannelIndex,
+ cm->nChannels
+
+ );
+
+ /* FormFactor, Pe and staticBitDemand calculation */
+ ErrorStatus = FDKaacEnc_QCMainPrepare(&elInfo,
+ hAacEnc->qcKernel->hAdjThr->adjThrStateElem[el],
+ psyOut->psyOutElement[el],
+ qcOut->qcElement[el],
+ hAacEnc->aot,
+ hAacEnc->config->syntaxFlags,
+ hAacEnc->config->epConfig);
+
+ if (ErrorStatus != AAC_ENC_OK)
+ return ErrorStatus;
+
+ /*-------------------------------------------- */
+
+ qcOut->qcElement[el]->extBitsUsed = 0;
+ qcOut->qcElement[el]->nExtensions = 0;
+ /* reset extension payload */
+ FDKmemclear(&qcOut->qcElement[el]->extension, (1)*sizeof(QC_OUT_EXTENSION));
+
+ for ( n = 0; n < MAX_TOTAL_EXT_PAYLOADS; n++ ) {
+ if ( !extPayloadUsed[n]
+ && (extPayload[n].associatedChElement == el)
+ && (extPayload[n].dataSize > 0)
+ && (extPayload[n].pData != NULL) )
+ {
+ int idx = qcOut->qcElement[el]->nExtensions++;
+
+ qcOut->qcElement[el]->extension[idx].type = extPayload[n].dataType; /* Perform a sanity check on the type? */
+ qcOut->qcElement[el]->extension[idx].nPayloadBits = extPayload[n].dataSize;
+ qcOut->qcElement[el]->extension[idx].pPayload = extPayload[n].pData;
+ /* Now ask the bitstream encoder how many bits we need to encode the data with the current bitstream syntax: */
+ qcOut->qcElement[el]->extBitsUsed +=
+ FDKaacEnc_writeExtensionData( NULL,
+ &qcOut->qcElement[el]->extension[idx],
+ 0, 0,
+ hAacEnc->config->syntaxFlags,
+ hAacEnc->aot,
+ hAacEnc->config->epConfig );
+ extPayloadUsed[n] = 1;
+ }
+ }
+
+ /* sum up extension and static bits for all channel elements */
+ qcOut->elementExtBits += qcOut->qcElement[el]->extBitsUsed;
+ qcOut->staticBits += qcOut->qcElement[el]->staticBitsUsed;
+
+ /* sum up pe */
+ qcOut->totalNoRedPe += qcOut->qcElement[el]->peData.pe;
+ }
+ }
+
+ qcOut->nExtensions = 0;
+ qcOut->globalExtBits = 0;
+
+ /* reset extension payload */
+ FDKmemclear(&qcOut->extension, (2+2)*sizeof(QC_OUT_EXTENSION));
+
+ /* Add extension payload not assigned to an channel element
+ (Ancillary data is the only supported type up to now) */
+ for ( n = 0; n < MAX_TOTAL_EXT_PAYLOADS; n++ ) {
+ if ( !extPayloadUsed[n]
+ && (extPayload[n].associatedChElement == -1)
+ && (extPayload[n].pData != NULL) )
+ {
+ UINT payloadBits = 0;
+
+ if (extPayload[n].dataType == EXT_DATA_ELEMENT) {
+ if (hAacEnc->ancillaryBitsPerFrame) {
+ /* granted frame dse bitrate */
+ payloadBits = hAacEnc->ancillaryBitsPerFrame;
+ }
+ else {
+ /* write anc data if bitrate constraint fulfilled */
+ if ((extPayload[n].dataSize>>3) <= hAacEnc->config->maxAncBytesPerAU) {
+ payloadBits = extPayload[n].dataSize;
+ }
+ }
+ payloadBits = fixMin( extPayload[n].dataSize, payloadBits );
+ } else {
+ payloadBits = extPayload[n].dataSize;
+ }
+
+ if (payloadBits > 0)
+ {
+ int idx = qcOut->nExtensions++;
+
+ qcOut->extension[idx].type = extPayload[n].dataType; /* Perform a sanity check on the type? */
+ qcOut->extension[idx].nPayloadBits = payloadBits;
+ qcOut->extension[idx].pPayload = extPayload[n].pData;
+ /* Now ask the bitstream encoder how many bits we need to encode the data with the current bitstream syntax: */
+ qcOut->globalExtBits += FDKaacEnc_writeExtensionData( NULL,
+ &qcOut->extension[idx],
+ 0, 0,
+ hAacEnc->config->syntaxFlags,
+ hAacEnc->aot,
+ hAacEnc->config->epConfig );
+ if (extPayload[n].dataType == EXT_DATA_ELEMENT) {
+ /* substract the processed bits */
+ extPayload[n].dataSize -= payloadBits;
+ }
+ extPayloadUsed[n] = 1;
+ }
+ }
+ }
+
+ if (!(hAacEnc->config->syntaxFlags & (AC_SCALABLE|AC_ER))) {
+ qcOut->globalExtBits += EL_ID_BITS; /* add bits for ID_END */
+ }
+
+ /* build bitstream all nSubFrames */
+ {
+ INT totalBits = 0; /* Total AU bits */;
+ INT avgTotalBits = 0;
+
+ /*-------------------------------------------- */
+ /* Get average total bits */
+ /*-------------------------------------------- */
+ {
+ /* frame wise bitrate adaption */
+ FDKaacEnc_AdjustBitrate(hAacEnc->qcKernel,
+ cm,
+ &avgTotalBits,
+ hAacEnc->config->bitRate,
+ hAacEnc->config->sampleRate,
+ hAacEnc->config->framelength);
+
+ /* adjust super frame bitrate */
+ avgTotalBits *= hAacEnc->config->nSubFrames;
+ }
+
+ /* Make first estimate of transport header overhead.
+ Take maximum possible frame size into account to prevent bitreservoir underrun. */
+ hAacEnc->qcKernel->globHdrBits = transportEnc_GetStaticBits(hTpEnc, avgTotalBits + hAacEnc->qcKernel->bitResTot);
+
+
+ /*-------------------------------------------- */
+ /*-------------------------------------------- */
+ /*-------------------------------------------- */
+
+ ErrorStatus = FDKaacEnc_QCMain(hAacEnc->qcKernel,
+ hAacEnc->psyOut,
+ hAacEnc->qcOut,
+ avgTotalBits,
+ cm
+ ,hAacEnc->aot,
+ hAacEnc->config->syntaxFlags,
+ hAacEnc->config->epConfig);
+
+ if (ErrorStatus != AAC_ENC_OK)
+ return ErrorStatus;
+ /*-------------------------------------------- */
+
+ /*-------------------------------------------- */
+ ErrorStatus = FDKaacEnc_updateFillBits(cm,
+ hAacEnc->qcKernel,
+ hAacEnc->qcKernel->elementBits,
+ hAacEnc->qcOut);
+ if (ErrorStatus != AAC_ENC_OK)
+ return ErrorStatus;
+
+ /*-------------------------------------------- */
+ ErrorStatus = FDKaacEnc_FinalizeBitConsumption(cm,
+ hAacEnc->qcKernel,
+ qcOut,
+ qcOut->qcElement,
+ hTpEnc,
+ hAacEnc->aot,
+ hAacEnc->config->syntaxFlags,
+ hAacEnc->config->epConfig);
+ if (ErrorStatus != AAC_ENC_OK)
+ return ErrorStatus;
+ /*-------------------------------------------- */
+ totalBits += qcOut->totalBits;
+
+
+ /*-------------------------------------------- */
+ FDKaacEnc_updateBitres(cm,
+ hAacEnc->qcKernel,
+ hAacEnc->qcOut);
+
+ /*-------------------------------------------- */
+
+ /* for ( all sub frames ) ... */
+ /* write bitstream header */
+ transportEnc_WriteAccessUnit(
+ hTpEnc,
+ totalBits,
+ FDKaacEnc_EncBitresToTpBitres(hAacEnc->bitrateMode, hAacEnc->qcKernel->bitResTot),
+ cm->nChannelsEff);
+
+ /* write bitstream */
+ ErrorStatus = FDKaacEnc_WriteBitstream(
+ hTpEnc,
+ cm,
+ qcOut,
+ psyOut,
+ hAacEnc->qcKernel,
+ hAacEnc->aot,
+ hAacEnc->config->syntaxFlags,
+ hAacEnc->config->epConfig);
+
+ if (ErrorStatus != AAC_ENC_OK)
+ return ErrorStatus;
+
+ /* transportEnc_EndAccessUnit() is being called inside FDKaacEnc_WriteBitstream() */
+ transportEnc_GetFrame(hTpEnc, nOutBytes);
+
+ } /* -end- if (curFrame==hAacEnc->qcKernel->nSubFrames) */
+
+
+ /*-------------------------------------------- */
+ return AAC_ENC_OK;
+}
+
+/*---------------------------------------------------------------------------
+
+ functionname:FDKaacEnc_Close
+ description: delete encoder instance
+ returns:
+
+ ---------------------------------------------------------------------------*/
+
+void FDKaacEnc_Close( HANDLE_AAC_ENC* phAacEnc) /* encoder handle */
+{
+ if (*phAacEnc == NULL) {
+ return;
+ }
+ AAC_ENC *hAacEnc = (AAC_ENC*)*phAacEnc;
+
+ if (hAacEnc->dynamic_RAM != NULL)
+ FreeAACdynamic_RAM(&hAacEnc->dynamic_RAM);
+
+ FDKaacEnc_PsyClose(&hAacEnc->psyKernel,hAacEnc->psyOut);
+
+ FDKaacEnc_QCClose(&hAacEnc->qcKernel, hAacEnc->qcOut);
+
+ FreeRam_aacEnc_AacEncoder(phAacEnc);
+}
+
+
+/* The following functions are in this source file only for convenience and */
+/* need not be visible outside of a possible encoder library. */
+
+/* basic defines for ancillary data */
+#define MAX_ANCRATE 19200 /* ancillary rate >= 19200 isn't valid */
+
+/*---------------------------------------------------------------------------
+
+ functionname: FDKaacEnc_InitCheckAncillary
+ description: initialize and check ancillary data struct
+ return: if success or NULL if error
+
+ ---------------------------------------------------------------------------*/
+static AAC_ENCODER_ERROR FDKaacEnc_InitCheckAncillary(INT bitRate,
+ INT framelength,
+ INT ancillaryRate,
+ INT *ancillaryBitsPerFrame,
+ INT sampleRate)
+{
+ INT diffToByteAlign;
+
+ /* don't use negative ancillary rates */
+ if ( ancillaryRate < -1 )
+ return AAC_ENC_UNSUPPORTED_ANC_BITRATE;
+
+ /* check if ancillary rate is ok */
+ if ( (ancillaryRate != (-1)) && (ancillaryRate != 0) ) {
+ /* ancRate <= 15% of bitrate && ancRate < 19200 */
+ if ( ( ancillaryRate >= MAX_ANCRATE ) ||
+ ( (ancillaryRate * 20) > (bitRate * 3) ) ) {
+ return AAC_ENC_UNSUPPORTED_ANC_BITRATE;
+ }
+ }
+ else if (ancillaryRate == -1) {
+ /* if no special ancRate is requested but a ancillary file is
+ stated, then generate a ancillary rate matching to the bitrate */
+ if (bitRate >= (MAX_ANCRATE * 10)) {
+ /* ancillary rate is 19199 */
+ ancillaryRate = (MAX_ANCRATE - 1);
+ }
+ else { /* 10% of bitrate */
+ ancillaryRate = bitRate / 10;
+ }
+ }
+
+ /* make ancillaryBitsPerFrame byte align */
+ *ancillaryBitsPerFrame = (ancillaryRate * framelength ) / sampleRate;
+ diffToByteAlign = *ancillaryBitsPerFrame % 8;
+ *ancillaryBitsPerFrame = *ancillaryBitsPerFrame - diffToByteAlign;
+
+ return AAC_ENC_OK;
+}