mirror of
https://github.com/sle118/squeezelite-esp32.git
synced 2025-12-09 13:07:03 +03:00
497 lines
16 KiB
C
497 lines
16 KiB
C
/* ***** BEGIN LICENSE BLOCK *****
|
|
* Source last modified: $Id: filefmt.c,v 1.1 2005/02/26 01:47:34 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)
|
|
* February 2005
|
|
*
|
|
* filefmt.c - ADIF and ADTS header decoding, raw block handling
|
|
**************************************************************************************/
|
|
|
|
#include "coder.h"
|
|
|
|
/**************************************************************************************
|
|
* Function: UnpackADTSHeader
|
|
*
|
|
* Description: parse the ADTS frame header and initialize decoder state
|
|
*
|
|
* Inputs: valid AACDecInfo struct
|
|
* double pointer to buffer with complete ADTS frame header (byte aligned)
|
|
* header size = 7 bytes, plus 2 if CRC
|
|
*
|
|
* Outputs: filled in ADTS struct
|
|
* updated buffer pointer
|
|
* updated bit offset
|
|
* updated number of available bits
|
|
*
|
|
* Return: 0 if successful, error code (< 0) if error
|
|
*
|
|
* TODO: test CRC
|
|
* verify that fixed fields don't change between frames
|
|
**************************************************************************************/
|
|
int UnpackADTSHeader(AACDecInfo *aacDecInfo, unsigned char **buf, int *bitOffset, int *bitsAvail)
|
|
{
|
|
int bitsUsed;
|
|
PSInfoBase *psi;
|
|
BitStreamInfo bsi;
|
|
ADTSHeader *fhADTS;
|
|
|
|
/* validate pointers */
|
|
if (!aacDecInfo || !aacDecInfo->psInfoBase)
|
|
return ERR_AAC_NULL_POINTER;
|
|
psi = (PSInfoBase *)(aacDecInfo->psInfoBase);
|
|
fhADTS = &(psi->fhADTS);
|
|
|
|
/* init bitstream reader */
|
|
SetBitstreamPointer(&bsi, (*bitsAvail + 7) >> 3, *buf);
|
|
GetBits(&bsi, *bitOffset);
|
|
|
|
/* verify that first 12 bits of header are syncword */
|
|
if (GetBits(&bsi, 12) != 0x0fff) {
|
|
return ERR_AAC_INVALID_ADTS_HEADER;
|
|
}
|
|
|
|
/* fixed fields - should not change from frame to frame */
|
|
fhADTS->id = GetBits(&bsi, 1);
|
|
fhADTS->layer = GetBits(&bsi, 2);
|
|
fhADTS->protectBit = GetBits(&bsi, 1);
|
|
fhADTS->profile = GetBits(&bsi, 2);
|
|
fhADTS->sampRateIdx = GetBits(&bsi, 4);
|
|
fhADTS->privateBit = GetBits(&bsi, 1);
|
|
fhADTS->channelConfig = GetBits(&bsi, 3);
|
|
fhADTS->origCopy = GetBits(&bsi, 1);
|
|
fhADTS->home = GetBits(&bsi, 1);
|
|
|
|
/* variable fields - can change from frame to frame */
|
|
fhADTS->copyBit = GetBits(&bsi, 1);
|
|
fhADTS->copyStart = GetBits(&bsi, 1);
|
|
fhADTS->frameLength = GetBits(&bsi, 13);
|
|
fhADTS->bufferFull = GetBits(&bsi, 11);
|
|
fhADTS->numRawDataBlocks = GetBits(&bsi, 2) + 1;
|
|
|
|
/* note - MPEG4 spec, correction 1 changes how CRC is handled when protectBit == 0 and numRawDataBlocks > 1 */
|
|
if (fhADTS->protectBit == 0)
|
|
fhADTS->crcCheckWord = GetBits(&bsi, 16);
|
|
|
|
/* byte align */
|
|
ByteAlignBitstream(&bsi); /* should always be aligned anyway */
|
|
|
|
/* check validity of header */
|
|
if (fhADTS->layer != 0 || fhADTS->profile != AAC_PROFILE_LC ||
|
|
fhADTS->sampRateIdx >= NUM_SAMPLE_RATES || fhADTS->channelConfig >= NUM_DEF_CHAN_MAPS)
|
|
return ERR_AAC_INVALID_ADTS_HEADER;
|
|
|
|
#ifndef AAC_ENABLE_MPEG4
|
|
if (fhADTS->id != 1)
|
|
return ERR_AAC_MPEG4_UNSUPPORTED;
|
|
#endif
|
|
|
|
/* update codec info */
|
|
psi->sampRateIdx = fhADTS->sampRateIdx;
|
|
if (!psi->useImpChanMap)
|
|
psi->nChans = channelMapTab[fhADTS->channelConfig];
|
|
|
|
/* syntactic element fields will be read from bitstream for each element */
|
|
aacDecInfo->prevBlockID = AAC_ID_INVALID;
|
|
aacDecInfo->currBlockID = AAC_ID_INVALID;
|
|
aacDecInfo->currInstTag = -1;
|
|
|
|
/* fill in user-accessible data (TODO - calc bitrate, handle tricky channel config cases) */
|
|
aacDecInfo->bitRate = 0;
|
|
aacDecInfo->nChans = psi->nChans;
|
|
aacDecInfo->sampRate = sampRateTab[psi->sampRateIdx];
|
|
aacDecInfo->profile = fhADTS->profile;
|
|
aacDecInfo->sbrEnabled = 0;
|
|
aacDecInfo->adtsBlocksLeft = fhADTS->numRawDataBlocks;
|
|
|
|
/* update bitstream reader */
|
|
bitsUsed = CalcBitsUsed(&bsi, *buf, *bitOffset);
|
|
*buf += (bitsUsed + *bitOffset) >> 3;
|
|
*bitOffset = (bitsUsed + *bitOffset) & 0x07;
|
|
*bitsAvail -= bitsUsed ;
|
|
if (*bitsAvail < 0)
|
|
return ERR_AAC_INDATA_UNDERFLOW;
|
|
|
|
return ERR_AAC_NONE;
|
|
}
|
|
|
|
/**************************************************************************************
|
|
* Function: GetADTSChannelMapping
|
|
*
|
|
* Description: determine the number of channels from implicit mapping rules
|
|
*
|
|
* Inputs: valid AACDecInfo struct
|
|
* pointer to start of raw_data_block
|
|
* bit offset
|
|
* bits available
|
|
*
|
|
* Outputs: updated number of channels
|
|
*
|
|
* Return: 0 if successful, error code (< 0) if error
|
|
*
|
|
* Notes: calculates total number of channels using rules in 14496-3, 4.5.1.2.1
|
|
* does not attempt to deduce speaker geometry
|
|
**************************************************************************************/
|
|
int GetADTSChannelMapping(AACDecInfo *aacDecInfo, unsigned char *buf, int bitOffset, int bitsAvail)
|
|
{
|
|
int ch, nChans, elementChans, err;
|
|
PSInfoBase *psi;
|
|
|
|
/* validate pointers */
|
|
if (!aacDecInfo || !aacDecInfo->psInfoBase)
|
|
return ERR_AAC_NULL_POINTER;
|
|
psi = (PSInfoBase *)(aacDecInfo->psInfoBase);
|
|
|
|
nChans = 0;
|
|
do {
|
|
/* parse next syntactic element */
|
|
err = DecodeNextElement(aacDecInfo, &buf, &bitOffset, &bitsAvail);
|
|
if (err)
|
|
return err;
|
|
|
|
elementChans = elementNumChans[aacDecInfo->currBlockID];
|
|
nChans += elementChans;
|
|
|
|
for (ch = 0; ch < elementChans; ch++) {
|
|
err = DecodeNoiselessData(aacDecInfo, &buf, &bitOffset, &bitsAvail, ch);
|
|
if (err)
|
|
return err;
|
|
}
|
|
} while (aacDecInfo->currBlockID != AAC_ID_END);
|
|
|
|
if (nChans <= 0)
|
|
return ERR_AAC_CHANNEL_MAP;
|
|
|
|
/* update number of channels in codec state and user-accessible info structs */
|
|
psi->nChans = nChans;
|
|
aacDecInfo->nChans = psi->nChans;
|
|
psi->useImpChanMap = 1;
|
|
|
|
return ERR_AAC_NONE;
|
|
}
|
|
|
|
/**************************************************************************************
|
|
* Function: GetNumChannelsADIF
|
|
*
|
|
* Description: get number of channels from program config elements in an ADIF file
|
|
*
|
|
* Inputs: array of filled-in program config element structures
|
|
* number of PCE's
|
|
*
|
|
* Outputs: none
|
|
*
|
|
* Return: total number of channels in file
|
|
* -1 if error (invalid number of PCE's or unsupported mode)
|
|
**************************************************************************************/
|
|
static int GetNumChannelsADIF(ProgConfigElement *fhPCE, int nPCE)
|
|
{
|
|
int i, j, nChans;
|
|
|
|
if (nPCE < 1 || nPCE > MAX_NUM_PCE_ADIF)
|
|
return -1;
|
|
|
|
nChans = 0;
|
|
for (i = 0; i < nPCE; i++) {
|
|
/* for now: only support LC, no channel coupling */
|
|
if (fhPCE[i].profile != AAC_PROFILE_LC || fhPCE[i].numCCE > 0)
|
|
return -1;
|
|
|
|
/* add up number of channels in all channel elements (assume all single-channel) */
|
|
nChans += fhPCE[i].numFCE;
|
|
nChans += fhPCE[i].numSCE;
|
|
nChans += fhPCE[i].numBCE;
|
|
nChans += fhPCE[i].numLCE;
|
|
|
|
/* add one more for every element which is a channel pair */
|
|
for (j = 0; j < fhPCE[i].numFCE; j++) {
|
|
if (CHAN_ELEM_IS_CPE(fhPCE[i].fce[j]))
|
|
nChans++;
|
|
}
|
|
for (j = 0; j < fhPCE[i].numSCE; j++) {
|
|
if (CHAN_ELEM_IS_CPE(fhPCE[i].sce[j]))
|
|
nChans++;
|
|
}
|
|
for (j = 0; j < fhPCE[i].numBCE; j++) {
|
|
if (CHAN_ELEM_IS_CPE(fhPCE[i].bce[j]))
|
|
nChans++;
|
|
}
|
|
|
|
}
|
|
|
|
return nChans;
|
|
}
|
|
|
|
/**************************************************************************************
|
|
* Function: GetSampleRateIdxADIF
|
|
*
|
|
* Description: get sampling rate index from program config elements in an ADIF file
|
|
*
|
|
* Inputs: array of filled-in program config element structures
|
|
* number of PCE's
|
|
*
|
|
* Outputs: none
|
|
*
|
|
* Return: sample rate of file
|
|
* -1 if error (invalid number of PCE's or sample rate mismatch)
|
|
**************************************************************************************/
|
|
static int GetSampleRateIdxADIF(ProgConfigElement *fhPCE, int nPCE)
|
|
{
|
|
int i, idx;
|
|
|
|
if (nPCE < 1 || nPCE > MAX_NUM_PCE_ADIF)
|
|
return -1;
|
|
|
|
/* make sure all PCE's have the same sample rate */
|
|
idx = fhPCE[0].sampRateIdx;
|
|
for (i = 1; i < nPCE; i++) {
|
|
if (fhPCE[i].sampRateIdx != idx)
|
|
return -1;
|
|
}
|
|
|
|
return idx;
|
|
}
|
|
|
|
/**************************************************************************************
|
|
* Function: UnpackADIFHeader
|
|
*
|
|
* Description: parse the ADIF file header and initialize decoder state
|
|
*
|
|
* Inputs: valid AACDecInfo struct
|
|
* double pointer to buffer with complete ADIF header
|
|
* (starting at 'A' in 'ADIF' tag)
|
|
* pointer to bit offset
|
|
* pointer to number of valid bits remaining in inbuf
|
|
*
|
|
* Outputs: filled-in ADIF struct
|
|
* updated buffer pointer
|
|
* updated bit offset
|
|
* updated number of available bits
|
|
*
|
|
* Return: 0 if successful, error code (< 0) if error
|
|
**************************************************************************************/
|
|
int UnpackADIFHeader(AACDecInfo *aacDecInfo, unsigned char **buf, int *bitOffset, int *bitsAvail)
|
|
{
|
|
int i, bitsUsed;
|
|
PSInfoBase *psi;
|
|
BitStreamInfo bsi;
|
|
ADIFHeader *fhADIF;
|
|
ProgConfigElement *pce;
|
|
|
|
/* validate pointers */
|
|
if (!aacDecInfo || !aacDecInfo->psInfoBase)
|
|
return ERR_AAC_NULL_POINTER;
|
|
psi = (PSInfoBase *)(aacDecInfo->psInfoBase);
|
|
|
|
/* init bitstream reader */
|
|
SetBitstreamPointer(&bsi, (*bitsAvail + 7) >> 3, *buf);
|
|
GetBits(&bsi, *bitOffset);
|
|
|
|
/* unpack ADIF file header */
|
|
fhADIF = &(psi->fhADIF);
|
|
pce = psi->pce;
|
|
|
|
/* verify that first 32 bits of header are "ADIF" */
|
|
if (GetBits(&bsi, 8) != 'A' || GetBits(&bsi, 8) != 'D' || GetBits(&bsi, 8) != 'I' || GetBits(&bsi, 8) != 'F')
|
|
return ERR_AAC_INVALID_ADIF_HEADER;
|
|
|
|
/* read ADIF header fields */
|
|
fhADIF->copyBit = GetBits(&bsi, 1);
|
|
if (fhADIF->copyBit) {
|
|
for (i = 0; i < ADIF_COPYID_SIZE; i++)
|
|
fhADIF->copyID[i] = GetBits(&bsi, 8);
|
|
}
|
|
fhADIF->origCopy = GetBits(&bsi, 1);
|
|
fhADIF->home = GetBits(&bsi, 1);
|
|
fhADIF->bsType = GetBits(&bsi, 1);
|
|
fhADIF->bitRate = GetBits(&bsi, 23);
|
|
fhADIF->numPCE = GetBits(&bsi, 4) + 1; /* add 1 (so range = [1, 16]) */
|
|
if (fhADIF->bsType == 0)
|
|
fhADIF->bufferFull = GetBits(&bsi, 20);
|
|
|
|
/* parse all program config elements */
|
|
for (i = 0; i < fhADIF->numPCE; i++)
|
|
DecodeProgramConfigElement(pce + i, &bsi);
|
|
|
|
/* byte align */
|
|
ByteAlignBitstream(&bsi);
|
|
|
|
/* update codec info */
|
|
psi->nChans = GetNumChannelsADIF(pce, fhADIF->numPCE);
|
|
psi->sampRateIdx = GetSampleRateIdxADIF(pce, fhADIF->numPCE);
|
|
|
|
/* check validity of header */
|
|
if (psi->nChans < 0 || psi->sampRateIdx < 0 || psi->sampRateIdx >= NUM_SAMPLE_RATES)
|
|
return ERR_AAC_INVALID_ADIF_HEADER;
|
|
|
|
/* syntactic element fields will be read from bitstream for each element */
|
|
aacDecInfo->prevBlockID = AAC_ID_INVALID;
|
|
aacDecInfo->currBlockID = AAC_ID_INVALID;
|
|
aacDecInfo->currInstTag = -1;
|
|
|
|
/* fill in user-accessible data */
|
|
aacDecInfo->bitRate = 0;
|
|
aacDecInfo->nChans = psi->nChans;
|
|
aacDecInfo->sampRate = sampRateTab[psi->sampRateIdx];
|
|
aacDecInfo->profile = pce[0].profile;
|
|
aacDecInfo->sbrEnabled = 0;
|
|
|
|
/* update bitstream reader */
|
|
bitsUsed = CalcBitsUsed(&bsi, *buf, *bitOffset);
|
|
*buf += (bitsUsed + *bitOffset) >> 3;
|
|
*bitOffset = (bitsUsed + *bitOffset) & 0x07;
|
|
*bitsAvail -= bitsUsed ;
|
|
if (*bitsAvail < 0)
|
|
return ERR_AAC_INDATA_UNDERFLOW;
|
|
|
|
return ERR_AAC_NONE;
|
|
}
|
|
|
|
/**************************************************************************************
|
|
* Function: SetRawBlockParams
|
|
*
|
|
* Description: set internal state variables for decoding a stream of raw data blocks
|
|
*
|
|
* Inputs: valid AACDecInfo struct
|
|
* flag indicating source of parameters (from previous headers or passed
|
|
* explicitly by caller)
|
|
* number of channels
|
|
* sample rate
|
|
* profile ID
|
|
*
|
|
* Outputs: updated state variables in aacDecInfo
|
|
*
|
|
* Return: 0 if successful, error code (< 0) if error
|
|
*
|
|
* Notes: if copyLast == 1, then psi->nChans, psi->sampRateIdx, and
|
|
* aacDecInfo->profile are not changed (it's assumed that we already
|
|
* set them, such as by a previous call to UnpackADTSHeader())
|
|
* if copyLast == 0, then the parameters we passed in are used instead
|
|
**************************************************************************************/
|
|
int SetRawBlockParams(AACDecInfo *aacDecInfo, int copyLast, int nChans, int sampRate, int profile)
|
|
{
|
|
int idx;
|
|
PSInfoBase *psi;
|
|
|
|
/* validate pointers */
|
|
if (!aacDecInfo || !aacDecInfo->psInfoBase)
|
|
return ERR_AAC_NULL_POINTER;
|
|
psi = (PSInfoBase *)(aacDecInfo->psInfoBase);
|
|
|
|
if (!copyLast) {
|
|
aacDecInfo->profile = profile;
|
|
psi->nChans = nChans;
|
|
for (idx = 0; idx < NUM_SAMPLE_RATES; idx++) {
|
|
if (sampRate == sampRateTab[idx]) {
|
|
psi->sampRateIdx = idx;
|
|
break;
|
|
}
|
|
}
|
|
if (idx == NUM_SAMPLE_RATES)
|
|
return ERR_AAC_INVALID_FRAME;
|
|
}
|
|
aacDecInfo->nChans = psi->nChans;
|
|
aacDecInfo->sampRate = sampRateTab[psi->sampRateIdx];
|
|
|
|
/* check validity of header */
|
|
if (psi->sampRateIdx >= NUM_SAMPLE_RATES || psi->sampRateIdx < 0 || aacDecInfo->profile != AAC_PROFILE_LC)
|
|
return ERR_AAC_RAWBLOCK_PARAMS;
|
|
|
|
return ERR_AAC_NONE;
|
|
}
|
|
|
|
/**************************************************************************************
|
|
* Function: PrepareRawBlock
|
|
*
|
|
* Description: reset per-block state variables for raw blocks (no ADTS/ADIF headers)
|
|
*
|
|
* Inputs: valid AACDecInfo struct
|
|
*
|
|
* Outputs: updated state variables in aacDecInfo
|
|
*
|
|
* Return: 0 if successful, error code (< 0) if error
|
|
**************************************************************************************/
|
|
int PrepareRawBlock(AACDecInfo *aacDecInfo)
|
|
{
|
|
// PSInfoBase *psi;
|
|
|
|
/* validate pointers */
|
|
if (!aacDecInfo || !aacDecInfo->psInfoBase)
|
|
return ERR_AAC_NULL_POINTER;
|
|
// psi = (PSInfoBase *)(aacDecInfo->psInfoBase);
|
|
|
|
/* syntactic element fields will be read from bitstream for each element */
|
|
aacDecInfo->prevBlockID = AAC_ID_INVALID;
|
|
aacDecInfo->currBlockID = AAC_ID_INVALID;
|
|
aacDecInfo->currInstTag = -1;
|
|
|
|
/* fill in user-accessible data */
|
|
aacDecInfo->bitRate = 0;
|
|
aacDecInfo->sbrEnabled = 0;
|
|
|
|
return ERR_AAC_NONE;
|
|
}
|
|
|
|
/**************************************************************************************
|
|
* Function: FlushCodec
|
|
*
|
|
* Description: flush internal codec state (after seeking, for example)
|
|
*
|
|
* Inputs: valid AACDecInfo struct
|
|
*
|
|
* Outputs: updated state variables in aacDecInfo
|
|
*
|
|
* Return: 0 if successful, error code (< 0) if error
|
|
*
|
|
* Notes: only need to clear data which is persistent between frames
|
|
* (such as overlap buffer)
|
|
**************************************************************************************/
|
|
int FlushCodec(AACDecInfo *aacDecInfo)
|
|
{
|
|
PSInfoBase *psi;
|
|
|
|
/* validate pointers */
|
|
if (!aacDecInfo || !aacDecInfo->psInfoBase)
|
|
return ERR_AAC_NULL_POINTER;
|
|
psi = (PSInfoBase *)(aacDecInfo->psInfoBase);
|
|
|
|
ClearBuffer(psi->overlap, AAC_MAX_NCHANS * AAC_MAX_NSAMPS * sizeof(int));
|
|
ClearBuffer(psi->prevWinShape, AAC_MAX_NCHANS * sizeof(int));
|
|
|
|
return ERR_AAC_NONE;
|
|
}
|