📄 mp3dec.cpp
字号:
/*
mp3dec.cpp:
decode mp3-data to 16bit pcm
Notice:
1. this code is writen for mips-cpu(ATI-XILLEON serial CHIP)
2. this code has optimized for mips1 (mips R3000)
Author:
XiangXian Cheng, Network Dept, &Rd Center, TclKing Ltd.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <errno.h>
#include <math.h>
#include <time.h>
#define FPM_MIPS /* switch, optimize for mips cpu */
#include "mad.h"
#include "mp3decode.h"
#include "mp3locals.h"
/* open mp3 decode debug ? */
int _mp3decode_debug = 0 ;
static inline
signed int scale(mad_fixed_t sample) ;
static signed short MadFixedToSshort(mad_fixed_t Fixed) ;
static void ApplyFilter(struct mad_frame *Frame, mad_fixed_t *Filter) ;
static const char *MadErrorString(const struct mad_stream *Stream) ;
static int FillMp3Info(Mp3Info_t *pMp3Info, struct mad_header *Header) ;
/*===================================================================*/
/*
* The following utility routine performs simple rounding, clipping, and
* scaling of MAD's high-resolution samples down to 16 bits. It does not
* perform any dithering or noise shaping, which would be recommended to
* obtain any exceptional audio quality. It is therefore not recommended to
* use this routine if high-quality output is desired.
*/
static inline
signed int scale(mad_fixed_t sample)
{
/* round */
sample += (1L << (MAD_F_FRACBITS - 16));
/* clip */
if (sample >= MAD_F_ONE)
sample = MAD_F_ONE - 1;
else if (sample < -MAD_F_ONE)
sample = -MAD_F_ONE;
/* quantize */
return sample >> (MAD_F_FRACBITS + 1 - 16);
}
/*===================================================================*/
/****************************************************************************
* Converts a sample from libmad's fixed point number format to a signed *
* short (16 bits). *
****************************************************************************/
static signed short MadFixedToSshort(mad_fixed_t Fixed)
{
/* Clipping */
if(Fixed>=MAD_F_ONE)
return(SHRT_MAX);
if(Fixed<=-MAD_F_ONE)
return(-SHRT_MAX);
/* Conversion. */
Fixed=Fixed>>(MAD_F_FRACBITS-15);
return((signed short)Fixed);
}
/*===================================================================*/
/****************************************************************************
* Applies a frequency-domain filter to audio data in the subband-domain. *
****************************************************************************/
static void ApplyFilter(struct mad_frame *Frame, mad_fixed_t *Filter)
{
int Channel,
Sample,
Samples,
SubBand;
/* There is two application loops, each optimized for the number
* of audio channels to process. The first alternative is for
* two-channel frames, the second is for mono-audio.
*/
Samples=MAD_NSBSAMPLES(&Frame->header);
if(Frame->header.mode!=MAD_MODE_SINGLE_CHANNEL)
for(Channel=0;Channel<2;Channel++)
for(Sample=0;Sample<Samples;Sample++)
for(SubBand=0;SubBand<32;SubBand++)
Frame->sbsample[Channel][Sample][SubBand]=
mad_f_mul(Frame->sbsample[Channel][Sample][SubBand],
Filter[SubBand]);
else
for(Sample=0;Sample<Samples;Sample++)
for(SubBand=0;SubBand<32;SubBand++)
Frame->sbsample[0][Sample][SubBand]=
mad_f_mul(Frame->sbsample[0][Sample][SubBand],
Filter[SubBand]);
}
/*===================================================================*/
static const char *MadErrorString(const struct mad_stream *Stream)
{
switch(Stream->error)
{
/* Generic unrecoverable errors. */
case MAD_ERROR_BUFLEN:
return("input buffer too small (or EOF)");
case MAD_ERROR_BUFPTR:
return("invalid (null) buffer pointer");
case MAD_ERROR_NOMEM:
return("not enough memory");
/* Frame header related unrecoverable errors. */
case MAD_ERROR_LOSTSYNC:
return("lost synchronization");
case MAD_ERROR_BADLAYER:
return("reserved header layer value");
case MAD_ERROR_BADBITRATE:
return("forbidden bitrate value");
case MAD_ERROR_BADSAMPLERATE:
return("reserved sample frequency value");
case MAD_ERROR_BADEMPHASIS:
return("reserved emphasis value");
/* Recoverable errors */
case MAD_ERROR_BADCRC:
return("CRC check failed");
case MAD_ERROR_BADBITALLOC:
return("forbidden bit allocation value");
case MAD_ERROR_BADSCALEFACTOR:
return("bad scalefactor index");
case MAD_ERROR_BADFRAMELEN:
return("bad frame length");
case MAD_ERROR_BADBIGVALUES:
return("bad big_values count");
case MAD_ERROR_BADBLOCKTYPE:
return("reserved block_type");
case MAD_ERROR_BADSCFSI:
return("bad scalefactor selection info");
case MAD_ERROR_BADDATAPTR:
return("bad main_data_begin pointer");
case MAD_ERROR_BADPART3LEN:
return("bad audio data length");
case MAD_ERROR_BADHUFFTABLE:
return("bad Huffman table select");
case MAD_ERROR_BADHUFFDATA:
return("Huffman data overrun");
case MAD_ERROR_BADSTEREO:
return("incompatible block_type for JS");
/* Unknown error. This switch may be out of sync with libmad's
* defined error codes.
*/
default:
return("Unknown error code");
}
}
/*===================================================================*/
static int FillMp3Info(Mp3Info_t *pMp3Info, struct mad_header *Header)
{
int result = -1 ;
Mp3Info_t *p = pMp3Info ;
const char *Layer,
*Mode,
*Emphasis ;
if (!p
|| !Header)
goto done ;
/* Convert the layer number to it's printed representation. */
switch(Header->layer)
{
case MAD_LAYER_I:
Layer="I";
p->layer = 1 ;
break;
case MAD_LAYER_II:
Layer="II";
p->layer = 2 ;
break;
case MAD_LAYER_III:
p->layer = 3 ;
Layer="III";
break;
default:
Layer="(unexpected layer value)";
p->layer = 0 ;
break;
}
/* Convert the audio mode to it's printed representation. */
switch(Header->mode)
{
case MAD_MODE_SINGLE_CHANNEL:
Mode="single channel";
p->channel = 1 ;
break;
case MAD_MODE_DUAL_CHANNEL:
Mode="dual channel";
p->channel = 2 ;
break;
case MAD_MODE_JOINT_STEREO:
Mode="joint (MS/intensity) stereo";
p->channel = 2 ;
break;
case MAD_MODE_STEREO:
Mode="normal LR stereo";
p->channel = 2 ;
break;
default:
Mode="(unexpected mode value)";
p->channel = 0 ;
break;
}
switch(Header->emphasis)
{
case MAD_EMPHASIS_NONE:
Emphasis="no";
break;
case MAD_EMPHASIS_50_15_US:
Emphasis="50/15 us";
break;
case MAD_EMPHASIS_CCITT_J_17:
Emphasis="CCITT J.17";
break;
#if (MAD_VERSION_MAJOR>=1) || \
((MAD_VERSION_MAJOR==0) && (MAD_VERSION_MINOR>=15))
case MAD_EMPHASIS_RESERVED:
Emphasis="reserved(!)";
break;
#endif
default:
Emphasis="(unexpected emphasis value)";
break;
}
if (_mp3decode_debug)
fprintf(stderr,"%lu kb/s audio MPEG layer %s stream %s CRC, "
"%s with %s emphasis at %d Hz sample rate\n",
Header->bitrate,Layer,
Header->flags&MAD_FLAG_PROTECTION?"with":"without",
Mode,Emphasis,Header->samplerate);
p->mpeg = 1 ;
p->bitRate = Header->bitrate ;
p->sampleRate = Header->samplerate ;
p->nBitsPerSample = 16; /* now, we set it fixed (16 bits) */
p->frameSize = 144*p->bitRate/p->sampleRate
+ ((Header->flags&MAD_FLAG_PADDING)?1:0) ;
result = 0 ;
done:
return (result) ;
}
/*===================================================================*/
/*===================================================================*/
/*===================================================================*/
int Mp3DecodeStart(Mp3DecodeCtrl_t *pMp3DecCtrl)
{
int result = -1 ;
Mp3DecodeCtrl_t *p = pMp3DecCtrl ;
if (!p)
goto done ;
mad_stream_init(&p->Stream);
mad_frame_init(&p->Frame);
mad_synth_init(&p->Synth);
mad_timer_reset(&p->Timer);
result = 0 ;
done:
return (result) ;
}
/*===================================================================*/
int Mp3DecodeFrame(Mp3DecodeCtrl_t *pMp3DecCtrl)
{
int result ;
int i ;
int Status = MP3DEC_ERR_GENERAL ;
int DoFilter = 0 ;
mad_fixed_t Filter[32] ;
unsigned char *LeftChannelData = NULL ;
unsigned char *RightChannelData = NULL ;
unsigned char *InputBuffer ;
Mp3DecodeCtrl_t *p = pMp3DecCtrl ;
if (!p
|| p->outbuf == NULL
|| p->outbuf_len <= 0
)
goto done ;
InputBuffer = &(p->InputBuffer[0]) ;
if (p->pMp3Option)
{
if (!p->pMp3Option->notIgnoreCrc)
p->Stream.options |= MAD_OPTION_IGNORECRC ;
else
p->Stream.options &= (!MAD_OPTION_IGNORECRC) ;
if (p->pMp3Option->halfSamRateDecode)
p->Stream.options |= MAD_OPTION_HALFSAMPLERATE ;
else
p->Stream.options &= (!MAD_OPTION_HALFSAMPLERATE) ;
# if 0 /* not yet implemented */
if (p->pMp3Option->decodeChannel == 1)
{
p->Stream.options |= MAD_OPTION_LEFTCHANNEL ;
p->Stream.options &= (!MAD_OPTION_RIGHTCHANNEL) ;
}
else
if (p->pMp3Option->decodeChannel == 2)
{
p->Stream.options |= MAD_OPTION_RIGHTCHANNEL ;
p->Stream.options &= (!MAD_OPTION_LEFTCHANNEL) ;
}
else
if (p->pMp3Option->decodeChannel == 3)
{
p->Stream.options |= MAD_OPTION_LEFTCHANNEL ;
p->Stream.options |= MAD_OPTION_RIGHTCHANNEL ;
}
else
{
p->Stream.options |= MAD_OPTION_LEFTCHANNEL ;
p->Stream.options |= MAD_OPTION_RIGHTCHANNEL ;
}
#endif
}
try_again:
if(p->Stream.buffer==NULL || p->Stream.error==MAD_ERROR_BUFLEN)
{
size_t ReadSize ;
size_t Remaining ;
unsigned char *ReadStart ;
size_t r = 0 ;
if (p->Stream.next_frame!=NULL)
{
Remaining = p->Stream.bufend - p->Stream.next_frame ;
if (Remaining > 0)
memmove(InputBuffer, p->Stream.next_frame, Remaining) ;
ReadStart = InputBuffer + Remaining ;
ReadSize = INPUT_BUFFER_SIZE - Remaining ;
}
else
{
ReadSize = INPUT_BUFFER_SIZE,
ReadStart = InputBuffer,
Remaining = 0 ;
}
/* Fill-in the buffer. If an error occurs print a message
* and leave the decoding loop. If the end of stream is
* reached we also leave the loop but the return status is
* left untouched.
*/
if (p->r_h != 0)
{
/*r = RingBuf_Read(p->r_h, ReadStart, 1, ReadSize) ;*/
r = ReadFeedBuffer(p->r_h, (char*)ReadStart, 1,ReadSize);
if (r <= 0)
{
/* undo it */
if (Remaining > 0)
memmove((void *)p->Stream.next_frame, InputBuffer, Remaining) ;
Status = MP3DEC_ERR_DATAREQ ;
if (_mp3decode_debug)
printf("can't get data \n") ;
goto done ;
}
}
else
{
Status = MP3DEC_ERR_GENERAL ;
goto done ;
}
mad_stream_buffer(&p->Stream, InputBuffer, r+Remaining) ;
p->Stream.error= (mad_error)0 ;
}
if (mad_frame_decode(&p->Frame, &p->Stream))
{
if(MAD_RECOVERABLE(p->Stream.error))
{
/* Do not print a message if the error is a loss of
* synchronization and this loss is due to the end of
* stream guard bytes. (See the comments marked {3}
* supra for more informations about guard bytes.)
*/
if (p->Stream.error!=MAD_ERROR_LOSTSYNC)
{
if (_mp3decode_debug)
{
fprintf(stderr,"recoverable frame level error (%s)\n",
MadErrorString(&p->Stream));
fflush(stderr);
}
}
Status = MP3DEC_ERR_CANRECOV ;
goto done ;
}
else
{
if(p->Stream.error==MAD_ERROR_BUFLEN)
{
/* try to get data from ring-buffer */
goto try_again ;
}
else
{
if (_mp3decode_debug)
fprintf(stderr,"unrecoverable frame level error (%s).\n",
MadErrorString(&p->Stream));
Status = MP3DEC_ERR_FATAL ;
goto done ;
}
}
}
if(p->FrameCount == 0)
{
if (p->pMp3Info == NULL)
p->pMp3Info = (Mp3Info_t *)malloc(sizeof(Mp3Info_t)) ;
if (p->pMp3Info)
FillMp3Info(p->pMp3Info, &(p->Frame.header)) ;
}
p->FrameCount++ ;
mad_timer_add(&p->Timer, p->Frame.header.duration) ;
/* Between the frame decoding and samples synthesis we can
* perform some operations on the audio data. We do this only
* if some processing was required. Detailed explanations are
* given in the ApplyFilter() function.
*/
if(DoFilter)
ApplyFilter(&p->Frame, Filter) ;
/* Once decoded the frame is synthesized to PCM samples. No errors
* are reported by mad_synth_frame();
*/
mad_synth_frame(&p->Synth, &p->Frame) ;
/* calculate buffer */
if (p->Synth.pcm.length > 0)
{
int output_len = (2*p->Synth.pcm.length) ;
/* calulate output buffer is big enough */
if (MAD_NCHANNELS(&p->Frame.header) == 2)
output_len += (2*p->Synth.pcm.length) ;
if (output_len > p->outbuf_len)
{
Status = MP3DEC_ERR_OUTPUTBUF ;
goto done ;
}
p->output_len = output_len ;
LeftChannelData = (unsigned char *) p->outbuf ;
RightChannelData = LeftChannelData + 2 ;
}
else
{
Status = MP3DEC_ERR_CANRECOV ;
p->output_len = 0 ;
goto done ;
}
/* Synthesized samples must be converted from libmad's fixed
* point number to the consumer format. Here we use unsigned
* 16 bit big endian integers on two channels. Integer samples
* are temporarily stored in a buffer that is flushed when
* full.
*/
for(i=0;i<p->Synth.pcm.length;i++)
{
signed short Sample;
/* Left channel */
Sample=MadFixedToSshort(p->Synth.pcm.samples[0][i]);
if (LeftChannelData)
{
*LeftChannelData=(unsigned char)(Sample&0xff);
LeftChannelData++ ;
*LeftChannelData=(unsigned char)(Sample>>8);
LeftChannelData++ ;
}
/* Right channel. If the decoded stream is monophonic then
* the right output channel is the same as the left one.
*/
if(MAD_NCHANNELS(&p->Frame.header)==2)
{
Sample=MadFixedToSshort(p->Synth.pcm.samples[1][i]);
if (RightChannelData)
{
*RightChannelData=(unsigned char)(Sample&0xff);
RightChannelData++ ;
*RightChannelData=(unsigned char)(Sample>>8);
RightChannelData++ ;
if (LeftChannelData)
{
LeftChannelData = RightChannelData ;
RightChannelData += 2 ;
}
}
}
}
Status = MP3DEC_OK ;
done:
result = Status ;
return (result) ;
}
/*===================================================================*/
int Mp3DecodeEnd(Mp3DecodeCtrl_t *pMp3DecCtrl)
{
int result = -1 ;
char Buffer[80] ;
Mp3DecodeCtrl_t *p = pMp3DecCtrl ;
if (!p)
goto done ;
mad_synth_finish(&p->Synth);
mad_frame_finish(&p->Frame);
mad_stream_finish(&p->Stream);
if (_mp3decode_debug)
{
mad_timer_string(p->Timer,Buffer,"%lu:%02lu.%03u",
MAD_UNITS_MINUTES,MAD_UNITS_MILLISECONDS,0) ;
fprintf(stderr,"\n %lu frames decoded (%s).\n",
p->FrameCount,Buffer) ;
}
if (p->pMp3Info)
{
free(p->pMp3Info) ;
p->pMp3Info = NULL ;
}
result = 0 ;
done:
return (result) ;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -