📄 mp3.c
字号:
//****************************************************************************//// MP3.C - Codec interface driver for the MP3 decoder.//// Copyright (c) 1999,2000,2001 Cirrus Logic, Inc.////****************************************************************************#include "globals.h"#ifdef SUPPORT_MP3#include "mp3/mpgdata.h"#include "mp3/mpgaudio.h"#include "buffer/buffer.h"#include "src/src.h"//****************************************************************************//// The name of this codec.////****************************************************************************static const unsigned short pusCodecName[] ={ 'M', 'P', '3', ' ', 'M', 'P', 'E', 'G', ' ', 'L', 'a', 'y', 'e', 'r', ' ', '3', '\0'};//****************************************************************************//// A structure which defines the persistent state of the MP3 decoder.////****************************************************************************typedef struct{ // // A pointer to the buffer containing the persistent internal state of the // MP3 decoder library. // tMPEGInstance *pMPEGInstance; // // The file from which we read data. // tFile *pFile; // // A buffer to contain the encoded MP3 audio. // char pcEncodedData[2048]; // // Buffers to contain the decoded MP3 audio. // short psLeft[MP3_MAX_PCM_LENGTH + MP3_MAX_PCM_LENGTH + NUMTAPS - 1]; short psRight[MP3_MAX_PCM_LENGTH + MP3_MAX_PCM_LENGTH + NUMTAPS - 1]; // // The buffer to which we write decoded MP3 data. // BufferState *pOutput; // // The MP3 bitstream pointer. // tMPEGBitstream sBS; // // The decoded MP3 header information. // tMPEGHeader sHdr; // // The number of bytes in pcEncodedData which contain valid encoded MP3 // data. // unsigned short usValid; // // The sample rate of the decoded PCM stream. // unsigned short usSampleRate; // // The number of channels in the file. // unsigned char ucChannels; // // A boolean which is true if this file uses VBR. // unsigned char ucIsVBR; // // An unused half-word to pad the next member to a word boundary. // unsigned short usUnused; // // The offset of the first frame of the file. // unsigned long ulFirstFrame; // // The byte length of the file. // unsigned long ulLength; // // The time length of the file. // unsigned long ulTimeLength; // // The bit rate of the MP3 file. // unsigned long ulBitRate; // // The number of samples which have been decoded. // unsigned long ulTimePos; // // The seek points for VBR files. // unsigned char pucVBRSeek[100]; // // A buffer to contain the song title, if known. // unsigned short pusTitle[64]; // // A buffer to contain the song author, if known. // unsigned short pusArtist[64];} tMP3;//****************************************************************************//// The following is a mapping from the sample rate descriptor in the// tMPEGHeader structure to the integer number of samples per second.////****************************************************************************static const unsigned short usSRMap[] = { 11025, 12000, 8000, 0, 22050, 24000, 16000, 0, 44100, 48000, 32000, 0 };//****************************************************************************//// The following is a mapping from the bitrate_index and ID bit in the MPEG// sync header to a the bitrate of the frame. The first 16 entries are for// ID=0 (i.e. MPEG-2 or MPEG-2.5 half sample rate) and the second 16 entries// are for ID=1 (i.e. MPEG-1 full sample rate).////****************************************************************************static const unsigned short usBRMap[] = { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0, 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0 };//****************************************************************************//// MP3InitBitstream initializes the stream to the given byte offset in the// file.////****************************************************************************static voidMP3InitBitstream(tMP3 *pMP3, unsigned long ulFilePos){ // // Seek to the correct block of data in the file. // FSSeek(pMP3->pFile, ulFilePos & ~511); // // Read the first four pages from this position. // pMP3->usValid = FSReadBS(pMP3->pFile, pMP3->pcEncodedData, 2048); // // Initialize the bitstream pointer structure. // pMP3->sBS.bufptr = (unsigned int *)(pMP3->pcEncodedData + (ulFilePos & 508)); pMP3->sBS.bitidx = 8 * (ulFilePos & 3);}//****************************************************************************//// MP3FindNextFrame finds the next frame in the input MP3 bitstream.////****************************************************************************static unsigned longMP3FindNextFrame(tMP3 *pMP3){ unsigned long ulRead; // // Make sure the bitstream pointer structure makes sense (i.e. it is // pointing to a valid bit in a word, not at the bit following the last // bit of the previous word). // if(pMP3->sBS.bitidx == 32) { pMP3->sBS.bufptr++; pMP3->sBS.bitidx = 0; } // // If the bitstream pointer is not at the beginning of the local bitstream // buffer, then copy the remaining data back to the beginning. // if((int)pMP3->sBS.bufptr != (int)pMP3->pcEncodedData) { // // Copy the remainder of the data from the end of the local bitstream // buffer to the beginning. // memcpy(pMP3->pcEncodedData, pMP3->sBS.bufptr, 2048 - ((int)pMP3->sBS.bufptr - (int)pMP3->pcEncodedData)); // // Update the count of valid bytes in the local bitstream buffer. // ulRead = (int)pMP3->sBS.bufptr - (int)pMP3->pcEncodedData; if(ulRead > pMP3->usValid) { pMP3->usValid = 0; } else { pMP3->usValid -= (int)pMP3->sBS.bufptr - (int)pMP3->pcEncodedData; } // // Update the bitstream pointer structure. // pMP3->sBS.bufptr = (unsigned int *)pMP3->pcEncodedData; } // // See if there is any additional MP3 data that we can copy into the local // bitstream buffer. // if(pMP3->usValid <= (2048 - 512)) { // // Compute the number of bytes to read. // ulRead = (2048 - pMP3->usValid) & ~511; // // Read MP3 data into the end of the local bitstream buffer. Since the // ARM MP3 decoder needs the bytes within each word swapped, perform // the byte swap as we read. // pMP3->usValid += FSReadBS(pMP3->pFile, pMP3->pcEncodedData + pMP3->usValid, ulRead); } // // Find the next sync word. // if(MP3SearchForSyncword(pMP3->pMPEGInstance, &(pMP3->sBS), pMP3->usValid * 8) != eNoErr) { // // We could not find a sync word, so return an error. // return(0); } // // Decode the header. // if(MP3DecodeInfo(pMP3->pMPEGInstance, &(pMP3->sBS), &(pMP3->sHdr)) != eNoErr) { // // Skip back past the word that was consumed by the attempt to decode // the header. // pMP3->sBS.bufptr--; // // We could not decode the header, so return an error. // return(0); } // // Success. // return(1);}//****************************************************************************//// MP3DecodeVBRHeader determines if the current frame is a Xing VBR header// frame and decodes it if it is.////****************************************************************************static unsigned longMP3DecodeVBRHeader(tMP3 *pMP3){ unsigned char *pucPtr; unsigned long ulFlags, ulFrames, ulIdx, ulFrameSize; // // Get the offset to the beginning of the current frame. // pucPtr = (unsigned char *)pMP3->sBS.bufptr + (pMP3->sBS.bitidx >> 3); // // Determine the offset of the header. // if(pMP3->usSampleRate >= 32000) { // // This is a MPEG-1 file. Is this a mono or stereo stream? // if(pMP3->ucChannels == 1) { // // This is a mono stream, so the header starts at the 17st byte of // the frame data. // pucPtr += 17; } else { // // This is a stereo stream, so the header starts at the 32nd byte // of the frame data. // pucPtr += 32; } // // The frame size for MPEG-1 files is 1152. // ulFrameSize = 1152; } else { // // This is a MPEG-2 file. Is this a mono or stereo stream? // if(pMP3->ucChannels == 1) { // // This is a mono stream, so the header starts at the 9th byte of // the frame data. // pucPtr += 9; } else { // // This is a stereo stream, so the header starts at the 17th byte // of the frame. // pucPtr += 17; } // // The frame size for MPEG-2 files is 576. // ulFrameSize = 576; } // // See if the "Xing" signature appears in the frame. // if((pucPtr[3] != 'X') || (pucPtr[2] != 'i') || (pucPtr[1] != 'n') || (pucPtr[0] != 'g')) { // // This is not a Xing VBR header, so return a failure. // return(0); } // // Skip past the signature. // pucPtr += 4; // // Get the header flags from the stream. // ulFlags = (pucPtr[3] << 24) | (pucPtr[2] << 16) | (pucPtr[1] << 8) | pucPtr[0]; pucPtr += 4; // // If the number of frames exists in the header, then extract it now. // if(ulFlags & 1) { ulFrames = (pucPtr[3] << 24) | (pucPtr[2] << 16) | (pucPtr[1] << 8) | pucPtr[0]; pucPtr += 4; } else { // // The count of frames does not exist, so we will not be able to // properly support this file. // return(0); } // // If the file size exists in the header, then skip it. // if(ulFlags & 2) { pucPtr += 4; } // // If the seek point table exists in the header, then read it in now. // if(ulFlags & 4) { // // There are 100 entries in the table, so copy them one by one. // for(ulIdx = 0; ulIdx < 100; ulIdx++) { pMP3->pucVBRSeek[ulIdx ^ 3] = *pucPtr++; } // // Since the seek point table exists in the header, indicate that this // is a VBR file. // pMP3->ucIsVBR = 1; } else { // // Since there is no seek point table in the header, treat this file as // a non-VBR file. // pMP3->ucIsVBR = 0; } // // Now, compute the bitrate from the file size and the count of frames in // the file. // pMP3->ulBitRate = ((FSLength(pMP3->pFile) / ulFrames) * pMP3->usSampleRate) / (ulFrameSize / 8); // // Success. // return(1);}//****************************************************************************
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -