diff options
Diffstat (limited to 'circuitpython/lib/mp3/src/bitstream.c')
-rw-r--r-- | circuitpython/lib/mp3/src/bitstream.c | 389 |
1 files changed, 389 insertions, 0 deletions
diff --git a/circuitpython/lib/mp3/src/bitstream.c b/circuitpython/lib/mp3/src/bitstream.c new file mode 100644 index 0000000..608c39c --- /dev/null +++ b/circuitpython/lib/mp3/src/bitstream.c @@ -0,0 +1,389 @@ +/* ***** 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 + * + * bitstream.c - bitstream unpacking, frame header parsing, side info parsing + **************************************************************************************/ + +#include "coder.h" +#include "assembly.h" + +/************************************************************************************** + * Function: SetBitstreamPointer + * + * Description: initialize bitstream reader + * + * Inputs: pointer to BitStreamInfo struct + * number of bytes in bitstream + * pointer to byte-aligned buffer of data to read from + * + * Outputs: filled bitstream info struct + * + * Return: none + **************************************************************************************/ +void SetBitstreamPointer(BitStreamInfo *bsi, int nBytes, unsigned char *buf) +{ + /* init bitstream */ + bsi->bytePtr = buf; + bsi->iCache = 0; /* 4-byte unsigned int */ + bsi->cachedBits = 0; /* i.e. zero bits in cache */ + bsi->nBytes = nBytes; +} + +/************************************************************************************** + * Function: RefillBitstreamCache + * + * Description: read new data from bitstream buffer into bsi cache + * + * Inputs: pointer to initialized BitStreamInfo struct + * + * Outputs: updated bitstream info struct + * + * Return: none + * + * Notes: only call when iCache is completely drained (resets bitOffset to 0) + * always loads 4 new bytes except when bsi->nBytes < 4 (end of buffer) + * stores data as big-endian in cache, regardless of machine endian-ness + * + * TODO: optimize for ARM + * possibly add little/big-endian modes for doing 32-bit loads + **************************************************************************************/ +static __inline void RefillBitstreamCache(BitStreamInfo *bsi) +{ + int nBytes = bsi->nBytes; + + /* optimize for common case, independent of machine endian-ness */ + if (nBytes >= 4) { + bsi->iCache = (*bsi->bytePtr++) << 24; + bsi->iCache |= (*bsi->bytePtr++) << 16; + bsi->iCache |= (*bsi->bytePtr++) << 8; + bsi->iCache |= (*bsi->bytePtr++); + bsi->cachedBits = 32; + bsi->nBytes -= 4; + } else { + bsi->iCache = 0; + while (nBytes--) { + bsi->iCache |= (*bsi->bytePtr++); + bsi->iCache <<= 8; + } + bsi->iCache <<= ((3 - bsi->nBytes)*8); + bsi->cachedBits = 8*bsi->nBytes; + bsi->nBytes = 0; + } +} + +/************************************************************************************** + * Function: GetBits + * + * Description: get bits from bitstream, advance bitstream pointer + * + * Inputs: pointer to initialized BitStreamInfo struct + * number of bits to get from bitstream + * + * Outputs: updated bitstream info struct + * + * Return: the next nBits bits of data from bitstream buffer + * + * Notes: nBits must be in range [0, 31], nBits outside this range masked by 0x1f + * for speed, does not indicate error if you overrun bit buffer + * if nBits = 0, returns 0 (useful for scalefactor unpacking) + * + * TODO: optimize for ARM + **************************************************************************************/ +unsigned int GetBits(BitStreamInfo *bsi, int nBits) +{ + unsigned int data, lowBits; + + nBits &= 0x1f; /* nBits mod 32 to avoid unpredictable results like >> by negative amount */ + data = bsi->iCache >> (31 - nBits); /* unsigned >> so zero-extend */ + data >>= 1; /* do as >> 31, >> 1 so that nBits = 0 works okay (returns 0) */ + bsi->iCache <<= nBits; /* left-justify cache */ + bsi->cachedBits -= nBits; /* how many bits have we drawn from the cache so far */ + + /* if we cross an int boundary, refill the cache */ + if (bsi->cachedBits < 0) { + lowBits = -bsi->cachedBits; + RefillBitstreamCache(bsi); + data |= bsi->iCache >> (32 - lowBits); /* get the low-order bits */ + + bsi->cachedBits -= lowBits; /* how many bits have we drawn from the cache so far */ + bsi->iCache <<= lowBits; /* left-justify cache */ + } + + return data; +} + +/************************************************************************************** + * Function: CalcBitsUsed + * + * Description: calculate how many bits have been read from bitstream + * + * Inputs: pointer to initialized BitStreamInfo struct + * pointer to start of bitstream buffer + * bit offset into first byte of startBuf (0-7) + * + * Outputs: none + * + * Return: number of bits read from bitstream, as offset from startBuf:startOffset + **************************************************************************************/ +int CalcBitsUsed(BitStreamInfo *bsi, unsigned char *startBuf, int startOffset) +{ + int bitsUsed; + + bitsUsed = (bsi->bytePtr - startBuf) * 8; + bitsUsed -= bsi->cachedBits; + bitsUsed -= startOffset; + + return bitsUsed; +} + +/************************************************************************************** + * Function: CheckPadBit + * + * Description: check whether padding byte is present in an MP3 frame + * + * Inputs: MP3DecInfo struct with valid FrameHeader struct + * (filled by UnpackFrameHeader()) + * + * Outputs: none + * + * Return: 1 if pad bit is set, 0 if not, -1 if null input pointer + **************************************************************************************/ +int CheckPadBit(MP3DecInfo *mp3DecInfo) +{ + FrameHeader *fh; + + /* validate pointers */ + if (!mp3DecInfo || !mp3DecInfo->FrameHeaderPS) + return -1; + + fh = ((FrameHeader *)(mp3DecInfo->FrameHeaderPS)); + + return (fh->paddingBit ? 1 : 0); +} + +/************************************************************************************** + * Function: UnpackFrameHeader + * + * Description: parse the fields of the MP3 frame header + * + * Inputs: buffer pointing to a complete MP3 frame header (4 bytes, plus 2 if CRC) + * + * Outputs: filled frame header info in the MP3DecInfo structure + * updated platform-specific FrameHeader struct + * + * Return: length (in bytes) of frame header (for caller to calculate offset to + * first byte following frame header) + * -1 if null frameHeader or invalid header + * + * TODO: check for valid modes, depending on capabilities of decoder + * test CRC on actual stream (verify no endian problems) + **************************************************************************************/ +int UnpackFrameHeader(MP3DecInfo *mp3DecInfo, unsigned char *buf) +{ + + int verIdx; + FrameHeader *fh; + + /* validate pointers and sync word */ + if (!mp3DecInfo || !mp3DecInfo->FrameHeaderPS || (buf[0] & SYNCWORDH) != SYNCWORDH || (buf[1] & SYNCWORDL) != SYNCWORDL) + return -1; + + fh = ((FrameHeader *)(mp3DecInfo->FrameHeaderPS)); + + /* read header fields - use bitmasks instead of GetBits() for speed, since format never varies */ + verIdx = (buf[1] >> 3) & 0x03; + fh->ver = (MPEGVersion)( verIdx == 0 ? MPEG25 : ((verIdx & 0x01) ? MPEG1 : MPEG2) ); + fh->layer = 4 - ((buf[1] >> 1) & 0x03); /* easy mapping of index to layer number, 4 = error */ + fh->crc = 1 - ((buf[1] >> 0) & 0x01); + fh->brIdx = (buf[2] >> 4) & 0x0f; + fh->srIdx = (buf[2] >> 2) & 0x03; + fh->paddingBit = (buf[2] >> 1) & 0x01; + fh->privateBit = (buf[2] >> 0) & 0x01; + fh->sMode = (StereoMode)((buf[3] >> 6) & 0x03); /* maps to correct enum (see definition) */ + fh->modeExt = (buf[3] >> 4) & 0x03; + fh->copyFlag = (buf[3] >> 3) & 0x01; + fh->origFlag = (buf[3] >> 2) & 0x01; + fh->emphasis = (buf[3] >> 0) & 0x03; + + /* check parameters to avoid indexing tables with bad values */ + if (fh->srIdx == 3 || fh->layer == 4 || fh->brIdx == 15) + return -1; + + fh->sfBand = &sfBandTable[fh->ver][fh->srIdx]; /* for readability (we reference sfBandTable many times in decoder) */ + if (fh->sMode != Joint) /* just to be safe (dequant, stproc check fh->modeExt) */ + fh->modeExt = 0; + + /* init user-accessible data */ + mp3DecInfo->nChans = (fh->sMode == Mono ? 1 : 2); + mp3DecInfo->samprate = samplerateTab[fh->ver][fh->srIdx]; + mp3DecInfo->nGrans = (fh->ver == MPEG1 ? NGRANS_MPEG1 : NGRANS_MPEG2); + mp3DecInfo->nGranSamps = ((int)samplesPerFrameTab[fh->ver][fh->layer - 1]) / mp3DecInfo->nGrans; + mp3DecInfo->layer = fh->layer; + mp3DecInfo->version = fh->ver; + + /* get bitrate and nSlots from table, unless brIdx == 0 (free mode) in which case caller must figure it out himself + * question - do we want to overwrite mp3DecInfo->bitrate with 0 each time if it's free mode, and + * copy the pre-calculated actual free bitrate into it in mp3dec.c (according to the spec, + * this shouldn't be necessary, since it should be either all frames free or none free) + */ + if (fh->brIdx) { + mp3DecInfo->bitrate = ((int)bitrateTab[fh->ver][fh->layer - 1][fh->brIdx]) * 1000; + + /* nSlots = total frame bytes (from table) - sideInfo bytes - header - CRC (if present) + pad (if present) */ + mp3DecInfo->nSlots = (int)slotTab[fh->ver][fh->srIdx][fh->brIdx] - + (int)sideBytesTab[fh->ver][(fh->sMode == Mono ? 0 : 1)] - + 4 - (fh->crc ? 2 : 0) + (fh->paddingBit ? 1 : 0); + } + + /* load crc word, if enabled, and return length of frame header (in bytes) */ + if (fh->crc) { + fh->CRCWord = ((int)buf[4] << 8 | (int)buf[5] << 0); + return 6; + } else { + fh->CRCWord = 0; + return 4; + } +} + +/************************************************************************************** + * Function: UnpackSideInfo + * + * Description: parse the fields of the MP3 side info header + * + * Inputs: MP3DecInfo structure filled by UnpackFrameHeader() + * buffer pointing to the MP3 side info data + * + * Outputs: updated mainDataBegin in MP3DecInfo struct + * updated private (platform-specific) SideInfo struct + * + * Return: length (in bytes) of side info data + * -1 if null input pointers + **************************************************************************************/ +int UnpackSideInfo(MP3DecInfo *mp3DecInfo, unsigned char *buf) +{ + int gr, ch, bd, nBytes; + BitStreamInfo bitStreamInfo, *bsi; + FrameHeader *fh; + SideInfo *si; + SideInfoSub *sis; + + /* validate pointers and sync word */ + if (!mp3DecInfo || !mp3DecInfo->FrameHeaderPS || !mp3DecInfo->SideInfoPS) + return -1; + + fh = ((FrameHeader *)(mp3DecInfo->FrameHeaderPS)); + si = ((SideInfo *)(mp3DecInfo->SideInfoPS)); + + bsi = &bitStreamInfo; + if (fh->ver == MPEG1) { + /* MPEG 1 */ + nBytes = (fh->sMode == Mono ? SIBYTES_MPEG1_MONO : SIBYTES_MPEG1_STEREO); + SetBitstreamPointer(bsi, nBytes, buf); + si->mainDataBegin = GetBits(bsi, 9); + si->privateBits = GetBits(bsi, (fh->sMode == Mono ? 5 : 3)); + + for (ch = 0; ch < mp3DecInfo->nChans; ch++) + for (bd = 0; bd < MAX_SCFBD; bd++) + si->scfsi[ch][bd] = GetBits(bsi, 1); + } else { + /* MPEG 2, MPEG 2.5 */ + nBytes = (fh->sMode == Mono ? SIBYTES_MPEG2_MONO : SIBYTES_MPEG2_STEREO); + SetBitstreamPointer(bsi, nBytes, buf); + si->mainDataBegin = GetBits(bsi, 8); + si->privateBits = GetBits(bsi, (fh->sMode == Mono ? 1 : 2)); + } + + for(gr =0; gr < mp3DecInfo->nGrans; gr++) { + for (ch = 0; ch < mp3DecInfo->nChans; ch++) { + sis = &si->sis[gr][ch]; /* side info subblock for this granule, channel */ + + sis->part23Length = GetBits(bsi, 12); + sis->nBigvals = GetBits(bsi, 9); + sis->globalGain = GetBits(bsi, 8); + sis->sfCompress = GetBits(bsi, (fh->ver == MPEG1 ? 4 : 9)); + sis->winSwitchFlag = GetBits(bsi, 1); + + if(sis->winSwitchFlag) { + /* this is a start, stop, short, or mixed block */ + sis->blockType = GetBits(bsi, 2); /* 0 = normal, 1 = start, 2 = short, 3 = stop */ + sis->mixedBlock = GetBits(bsi, 1); /* 0 = not mixed, 1 = mixed */ + sis->tableSelect[0] = GetBits(bsi, 5); + sis->tableSelect[1] = GetBits(bsi, 5); + sis->tableSelect[2] = 0; /* unused */ + sis->subBlockGain[0] = GetBits(bsi, 3); + sis->subBlockGain[1] = GetBits(bsi, 3); + sis->subBlockGain[2] = GetBits(bsi, 3); + + /* TODO - check logic */ + if (sis->blockType == 0) { + /* this should not be allowed, according to spec */ + sis->nBigvals = 0; + sis->part23Length = 0; + sis->sfCompress = 0; + } else if (sis->blockType == 2 && sis->mixedBlock == 0) { + /* short block, not mixed */ + sis->region0Count = 8; + } else { + /* start, stop, or short-mixed */ + sis->region0Count = 7; + } + sis->region1Count = 20 - sis->region0Count; + } else { + /* this is a normal block */ + sis->blockType = 0; + sis->mixedBlock = 0; + sis->tableSelect[0] = GetBits(bsi, 5); + sis->tableSelect[1] = GetBits(bsi, 5); + sis->tableSelect[2] = GetBits(bsi, 5); + sis->region0Count = GetBits(bsi, 4); + sis->region1Count = GetBits(bsi, 3); + } + sis->preFlag = (fh->ver == MPEG1 ? GetBits(bsi, 1) : 0); + sis->sfactScale = GetBits(bsi, 1); + sis->count1TableSelect = GetBits(bsi, 1); + } + } + mp3DecInfo->mainDataBegin = si->mainDataBegin; /* needed by main decode loop */ + + ASSERT(nBytes == CalcBitsUsed(bsi, buf, 0) >> 3); + + return nBytes; +} + |