123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484 |
- /* ***** 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"
- //#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 */
- //#define PROFILE
- #ifdef PROFILE
- #include "systime.h"
- #endif
- /**************************************************************************************
- * 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;
- }
- /**************************************************************************************
- * 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;
-
- #ifdef PROFILE
- long time;
- #endif
- 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;
-
- #ifdef PROFILE
- time = systime_get();
- #endif
- /* unpack side info */
- siBytes = UnpackSideInfo(mp3DecInfo, *inbuf);
- if (siBytes < 0) {
- MP3ClearBadFrame(mp3DecInfo, outbuf);
- return ERR_MP3_INVALID_SIDEINFO;
- }
- *inbuf += siBytes;
- *bytesLeft -= (fhBytes + siBytes);
- #ifdef PROFILE
- time = systime_get() - time;
- printf("UnpackSideInfo: %i ms\n", time);
- #endif
-
-
- /* 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;
- }
- #ifdef PROFILE
- time = systime_get();
- #endif
- /* 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;
- }
- #ifdef PROFILE
- time = systime_get() - time;
- printf("data buffer filling: %i ms\n", time);
- #endif
- }
- bitOffset = 0;
- mainBits = mp3DecInfo->mainDataBytes * 8;
- /* decode one complete frame */
- for (gr = 0; gr < mp3DecInfo->nGrans; gr++) {
- for (ch = 0; ch < mp3DecInfo->nChans; ch++) {
-
- #ifdef PROFILE
- time = systime_get();
- #endif
- /* unpack scale factors and compute size of scale factor block */
- prevBitOffset = bitOffset;
- offset = UnpackScaleFactors(mp3DecInfo, mainPtr, &bitOffset, mainBits, gr, ch);
- #ifdef PROFILE
- time = systime_get() - time;
- printf("UnpackScaleFactors: %i ms\n", time);
- #endif
- 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;
- }
- #ifdef PROFILE
- time = systime_get();
- #endif
- /* 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;
- }
- #ifdef PROFILE
- time = systime_get() - time;
- printf("Huffman: %i ms\n", time);
- #endif
- mainPtr += offset;
- mainBits -= (8*offset - prevBitOffset + bitOffset);
- }
-
- #ifdef PROFILE
- time = systime_get();
- #endif
- /* dequantize coefficients, decode stereo, reorder short blocks */
- if (Dequantize(mp3DecInfo, gr) < 0) {
- MP3ClearBadFrame(mp3DecInfo, outbuf);
- return ERR_MP3_INVALID_DEQUANTIZE;
- }
- #ifdef PROFILE
- time = systime_get() - time;
- printf("Dequantize: %i ms\n", time);
- #endif
- /* alias reduction, inverse MDCT, overlap-add, frequency inversion */
- for (ch = 0; ch < mp3DecInfo->nChans; ch++)
- {
- #ifdef PROFILE
- time = systime_get();
- #endif
- if (IMDCT(mp3DecInfo, gr, ch) < 0) {
- MP3ClearBadFrame(mp3DecInfo, outbuf);
- return ERR_MP3_INVALID_IMDCT;
- }
- #ifdef PROFILE
- time = systime_get() - time;
- printf("IMDCT: %i ms\n", time);
- #endif
- }
-
- #ifdef PROFILE
- time = systime_get();
- #endif
- /* 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;
- }
- #ifdef PROFILE
- time = systime_get() - time;
- printf("Subband: %i ms\n", time);
- #endif
-
- }
- return ERR_MP3_NONE;
- }
|