⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mp3dec.cpp

📁 基于mips架构的ATI-XILLEON 226的mp3解码程序
💻 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 + -