rt-thread-official/bsp/stm32_radio/mp3/mp3dec.c

418 lines
16 KiB
C

/* ***** BEGIN LICENSE BLOCK *****
* Version: RCSL 1.0/RPSL 1.0
*
* Portions Copyright (c) 1995-2002 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
* Version 1.0 (the "RPSL") available at
* http://www.helixcommunity.org/content/rpsl unless you have licensed
* the file under the RealNetworks Community Source License Version 1.0
* (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 MP3 decoder
* Jon Recker (jrecker@real.com), Ken Cooke (kenc@real.com)
* June 2003
*
* mp3dec.c - platform-independent top level MP3 decoder API
**************************************************************************************/
#include "string.h" // J.Sz. 21/04/2006
// #include "hlxclib/string.h" /* for memmove, memcpy (can replace with different implementations if desired) */
#include "mp3common.h" /* includes mp3dec.h (public API) and internal, platform-independent API */
/**************************************************************************************
* Function: MP3InitDecoder
*
* Description: allocate memory for platform-specific data
* clear all the user-accessible fields
*
* Inputs: none
*
* Outputs: none
*
* Return: handle to mp3 decoder instance, 0 if malloc fails
**************************************************************************************/
HMP3Decoder MP3InitDecoder(void)
{
MP3DecInfo *mp3DecInfo;
mp3DecInfo = AllocateBuffers();
return (HMP3Decoder)mp3DecInfo;
}
/**************************************************************************************
* Function: MP3FreeDecoder
*
* Description: free platform-specific data allocated by InitMP3Decoder
* zero out the contents of MP3DecInfo struct
*
* Inputs: valid MP3 decoder instance pointer (HMP3Decoder)
*
* Outputs: none
*
* Return: none
**************************************************************************************/
void MP3FreeDecoder(HMP3Decoder hMP3Decoder)
{
MP3DecInfo *mp3DecInfo = (MP3DecInfo *)hMP3Decoder;
if (!mp3DecInfo)
return;
FreeBuffers(mp3DecInfo);
}
/**************************************************************************************
* Function: MP3FindSyncWord
*
* Description: locate the next byte-alinged sync word in the raw mp3 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 MP3FindSyncWord(unsigned char *buf, int nBytes)
{
int i;
/* find byte-aligned syncword - need 12 (MPEG 1,2) or 11 (MPEG 2.5) matching bits */
for (i = 0; i < nBytes - 1; i++) {
if ( (buf[i+0] & SYNCWORDH) == SYNCWORDH && (buf[i+1] & SYNCWORDL) == SYNCWORDL )
return i;
}
return -1;
}
/**************************************************************************************
* Function: MP3FindFreeSync
*
* Description: figure out number of bytes between adjacent sync words in "free" mode
*
* Inputs: buffer to search for next sync word
* the 4-byte frame header starting at the current sync word
* max number of bytes to search in buffer
*
* Outputs: none
*
* Return: offset to next sync word, minus any pad byte (i.e. nSlots)
* -1 if sync not found after searching nBytes
*
* Notes: this checks that the first 22 bits of the next frame header are the
* same as the current frame header, but it's still not foolproof
* (could accidentally find a sequence in the bitstream which
* appears to match but is not actually the next frame header)
* this could be made more error-resilient by checking several frames
* in a row and verifying that nSlots is the same in each case
* since free mode requires CBR (see spec) we generally only call
* this function once (first frame) then store the result (nSlots)
* and just use it from then on
**************************************************************************************/
static int MP3FindFreeSync(unsigned char *buf, unsigned char firstFH[4], int nBytes)
{
int offset = 0;
unsigned char *bufPtr = buf;
/* loop until we either:
* - run out of nBytes (FindMP3SyncWord() returns -1)
* - find the next valid frame header (sync word, version, layer, CRC flag, bitrate, and sample rate
* in next header must match current header)
*/
while (1) {
offset = MP3FindSyncWord(bufPtr, nBytes);
bufPtr += offset;
if (offset < 0) {
return -1;
} else if ( (bufPtr[0] == firstFH[0]) && (bufPtr[1] == firstFH[1]) && ((bufPtr[2] & 0xfc) == (firstFH[2] & 0xfc)) ) {
/* want to return number of bytes per frame, NOT counting the padding byte, so subtract one if padFlag == 1 */
if ((firstFH[2] >> 1) & 0x01)
bufPtr--;
return bufPtr - buf;
}
bufPtr += 3;
nBytes -= (offset + 3);
};
// return -1; Removed KJ
}
/**************************************************************************************
* Function: MP3GetLastFrameInfo
*
* Description: get info about last MP3 frame decoded (number of sampled decoded,
* sample rate, bitrate, etc.)
*
* Inputs: valid MP3 decoder instance pointer (HMP3Decoder)
* pointer to MP3FrameInfo struct
*
* Outputs: filled-in MP3FrameInfo struct
*
* Return: none
*
* Notes: call this right after calling MP3Decode
**************************************************************************************/
void MP3GetLastFrameInfo(HMP3Decoder hMP3Decoder, MP3FrameInfo *mp3FrameInfo)
{
MP3DecInfo *mp3DecInfo = (MP3DecInfo *)hMP3Decoder;
if (!mp3DecInfo || mp3DecInfo->layer != 3) {
mp3FrameInfo->bitrate = 0;
mp3FrameInfo->nChans = 0;
mp3FrameInfo->samprate = 0;
mp3FrameInfo->bitsPerSample = 0;
mp3FrameInfo->outputSamps = 0;
mp3FrameInfo->layer = 0;
mp3FrameInfo->version = 0;
} else {
mp3FrameInfo->bitrate = mp3DecInfo->bitrate;
mp3FrameInfo->nChans = mp3DecInfo->nChans;
mp3FrameInfo->samprate = mp3DecInfo->samprate;
mp3FrameInfo->bitsPerSample = 16;
mp3FrameInfo->outputSamps = mp3DecInfo->nChans * (int)samplesPerFrameTab[mp3DecInfo->version][mp3DecInfo->layer - 1];
mp3FrameInfo->layer = mp3DecInfo->layer;
mp3FrameInfo->version = mp3DecInfo->version;
}
}
/**************************************************************************************
* Function: MP3GetNextFrameInfo
*
* Description: parse MP3 frame header
*
* Inputs: valid MP3 decoder instance pointer (HMP3Decoder)
* pointer to MP3FrameInfo struct
* pointer to buffer containing valid MP3 frame header (located using
* MP3FindSyncWord(), above)
*
* Outputs: filled-in MP3FrameInfo struct
*
* Return: error code, defined in mp3dec.h (0 means no error, < 0 means error)
**************************************************************************************/
int MP3GetNextFrameInfo(HMP3Decoder hMP3Decoder, MP3FrameInfo *mp3FrameInfo, unsigned char *buf)
{
MP3DecInfo *mp3DecInfo = (MP3DecInfo *)hMP3Decoder;
if (!mp3DecInfo)
return ERR_MP3_NULL_POINTER;
if (UnpackFrameHeader(mp3DecInfo, buf) == -1 || mp3DecInfo->layer != 3)
return ERR_MP3_INVALID_FRAMEHEADER;
MP3GetLastFrameInfo(mp3DecInfo, mp3FrameInfo);
return ERR_MP3_NONE;
}
/**************************************************************************************
* Function: MP3ClearBadFrame
*
* Description: zero out pcm buffer if error decoding MP3 frame
*
* Inputs: mp3DecInfo struct with correct frame size parameters filled in
* pointer pcm output buffer
*
* Outputs: zeroed out pcm buffer
*
* Return: none
**************************************************************************************/
static void MP3ClearBadFrame(MP3DecInfo *mp3DecInfo, short *outbuf)
{
int i;
if (!mp3DecInfo)
return;
for (i = 0; i < mp3DecInfo->nGrans * mp3DecInfo->nGranSamps * mp3DecInfo->nChans; i++)
outbuf[i] = 0;
}
/**************************************************************************************
* Function: MP3Decode
*
* Description: decode one frame of MP3 data
*
* Inputs: valid MP3 decoder instance pointer (HMP3Decoder)
* double pointer to buffer of MP3 data (containing headers + mainData)
* number of valid bytes remaining in inbuf
* pointer to outbuf, big enough to hold one frame of decoded PCM samples
* flag indicating whether MP3 data is normal MPEG format (useSize = 0)
* or reformatted as "self-contained" frames (useSize = 1)
*
* Outputs: PCM data in outbuf, interleaved LRLRLR... if stereo
* number of output samples = nGrans * nGranSamps * nChans
* updated inbuf pointer, updated bytesLeft
*
* Return: error code, defined in mp3dec.h (0 means no error, < 0 means error)
*
* Notes: switching useSize on and off between frames in the same stream
* is not supported (bit reservoir is not maintained if useSize on)
**************************************************************************************/
int MP3Decode(HMP3Decoder hMP3Decoder, unsigned char **inbuf, int *bytesLeft, short *outbuf, int useSize)
{
int offset, bitOffset, mainBits, gr, ch, fhBytes, siBytes, freeFrameBytes;
int prevBitOffset, sfBlockBits, huffBlockBits;
unsigned char *mainPtr;
MP3DecInfo *mp3DecInfo = (MP3DecInfo *)hMP3Decoder;
if (!mp3DecInfo)
return ERR_MP3_NULL_POINTER;
/* unpack frame header */
fhBytes = UnpackFrameHeader(mp3DecInfo, *inbuf);
if (fhBytes < 0)
return ERR_MP3_INVALID_FRAMEHEADER; /* don't clear outbuf since we don't know size (failed to parse header) */
*inbuf += fhBytes;
/* unpack side info */
siBytes = UnpackSideInfo(mp3DecInfo, *inbuf);
if (siBytes < 0) {
MP3ClearBadFrame(mp3DecInfo, outbuf);
return ERR_MP3_INVALID_SIDEINFO;
}
*inbuf += siBytes;
*bytesLeft -= (fhBytes + siBytes);
/* if free mode, need to calculate bitrate and nSlots manually, based on frame size */
if (mp3DecInfo->bitrate == 0 || mp3DecInfo->freeBitrateFlag) {
if (!mp3DecInfo->freeBitrateFlag) {
/* first time through, need to scan for next sync word and figure out frame size */
mp3DecInfo->freeBitrateFlag = 1;
mp3DecInfo->freeBitrateSlots = MP3FindFreeSync(*inbuf, *inbuf - fhBytes - siBytes, *bytesLeft);
if (mp3DecInfo->freeBitrateSlots < 0) {
MP3ClearBadFrame(mp3DecInfo, outbuf);
return ERR_MP3_FREE_BITRATE_SYNC;
}
freeFrameBytes = mp3DecInfo->freeBitrateSlots + fhBytes + siBytes;
mp3DecInfo->bitrate = (freeFrameBytes * mp3DecInfo->samprate * 8) / (mp3DecInfo->nGrans * mp3DecInfo->nGranSamps);
}
mp3DecInfo->nSlots = mp3DecInfo->freeBitrateSlots + CheckPadBit(mp3DecInfo); /* add pad byte, if required */
}
/* useSize != 0 means we're getting reformatted (RTP) packets (see RFC 3119)
* - calling function assembles "self-contained" MP3 frames by shifting any main_data
* from the bit reservoir (in previous frames) to AFTER the sync word and side info
* - calling function should set mainDataBegin to 0, and tell us exactly how large this
* frame is (in bytesLeft)
*/
if (useSize) {
mp3DecInfo->nSlots = *bytesLeft;
if (mp3DecInfo->mainDataBegin != 0 || mp3DecInfo->nSlots <= 0) {
/* error - non self-contained frame, or missing frame (size <= 0), could do loss concealment here */
MP3ClearBadFrame(mp3DecInfo, outbuf);
return ERR_MP3_INVALID_FRAMEHEADER;
}
/* can operate in-place on reformatted frames */
mp3DecInfo->mainDataBytes = mp3DecInfo->nSlots;
mainPtr = *inbuf;
*inbuf += mp3DecInfo->nSlots;
*bytesLeft -= (mp3DecInfo->nSlots);
} else {
/* out of data - assume last or truncated frame */
if (mp3DecInfo->nSlots > *bytesLeft) {
MP3ClearBadFrame(mp3DecInfo, outbuf);
return ERR_MP3_INDATA_UNDERFLOW;
}
/* fill main data buffer with enough new data for this frame */
if (mp3DecInfo->mainDataBytes >= mp3DecInfo->mainDataBegin) {
/* adequate "old" main data available (i.e. bit reservoir) */
memmove(mp3DecInfo->mainBuf, mp3DecInfo->mainBuf + mp3DecInfo->mainDataBytes - mp3DecInfo->mainDataBegin, mp3DecInfo->mainDataBegin);
memcpy(mp3DecInfo->mainBuf + mp3DecInfo->mainDataBegin, *inbuf, mp3DecInfo->nSlots);
mp3DecInfo->mainDataBytes = mp3DecInfo->mainDataBegin + mp3DecInfo->nSlots;
*inbuf += mp3DecInfo->nSlots;
*bytesLeft -= (mp3DecInfo->nSlots);
mainPtr = mp3DecInfo->mainBuf;
} else {
/* not enough data in bit reservoir from previous frames (perhaps starting in middle of file) */
memcpy(mp3DecInfo->mainBuf + mp3DecInfo->mainDataBytes, *inbuf, mp3DecInfo->nSlots);
mp3DecInfo->mainDataBytes += mp3DecInfo->nSlots;
*inbuf += mp3DecInfo->nSlots;
*bytesLeft -= (mp3DecInfo->nSlots);
MP3ClearBadFrame(mp3DecInfo, outbuf);
return ERR_MP3_MAINDATA_UNDERFLOW;
}
}
bitOffset = 0;
mainBits = mp3DecInfo->mainDataBytes * 8;
/* decode one complete frame */
for (gr = 0; gr < mp3DecInfo->nGrans; gr++) {
for (ch = 0; ch < mp3DecInfo->nChans; ch++) {
/* unpack scale factors and compute size of scale factor block */
prevBitOffset = bitOffset;
offset = UnpackScaleFactors(mp3DecInfo, mainPtr, &bitOffset, mainBits, gr, ch);
sfBlockBits = 8*offset - prevBitOffset + bitOffset;
huffBlockBits = mp3DecInfo->part23Length[gr][ch] - sfBlockBits;
mainPtr += offset;
mainBits -= sfBlockBits;
if (offset < 0 || mainBits < huffBlockBits) {
MP3ClearBadFrame(mp3DecInfo, outbuf);
return ERR_MP3_INVALID_SCALEFACT;
}
/* decode Huffman code words */
prevBitOffset = bitOffset;
offset = DecodeHuffman(mp3DecInfo, mainPtr, &bitOffset, huffBlockBits, gr, ch);
if (offset < 0) {
MP3ClearBadFrame(mp3DecInfo, outbuf);
return ERR_MP3_INVALID_HUFFCODES;
}
mainPtr += offset;
mainBits -= (8*offset - prevBitOffset + bitOffset);
}
/* dequantize coefficients, decode stereo, reorder short blocks */
if (Dequantize(mp3DecInfo, gr) < 0) {
MP3ClearBadFrame(mp3DecInfo, outbuf);
return ERR_MP3_INVALID_DEQUANTIZE;
}
/* alias reduction, inverse MDCT, overlap-add, frequency inversion */
for (ch = 0; ch < mp3DecInfo->nChans; ch++)
if (IMDCT(mp3DecInfo, gr, ch) < 0) {
MP3ClearBadFrame(mp3DecInfo, outbuf);
return ERR_MP3_INVALID_IMDCT;
}
/* subband transform - if stereo, interleaves pcm LRLRLR */
if (Subband(mp3DecInfo, outbuf + gr*mp3DecInfo->nGranSamps*mp3DecInfo->nChans) < 0) {
MP3ClearBadFrame(mp3DecInfo, outbuf);
return ERR_MP3_INVALID_SUBBAND;
}
}
return ERR_MP3_NONE;
}