mirror of
https://github.com/sle118/squeezelite-esp32.git
synced 2025-12-11 05:57:05 +03:00
big merge
This commit is contained in:
476
components/spotify/cspot/bell/libhelix-aac/aacdec.c
Normal file
476
components/spotify/cspot/bell/libhelix-aac/aacdec.c
Normal file
@@ -0,0 +1,476 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Source last modified: $Id: aacdec.c,v 1.1 2005/02/26 01:47:31 jrecker Exp $
|
||||
*
|
||||
* Portions Copyright (c) 1995-2005 RealNetworks, Inc. All Rights Reserved.
|
||||
*
|
||||
* The contents of this file, and the files included with this file,
|
||||
* are subject to the current version of the RealNetworks Public
|
||||
* Source License (the "RPSL") available at
|
||||
* http://www.helixcommunity.org/content/rpsl unless you have licensed
|
||||
* the file under the current version of the RealNetworks Community
|
||||
* Source License (the "RCSL") available at
|
||||
* http://www.helixcommunity.org/content/rcsl, in which case the RCSL
|
||||
* will apply. You may also obtain the license terms directly from
|
||||
* RealNetworks. You may not use this file except in compliance with
|
||||
* the RPSL or, if you have a valid RCSL with RealNetworks applicable
|
||||
* to this file, the RCSL. Please see the applicable RPSL or RCSL for
|
||||
* the rights, obligations and limitations governing use of the
|
||||
* contents of the file.
|
||||
*
|
||||
* This file is part of the Helix DNA Technology. RealNetworks is the
|
||||
* developer of the Original Code and owns the copyrights in the
|
||||
* portions it created.
|
||||
*
|
||||
* This file, and the files included with this file, is distributed
|
||||
* and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
|
||||
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
|
||||
* ENJOYMENT OR NON-INFRINGEMENT.
|
||||
*
|
||||
* Technology Compatibility Kit Test Suite(s) Location:
|
||||
* http://www.helixcommunity.org/content/tck
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/**************************************************************************************
|
||||
* Fixed-point HE-AAC decoder
|
||||
* Jon Recker (jrecker@real.com), Ken Cooke (kenc@real.com)
|
||||
* February 2005
|
||||
*
|
||||
* aacdec.c - platform-independent top level decoder API
|
||||
**************************************************************************************/
|
||||
|
||||
#include "aaccommon.h"
|
||||
|
||||
//#include "profile.h"
|
||||
|
||||
#define PROFILE_START(x)
|
||||
#define PROFILE_END()
|
||||
|
||||
/**************************************************************************************
|
||||
* Function: AACInitDecoder
|
||||
*
|
||||
* Description: allocate memory for platform-specific data
|
||||
* clear all the user-accessible fields
|
||||
* initialize SBR decoder if enabled
|
||||
*
|
||||
* Inputs: none
|
||||
*
|
||||
* Outputs: none
|
||||
*
|
||||
* Return: handle to AAC decoder instance, 0 if malloc fails
|
||||
**************************************************************************************/
|
||||
HAACDecoder AACInitDecoder(void)
|
||||
{
|
||||
AACDecInfo *aacDecInfo;
|
||||
|
||||
aacDecInfo = AllocateBuffers();
|
||||
if (!aacDecInfo)
|
||||
return 0;
|
||||
|
||||
#ifdef AAC_ENABLE_SBR
|
||||
if (InitSBR(aacDecInfo)) {
|
||||
AACFreeDecoder(aacDecInfo);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return (HAACDecoder)aacDecInfo;
|
||||
}
|
||||
|
||||
HAACDecoder AACInitDecoderPre(void *ptr, int sz)
|
||||
{
|
||||
AACDecInfo *aacDecInfo;
|
||||
|
||||
aacDecInfo = AllocateBuffersPre(&ptr, &sz);
|
||||
if (!aacDecInfo)
|
||||
return 0;
|
||||
|
||||
#ifdef AAC_ENABLE_SBR
|
||||
if (InitSBRPre(aacDecInfo, &ptr, &sz)) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return (HAACDecoder)aacDecInfo;
|
||||
}
|
||||
|
||||
/**************************************************************************************
|
||||
* Function: AACFreeDecoder
|
||||
*
|
||||
* Description: free platform-specific data allocated by AACInitDecoder
|
||||
* free SBR decoder if enabled
|
||||
*
|
||||
* Inputs: valid AAC decoder instance pointer (HAACDecoder)
|
||||
*
|
||||
* Outputs: none
|
||||
*
|
||||
* Return: none
|
||||
**************************************************************************************/
|
||||
void AACFreeDecoder(HAACDecoder hAACDecoder)
|
||||
{
|
||||
AACDecInfo *aacDecInfo = (AACDecInfo *)hAACDecoder;
|
||||
|
||||
if (!aacDecInfo)
|
||||
return;
|
||||
|
||||
#ifdef AAC_ENABLE_SBR
|
||||
FreeSBR(aacDecInfo);
|
||||
#endif
|
||||
FreeBuffers(aacDecInfo);
|
||||
}
|
||||
|
||||
/**************************************************************************************
|
||||
* Function: AACFindSyncWord
|
||||
*
|
||||
* Description: locate the next byte-alinged sync word in the raw AAC stream
|
||||
*
|
||||
* Inputs: buffer to search for sync word
|
||||
* max number of bytes to search in buffer
|
||||
*
|
||||
* Outputs: none
|
||||
*
|
||||
* Return: offset to first sync word (bytes from start of buf)
|
||||
* -1 if sync not found after searching nBytes
|
||||
**************************************************************************************/
|
||||
int AACFindSyncWord(unsigned char *buf, int nBytes)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* find byte-aligned syncword (12 bits = 0xFFF) */
|
||||
for (i = 0; i < nBytes - 1; i++) {
|
||||
if ( (buf[i+0] & SYNCWORDH) == SYNCWORDH && (buf[i+1] & SYNCWORDL) == SYNCWORDL )
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**************************************************************************************
|
||||
* Function: AACGetLastFrameInfo
|
||||
*
|
||||
* Description: get info about last AAC frame decoded (number of samples decoded,
|
||||
* sample rate, bit rate, etc.)
|
||||
*
|
||||
* Inputs: valid AAC decoder instance pointer (HAACDecoder)
|
||||
* pointer to AACFrameInfo struct
|
||||
*
|
||||
* Outputs: filled-in AACFrameInfo struct
|
||||
*
|
||||
* Return: none
|
||||
*
|
||||
* Notes: call this right after calling AACDecode()
|
||||
**************************************************************************************/
|
||||
void AACGetLastFrameInfo(HAACDecoder hAACDecoder, AACFrameInfo *aacFrameInfo)
|
||||
{
|
||||
AACDecInfo *aacDecInfo = (AACDecInfo *)hAACDecoder;
|
||||
|
||||
if (!aacDecInfo) {
|
||||
aacFrameInfo->bitRate = 0;
|
||||
aacFrameInfo->nChans = 0;
|
||||
aacFrameInfo->sampRateCore = 0;
|
||||
aacFrameInfo->sampRateOut = 0;
|
||||
aacFrameInfo->bitsPerSample = 0;
|
||||
aacFrameInfo->outputSamps = 0;
|
||||
aacFrameInfo->profile = 0;
|
||||
aacFrameInfo->tnsUsed = 0;
|
||||
aacFrameInfo->pnsUsed = 0;
|
||||
} else {
|
||||
aacFrameInfo->bitRate = aacDecInfo->bitRate;
|
||||
aacFrameInfo->nChans = aacDecInfo->nChans;
|
||||
aacFrameInfo->sampRateCore = aacDecInfo->sampRate;
|
||||
aacFrameInfo->sampRateOut = aacDecInfo->sampRate * (aacDecInfo->sbrEnabled ? 2 : 1);
|
||||
aacFrameInfo->bitsPerSample = 16;
|
||||
aacFrameInfo->outputSamps = aacDecInfo->nChans * AAC_MAX_NSAMPS * (aacDecInfo->sbrEnabled ? 2 : 1);
|
||||
aacFrameInfo->profile = aacDecInfo->profile;
|
||||
aacFrameInfo->tnsUsed = aacDecInfo->tnsUsed;
|
||||
aacFrameInfo->pnsUsed = aacDecInfo->pnsUsed;
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************************
|
||||
* Function: AACSetRawBlockParams
|
||||
*
|
||||
* Description: set internal state variables for decoding a stream of raw data blocks
|
||||
*
|
||||
* Inputs: valid AAC decoder instance pointer (HAACDecoder)
|
||||
* flag indicating source of parameters
|
||||
* AACFrameInfo struct, with the members nChans, sampRate, and profile
|
||||
* optionally filled-in
|
||||
*
|
||||
* Outputs: updated codec state
|
||||
*
|
||||
* Return: 0 if successful, error code (< 0) if error
|
||||
*
|
||||
* Notes: if copyLast == 1, then the codec sets up its internal state (for
|
||||
* decoding raw blocks) based on previously-decoded ADTS header info
|
||||
* if copyLast == 0, then the codec uses the values passed in
|
||||
* aacFrameInfo to configure its internal state (useful when the
|
||||
* source is MP4 format, for example)
|
||||
**************************************************************************************/
|
||||
int AACSetRawBlockParams(HAACDecoder hAACDecoder, int copyLast, AACFrameInfo *aacFrameInfo)
|
||||
{
|
||||
AACDecInfo *aacDecInfo = (AACDecInfo *)hAACDecoder;
|
||||
|
||||
if (!aacDecInfo)
|
||||
return ERR_AAC_NULL_POINTER;
|
||||
|
||||
aacDecInfo->format = AAC_FF_RAW;
|
||||
if (copyLast)
|
||||
return SetRawBlockParams(aacDecInfo, 1, 0, 0, 0);
|
||||
else
|
||||
return SetRawBlockParams(aacDecInfo, 0, aacFrameInfo->nChans, aacFrameInfo->sampRateCore, aacFrameInfo->profile);
|
||||
}
|
||||
|
||||
/**************************************************************************************
|
||||
* Function: AACFlushCodec
|
||||
*
|
||||
* Description: flush internal codec state (after seeking, for example)
|
||||
*
|
||||
* Inputs: valid AAC decoder instance pointer (HAACDecoder)
|
||||
*
|
||||
* Outputs: updated state variables in aacDecInfo
|
||||
*
|
||||
* Return: 0 if successful, error code (< 0) if error
|
||||
**************************************************************************************/
|
||||
int AACFlushCodec(HAACDecoder hAACDecoder)
|
||||
{
|
||||
int ch;
|
||||
AACDecInfo *aacDecInfo = (AACDecInfo *)hAACDecoder;
|
||||
|
||||
if (!aacDecInfo)
|
||||
return ERR_AAC_NULL_POINTER;
|
||||
|
||||
/* reset common state variables which change per-frame
|
||||
* don't touch state variables which are (usually) constant for entire clip
|
||||
* (nChans, sampRate, profile, format, sbrEnabled)
|
||||
*/
|
||||
aacDecInfo->prevBlockID = AAC_ID_INVALID;
|
||||
aacDecInfo->currBlockID = AAC_ID_INVALID;
|
||||
aacDecInfo->currInstTag = -1;
|
||||
for (ch = 0; ch < MAX_NCHANS_ELEM; ch++)
|
||||
aacDecInfo->sbDeinterleaveReqd[ch] = 0;
|
||||
aacDecInfo->adtsBlocksLeft = 0;
|
||||
aacDecInfo->tnsUsed = 0;
|
||||
aacDecInfo->pnsUsed = 0;
|
||||
|
||||
/* reset internal codec state (flush overlap buffers, etc.) */
|
||||
FlushCodec(aacDecInfo);
|
||||
#ifdef AAC_ENABLE_SBR
|
||||
FlushCodecSBR(aacDecInfo);
|
||||
#endif
|
||||
|
||||
return ERR_AAC_NONE;
|
||||
}
|
||||
|
||||
/**************************************************************************************
|
||||
* Function: AACDecode
|
||||
*
|
||||
* Description: decode AAC frame
|
||||
*
|
||||
* Inputs: valid AAC decoder instance pointer (HAACDecoder)
|
||||
* double pointer to buffer of AAC data
|
||||
* pointer to number of valid bytes remaining in inbuf
|
||||
* pointer to outbuf, big enough to hold one frame of decoded PCM samples
|
||||
* (outbuf must be double-sized if SBR enabled)
|
||||
*
|
||||
* Outputs: PCM data in outbuf, interleaved LRLRLR... if stereo
|
||||
* number of output samples = 1024 per channel (2048 if SBR enabled)
|
||||
* updated inbuf pointer
|
||||
* updated bytesLeft
|
||||
*
|
||||
* Return: 0 if successful, error code (< 0) if error
|
||||
*
|
||||
* Notes: inbuf pointer and bytesLeft are not updated until whole frame is
|
||||
* successfully decoded, so if ERR_AAC_INDATA_UNDERFLOW is returned
|
||||
* just call AACDecode again with more data in inbuf
|
||||
**************************************************************************************/
|
||||
int AACDecode(HAACDecoder hAACDecoder, unsigned char **inbuf, int *bytesLeft, short *outbuf)
|
||||
{
|
||||
int err, offset, bitOffset, bitsAvail;
|
||||
int ch, baseChan, elementChans;
|
||||
unsigned char *inptr;
|
||||
AACDecInfo *aacDecInfo = (AACDecInfo *)hAACDecoder;
|
||||
#ifdef AAC_ENABLE_SBR
|
||||
int baseChanSBR, elementChansSBR;
|
||||
#endif
|
||||
|
||||
if (!aacDecInfo)
|
||||
return ERR_AAC_NULL_POINTER;
|
||||
|
||||
/* make local copies (see "Notes" above) */
|
||||
inptr = *inbuf;
|
||||
bitOffset = 0;
|
||||
bitsAvail = (*bytesLeft) << 3;
|
||||
|
||||
/* first time through figure out what the file format is */
|
||||
if (aacDecInfo->format == AAC_FF_Unknown) {
|
||||
if (bitsAvail < 32)
|
||||
return ERR_AAC_INDATA_UNDERFLOW;
|
||||
|
||||
if (IS_ADIF(inptr)) {
|
||||
/* unpack ADIF header */
|
||||
aacDecInfo->format = AAC_FF_ADIF;
|
||||
err = UnpackADIFHeader(aacDecInfo, &inptr, &bitOffset, &bitsAvail);
|
||||
if (err)
|
||||
return err;
|
||||
} else {
|
||||
/* assume ADTS by default */
|
||||
aacDecInfo->format = AAC_FF_ADTS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* if ADTS, search for start of next frame */
|
||||
if (aacDecInfo->format == AAC_FF_ADTS) {
|
||||
/* can have 1-4 raw data blocks per ADTS frame (header only present for first one) */
|
||||
if (aacDecInfo->adtsBlocksLeft == 0) {
|
||||
offset = AACFindSyncWord(inptr, bitsAvail >> 3);
|
||||
if (offset < 0)
|
||||
return ERR_AAC_INDATA_UNDERFLOW;
|
||||
inptr += offset;
|
||||
bitsAvail -= (offset << 3);
|
||||
|
||||
err = UnpackADTSHeader(aacDecInfo, &inptr, &bitOffset, &bitsAvail);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (aacDecInfo->nChans == -1) {
|
||||
/* figure out implicit channel mapping if necessary */
|
||||
err = GetADTSChannelMapping(aacDecInfo, inptr, bitOffset, bitsAvail);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
aacDecInfo->adtsBlocksLeft--;
|
||||
} else if (aacDecInfo->format == AAC_FF_RAW) {
|
||||
err = PrepareRawBlock(aacDecInfo);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* check for valid number of channels */
|
||||
if (aacDecInfo->nChans > AAC_MAX_NCHANS || aacDecInfo->nChans <= 0)
|
||||
return ERR_AAC_NCHANS_TOO_HIGH;
|
||||
|
||||
/* will be set later if active in this frame */
|
||||
aacDecInfo->tnsUsed = 0;
|
||||
aacDecInfo->pnsUsed = 0;
|
||||
|
||||
bitOffset = 0;
|
||||
baseChan = 0;
|
||||
#ifdef AAC_ENABLE_SBR
|
||||
baseChanSBR = 0;
|
||||
#endif
|
||||
do {
|
||||
|
||||
|
||||
|
||||
/* parse next syntactic element */
|
||||
err = DecodeNextElement(aacDecInfo, &inptr, &bitOffset, &bitsAvail);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
elementChans = elementNumChans[aacDecInfo->currBlockID];
|
||||
if (baseChan + elementChans > AAC_MAX_NCHANS)
|
||||
return ERR_AAC_NCHANS_TOO_HIGH;
|
||||
|
||||
/* noiseless decoder and dequantizer */
|
||||
for (ch = 0; ch < elementChans; ch++) {
|
||||
PROFILE_START("noiseless decoder");
|
||||
err = DecodeNoiselessData(aacDecInfo, &inptr, &bitOffset, &bitsAvail, ch);
|
||||
PROFILE_END();
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
PROFILE_START("dequant");
|
||||
if (Dequantize(aacDecInfo, ch))
|
||||
return ERR_AAC_DEQUANT;
|
||||
PROFILE_END();
|
||||
}
|
||||
|
||||
PROFILE_START("mid-side and intensity stereo");
|
||||
/* mid-side and intensity stereo */
|
||||
if (aacDecInfo->currBlockID == AAC_ID_CPE) {
|
||||
if (StereoProcess(aacDecInfo))
|
||||
return ERR_AAC_STEREO_PROCESS;
|
||||
}
|
||||
PROFILE_END();
|
||||
|
||||
|
||||
/* PNS, TNS, inverse transform */
|
||||
for (ch = 0; ch < elementChans; ch++) {
|
||||
PROFILE_START("PNS");
|
||||
if (PNS(aacDecInfo, ch))
|
||||
return ERR_AAC_PNS;
|
||||
PROFILE_END();
|
||||
|
||||
if (aacDecInfo->sbDeinterleaveReqd[ch]) {
|
||||
/* deinterleave short blocks, if required */
|
||||
if (DeinterleaveShortBlocks(aacDecInfo, ch))
|
||||
return ERR_AAC_SHORT_BLOCK_DEINT;
|
||||
aacDecInfo->sbDeinterleaveReqd[ch] = 0;
|
||||
}
|
||||
|
||||
PROFILE_START("TNS");
|
||||
if (TNSFilter(aacDecInfo, ch))
|
||||
return ERR_AAC_TNS;
|
||||
PROFILE_END();
|
||||
|
||||
PROFILE_START("IMDCT");
|
||||
if (IMDCT(aacDecInfo, ch, baseChan + ch, outbuf))
|
||||
return ERR_AAC_IMDCT;
|
||||
PROFILE_END();
|
||||
}
|
||||
|
||||
#ifdef AAC_ENABLE_SBR
|
||||
if (aacDecInfo->sbrEnabled && (aacDecInfo->currBlockID == AAC_ID_FIL || aacDecInfo->currBlockID == AAC_ID_LFE)) {
|
||||
if (aacDecInfo->currBlockID == AAC_ID_LFE)
|
||||
elementChansSBR = elementNumChans[AAC_ID_LFE];
|
||||
else if (aacDecInfo->currBlockID == AAC_ID_FIL && (aacDecInfo->prevBlockID == AAC_ID_SCE || aacDecInfo->prevBlockID == AAC_ID_CPE))
|
||||
elementChansSBR = elementNumChans[aacDecInfo->prevBlockID];
|
||||
else
|
||||
elementChansSBR = 0;
|
||||
|
||||
if (baseChanSBR + elementChansSBR > AAC_MAX_NCHANS)
|
||||
return ERR_AAC_SBR_NCHANS_TOO_HIGH;
|
||||
|
||||
/* parse SBR extension data if present (contained in a fill element) */
|
||||
if (DecodeSBRBitstream(aacDecInfo, baseChanSBR))
|
||||
return ERR_AAC_SBR_BITSTREAM;
|
||||
|
||||
/* apply SBR */
|
||||
if (DecodeSBRData(aacDecInfo, baseChanSBR, outbuf))
|
||||
return ERR_AAC_SBR_DATA;
|
||||
|
||||
baseChanSBR += elementChansSBR;
|
||||
}
|
||||
#endif
|
||||
|
||||
baseChan += elementChans;
|
||||
} while (aacDecInfo->currBlockID != AAC_ID_END);
|
||||
|
||||
/* byte align after each raw_data_block */
|
||||
if (bitOffset) {
|
||||
inptr++;
|
||||
bitsAvail -= (8-bitOffset);
|
||||
bitOffset = 0;
|
||||
if (bitsAvail < 0)
|
||||
return ERR_AAC_INDATA_UNDERFLOW;
|
||||
}
|
||||
|
||||
/* update pointers */
|
||||
aacDecInfo->frameCount++;
|
||||
*bytesLeft -= (inptr - *inbuf);
|
||||
*inbuf = inptr;
|
||||
|
||||
return ERR_AAC_NONE;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user