mirror of
https://github.com/mstorsjo/fdk-aac.git
synced 2025-02-09 16:18:45 +01:00
- Update disclaimer in all source files. - Increment library version in each FDK sub-module. Bug 9428126 Change-Id: I490b96d4ee472246b01483202b0bb4f1e9c2a5d7
1029 lines
39 KiB
C++
1029 lines
39 KiB
C++
|
|
/* -----------------------------------------------------------------------------------------------------------
|
|
Software License for The Fraunhofer FDK AAC Codec Library for Android
|
|
|
|
© Copyright 1995 - 2013 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
|
|
----------------------------------------------------------------------------------------------------------- */
|
|
|
|
/*************************** Fast MPEG AAC Audio Encoder **********************
|
|
|
|
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"
|
|
|
|
|
|
|
|
|
|
#define MIN_BUFSIZE_PER_EFF_CHAN 6144
|
|
|
|
static AAC_ENCODER_ERROR FDKaacEnc_InitCheckAncillary(INT bitRate,
|
|
INT framelength,
|
|
INT ancillaryRate,
|
|
INT *ancillaryBitsPerFrame,
|
|
INT sampleRate);
|
|
|
|
INT FDKaacEnc_LimitBitrate(
|
|
HANDLE_TRANSPORTENC hTpEnc,
|
|
INT coreSamplingRate,
|
|
INT frameLength,
|
|
INT nChannels,
|
|
INT nChannelsEff,
|
|
INT bitRate,
|
|
INT averageBits,
|
|
INT *pAverageBitsPerFrame,
|
|
INT bitrateMode,
|
|
INT nSubFrames
|
|
)
|
|
{
|
|
INT transportBits, prevBitRate, averageBitsPerFrame, shift = 0, iter=0;
|
|
|
|
while ( (frameLength & ~((1<<(shift+1))-1)) == frameLength
|
|
&& (coreSamplingRate & ~((1<<(shift+1))-1)) == coreSamplingRate )
|
|
{
|
|
shift ++;
|
|
}
|
|
|
|
do {
|
|
prevBitRate = bitRate;
|
|
averageBitsPerFrame = (bitRate*(frameLength>>shift)) / (coreSamplingRate>>shift) / nSubFrames;
|
|
|
|
if (pAverageBitsPerFrame != NULL) {
|
|
*pAverageBitsPerFrame = averageBitsPerFrame;
|
|
}
|
|
|
|
if (hTpEnc != NULL) {
|
|
transportBits = transportEnc_GetStaticBits(hTpEnc, averageBitsPerFrame);
|
|
} else {
|
|
/* Assume some worst case */
|
|
transportBits = 208;
|
|
}
|
|
|
|
bitRate = FDKmax(bitRate, ((((40 * nChannels) + transportBits) * (coreSamplingRate)) / frameLength) );
|
|
FDK_ASSERT(bitRate >= 0);
|
|
|
|
bitRate = FDKmin(bitRate, ((nChannelsEff * MIN_BUFSIZE_PER_EFF_CHAN)*(coreSamplingRate>>shift)) / (frameLength>>shift)) ;
|
|
FDK_ASSERT(bitRate >= 0);
|
|
|
|
} while (prevBitRate != bitRate && iter++ < 3) ;
|
|
|
|
return bitRate;
|
|
}
|
|
|
|
|
|
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 = -1; /* Framesize not configured */
|
|
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 */
|
|
|
|
if (FDKaacEnc_LimitBitrate(
|
|
hTpEnc,
|
|
config->sampleRate,
|
|
config->framelength,
|
|
config->nChannels,
|
|
FDKaacEnc_GetChannelModeConfiguration(config->channelMode)->nChannelsEff,
|
|
config->bitRate,
|
|
config->averageBits,
|
|
&averageBitsPerFrame,
|
|
config->bitrateMode,
|
|
config->nSubFrames
|
|
) != config->bitRate )
|
|
{
|
|
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_ER_AAC_LD
|
|
|| config->audioObjectType == AOT_ER_AAC_ELD )
|
|
{
|
|
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;
|
|
}
|