/* ***** 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 "bitstream.h" #include #include "aacdec.h" #define HELIX_MAX_DECODE_CH_NUM (6) /************************************************************************************** * 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; } /************************************************************************************** * 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->format = 0; 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->format = aacDecInfo->format; 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; } } void AACGetDecoderInfo(HAACDecoder hAACDecoder, AACFrameInfo *aacFrameInfo) { AACDecInfo *aacDecInfo = (AACDecInfo *)hAACDecoder; if (aacDecInfo) { aacFrameInfo->format = aacDecInfo->format; 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; aacFrameInfo->total_byte_parsed = aacDecInfo->byteParsed; aacFrameInfo->total_sample_decoded = aacDecInfo->sampleDecoded; if (aacDecInfo->bitRate) { aacFrameInfo->bitRate = aacDecInfo->bitRate; } else if (aacDecInfo->sampleDecoded > 0) { aacFrameInfo->bitRate = (int)(((float)(aacDecInfo->byteParsed)) / ((float)aacDecInfo->sampleDecoded / (float)aacFrameInfo->sampRateOut)) << 3; } } } /************************************************************************************** * 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; aacDecInfo->audio_send_by_frame = aacFrameInfo->audio_send_by_frame; 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, baseChanSBR, elementChans; unsigned char *inptr; AACDecInfo *aacDecInfo = (AACDecInfo *)hAACDecoder; #ifdef AAC_ENABLE_SBR int 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; //printk("ADIF_DBG:ready step into UnpackADIFHeader()!\n"); err = UnpackADIFHeader(aacDecInfo, &inptr, &bitOffset, &bitsAvail); if (err) { return err; } } else { /* assume ADTS by default */ aacDecInfo->format = AAC_FF_ADTS; } } //printk("ADIF_DBG:aacDecInfo->format1=%d\n",aacDecInfo->format); /* 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*/1) { offset = AACFindSyncWord(inptr, bitsAvail >> 3); if (AACDataSource == 1) { if (offset < 0) { //not find sync word in current buffer return ERR_AAC_INVALID_ADTS_SYNCWORD; //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; } } //printk("ADIF_DBG:aacDecInfo->nChans=%d aacDecInfo->sampRate=%d\n",aacDecInfo->nChans,aacDecInfo->sampRate); /* check for valid number of channels */ if (aacDecInfo->nChans > AAC_MAX_NCHANS || aacDecInfo->nChans <= 0) { printk("AAC ERR: ERR_AAC_NCHANS_TOO_HIGH\n"); 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; baseChanSBR = 0; 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++) { err = DecodeNoiselessData(aacDecInfo, &inptr, &bitOffset, &bitsAvail, ch); if (err) { return err; } if (Dequantize(aacDecInfo, ch)) { return ERR_AAC_DEQUANT; } } /* mid-side and intensity stereo */ if (aacDecInfo->currBlockID == AAC_ID_CPE) { if (StereoProcess(aacDecInfo)) { return ERR_AAC_STEREO_PROCESS; } } /* PNS, TNS, inverse transform */ for (ch = 0; ch < elementChans; ch++) { if (PNS(aacDecInfo, ch)) { return ERR_AAC_PNS; } if (aacDecInfo->sbDeinterleaveReqd[ch]) { /* deinterleave short blocks, if required */ if (DeinterleaveShortBlocks(aacDecInfo, ch)) { return ERR_AAC_SHORT_BLOCK_DEINT; } aacDecInfo->sbDeinterleaveReqd[ch] = 0; } if (TNSFilter(aacDecInfo, ch)) { return ERR_AAC_TNS; } if (IMDCT(aacDecInfo, ch, baseChan + ch, outbuf)) { return ERR_AAC_IMDCT; } } #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 */ if (AACDataSource == 1) { aacDecInfo->frameCount++; aacDecInfo->byteParsed += inptr - *inbuf; //printk(" decode one frame cost byte %d \n",inptr - *inbuf); aacDecInfo->sampleDecoded += AAC_MAX_NSAMPS * (aacDecInfo->sbrEnabled ? 2 : 1); *bytesLeft -= (inptr - *inbuf); *inbuf = inptr; } else { aacDecInfo->frameCount++; aacDecInfo->byteParsed = CalcBitsUsed(0, 0, 0) >> 3; aacDecInfo->sampleDecoded += AAC_MAX_NSAMPS * (aacDecInfo->sbrEnabled ? 2 : 1); *bytesLeft -= (CalcBitsUsed(0, 0, 0) >> 3); // *inbuf = *inbuf+; } return ERR_AAC_NONE; }