📄 maddecoder.cpp
字号:
/*
* Copyright (c) 2004 P.Wolff
*
* Based on :
* madlld.c,
* (c) 2001--2004 Bertrand Petit
*
* madplay - MPEG audio decoder and player
* Copyright (C) 2000-2004 Robert Leslie
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#pragma warning( disable : 4127 ) // while(1)
#include "MadDecoder.h"
#include "OggLog.h"
#include "mad.h"
#include "id3tag.h"
#include "gettext.h"
#include "tag.h"
#include <utf.h>
#include <limits.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h>
#include <fcntl.h>
#define MadErrorString(x) mad_stream_errorstr(x)
# define N_(text) (text)
# define _(text) (text)
/****************************************************************************
* Converts a sample from libmad's fixed point number format to a signed *
* short (16 bits). *
****************************************************************************/
signed short CMadDecoder::MadFixedToSshort(mad_fixed_t Fixed)
{
/* A fixed point number is formed of the following bit pattern:
*
* SWWWFFFFFFFFFFFFFFFFFFFFFFFFFFFF
* MSB LSB
* S ==> Sign (0 is positive, 1 is negative)
* W ==> Whole part bits
* F ==> Fractional part bits
*
* This pattern contains MAD_F_FRACBITS fractional bits, one
* should alway use this macro when working on the bits of a fixed
* point number. It is not guaranteed to be constant over the
* different platforms supported by libmad.
*
* The signed short value is formed, after clipping, by the least
* significant whole part bit, followed by the 15 most significant
* fractional part bits. Warning: this is a quick and dirty way to
* compute the 16-bit number, madplay includes much better
* algorithms.
*/
/* 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);
}
// helper function putting synthesized pcm samples into a buffer.
int CMadDecoder::mad_outputpacket(unsigned char* ptr, const unsigned char* endptr) {
//TRACEF(_L("CMadDecoder::outputpacket"));
int counter=0;
if(ptr+4>=endptr) return 0;
int i;
if(iRememberPcmSamples==iSynth.pcm.length) iRememberPcmSamples=0;
for(i=iRememberPcmSamples;i<iSynth.pcm.length;i++,counter++)
{
signed short Sample;
// FIXMAD: eventually fix this warning
#pragma warning( disable : 4244 ) // conversion from int to uchar: possible loss of data
/* Left channel */
Sample=MadFixedToSshort(iSynth.pcm.samples[0][i]);
*(ptr++)=Sample&0xff;
*(ptr++)=Sample>>8;
/* Right channel. If the decoded stream is monophonic then
* the right output channel is the same as the left one.
*/
if(MAD_NCHANNELS(&iFrame.header)==2)
Sample=MadFixedToSshort(iSynth.pcm.samples[1][i]);
*(ptr++)=Sample&0xff;
*(ptr++)=Sample>>8;
if(ptr+4>endptr) {
break;
}
}
iRememberPcmSamples=i;
if(iRememberPcmSamples==iSynth.pcm.length) iRememberPcmSamples=0;
//TRACEF(_L("~CMadDecoder::outputpacket"));
return counter*4;
}
// seek to iGlobalTimer;
// IMPROVE_MAD: There are several issues here:
// o first, the buffers aren't properly cleared, which results in a delay
// where the old buffers are played
// o second, searching itself is just an estimate.
// To do it right, we would have to keep an array with frames and times.
// (see mpg321-0.2.10/mad.c line 222 for inspiration)
// o third, Rob Leslie says that you should call mad_synth_frame() once
// and discard the resulting PCM.
// o Oh, and we don't update the frame counter. Should we?
void CMadDecoder::jumpseek(void) {
int new_position;
int gbt=mad_timer_count (iGlobalTimer, MAD_UNITS_MILLISECONDS);
int tt=TimeTotal().Low();
new_position = (int)((double)gbt /
(double)tt * iFilesize);
new_position =new_position - (INPUT_BUFFER_SIZE+MAD_BUFFER_GUARD);
if(new_position<0) new_position=0;
if (fseek (iInputFp, new_position, SEEK_SET) == -1) {
// FIXMAD: well...
}
mad_frame_mute (&iFrame);
mad_synth_mute (&iSynth);
iStream.error = MAD_ERROR_BUFLEN;
iStream.next_frame = NULL;
iStream.sync = 0;
iTimer=iGlobalTimer;
iPlaystate=EPLAY;
}
// try to figure out the total time.
void CMadDecoder::getframeinfo(void) {
unsigned int lbitrate;
lbitrate = iFrame.header.bitrate / 1000;
vbr_rate += lbitrate;
vbr_frames++;
vbr += (bitrate && bitrate != lbitrate) ? 128 : -1;
if (vbr < 0)
vbr = 0;
else if (vbr > 512)
vbr = 512;
bitrate = lbitrate;
// lucky - timer was in the ID3v2 or in the XING tag
if(mad_timer_compare(iTotalTime,mad_timer_zero)!=0) return;
unsigned long rate;
/* estimate based on size and bitrate */
rate = vbr ? vbr_rate * 125 / vbr_frames : bitrate * 125UL;
mad_timer_set(&iEstTotalTime, 0, iFilesize, rate);
// if ((tag->flags & TAG_XING) &&
// (tag->xing.flags & TAG_XING_FRAMES)) {
// player->stats.total_time = frame->header.duration;
// mad_timer_multiply(&player->stats.total_time, tag->xing.frames);
// }
//
// /* total stream byte size adjustment */
//
// frame_size = stream->next_frame - stream->this_frame;
//
// if (player->stats.total_bytes == 0) {
// if ((tag->flags & TAG_XING) && (tag->xing.flags & TAG_XING_BYTES) &&
// tag->xing.bytes > frame_size)
// player->stats.total_bytes = tag->xing.bytes - frame_size;
// }
// else if (player->stats.total_bytes >=
// stream->next_frame - stream->this_frame)
// player->stats.total_bytes -= frame_size;
}
int CMadDecoder::Clear() {
iGuardPtr=NULL;
iStatus=0;
iBstdFile=0;
iRememberPcmSamples=0;
iTotalTime=mad_timer_zero;
if(filetag) {
id3_file_close(filetag);
filetag=NULL;
}
if(id3tag) {
id3_tag_delete(id3tag);
id3tag=NULL;
}
tag_init(&xltag); //FIXFIXMAD: clear/destruct this !!!!
/* First the structures used by libmad must be initialized. */
mad_stream_init(&iStream);
mad_frame_init(&iFrame);
mad_synth_init(&iSynth);
mad_timer_reset(&iTimer);
mad_timer_reset(&iGlobalTimer);
return 0;
}
int CMadDecoder::Open(FILE* f,const TDesC& aFilename) {
//TRACEF(_L("CMadDecoder::Open"));
// Clear();
iBstdFile=NewBstdFile(f);
if(iBstdFile==NULL)
{
return(1);
}
int fd = wopen((wchar_t*)aFilename.Ptr(), O_RDONLY | O_BINARY);
struct stat buf;
if (fd && (fstat (fd, &buf) != -1)) {
iFilesize = buf.st_size;
}
// dummy read to fill header values
mad_read(NULL,0);
iInputFp=f;
if(id3tag) return 0; // there was an ID3v2 tag at the beginning. Good.
// else we're checking for an ID3v1 tag - slower.
if(fd) filetag = id3_file_fdopen(fd, ID3_FILE_MODE_READONLY);
return 0;
}
int CMadDecoder::OpenInfo(FILE* f,const TDesC& aFilename) {
return Open(f,aFilename);
}
int CMadDecoder::Close(FILE*) {
//TRACEF(_L("CMadDecoder::Close"));
/* The input file was completely read; the memory allocated by our
* reading module must be reclaimed.
*/
BstdFileDestroy(iBstdFile);
if(filetag) {
id3_file_close(filetag);
filetag=NULL;
}
if(id3tag) {
id3_tag_delete(id3tag);
id3tag=NULL;
}
/* Mad is no longer used, the structures that were initialized must
* now be cleared.
*/
mad_synth_finish(&iSynth);
mad_frame_finish(&iFrame);
mad_stream_finish(&iStream);
//TRACEF(_L("~CMadDecoder::Clear"));
return 0;
}
int CMadDecoder::Read(TDes8& aBuffer,int Pos)
{
//TRACEF(_L("CMadDecoder::Read"));
unsigned char* outputbuffer=(unsigned char *) &(aBuffer.Ptr()[Pos]);
int length=aBuffer.MaxLength()-Pos;
return mad_read(outputbuffer,length);
}
/*
mad_read, similar to ov_read from Tremor:
tries to put length bytes of packed PCM data into buffer
return value:
<0) error/hole in data
0) EOF
n) number of bytes of PCM actually returned.
We try to fill the buffer completely though.
Passing outputbuffer=0 will read the header values.
*/
int CMadDecoder::mad_read(unsigned char* outputbuffer,int length)
{
const unsigned char *iOutputBufferEnd=outputbuffer+length;
unsigned char *iOutputPtr=outputbuffer;
int BytesWritten=0;
if(iRememberPcmSamples) {
int CurrentBytesWritten=mad_outputpacket(iOutputPtr,iOutputBufferEnd);
BytesWritten+=CurrentBytesWritten;
iOutputPtr+=CurrentBytesWritten;
}
// it still doesn't fit - so return and try next time
if(iRememberPcmSamples) return BytesWritten;
while(1){
//TRACEF(_L("CMadDecoder::Read while"));
/* The input bucket must be filled if it becomes empty or if
* it's the first execution of the loop.
*/
if(iStream.buffer==NULL || iStream.error==MAD_ERROR_BUFLEN)
{
size_t ReadSize;
size_t Remaining;
unsigned char *ReadStart;
/* {2} libmad may not consume all bytes of the input
* buffer. If the last frame in the buffer is not wholly
* contained by it, then that frame's start is pointed by
* the next_frame member of the Stream structure. This
* common situation occurs when mad_frame_decode() fails,
* sets the stream error code to MAD_ERROR_BUFLEN, and
* sets the next_frame pointer to a non NULL value. (See
* also the comment marked {4} bellow.)
*
* When this occurs, the remaining unused bytes must be
* put back at the beginning of the buffer and taken in
* account before refilling the buffer. This means that
* the input buffer must be large enough to hold a whole
* frame at the highest observable bit-rate (currently 448
* kb/s). XXX=XXX Is 2016 bytes the size of the largest
* frame? (448000*(1152/32000))/8
*/
if(iStream.next_frame!=NULL)
{
Remaining=iStream.bufend-iStream.next_frame;
memmove(InputBuffer,iStream.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.
*/
ReadSize=BstdRead(ReadStart,1,ReadSize,iBstdFile);
if(ReadSize<=0)
{
if(ferror(iInputFp))
{
//fprintf(stderr,"read error on bit-stream \n");
return -1;
}
if(feof(iInputFp))
//fprintf(stderr,"end of input stream\n");
return BytesWritten;
}
/* {3} When decoding the last frame of a file, it must be
* followed by MAD_BUFFER_GUARD zero bytes if one wants to
* decode that last frame. When the end of file is
* detected we append that quantity of bytes at the end of
* the available data. Note that the buffer can't overflow
* as the guard size was allocated but not used the the
* buffer management code. (See also the comment marked
* {1}.)
*
* In a message to the mad-dev mailing list on May 29th,
* 2001, Rob Leslie explains the guard zone as follows:
*
* "The reason for MAD_BUFFER_GUARD has to do with the
* way decoding is performed. In Layer III, Huffman
* decoding may inadvertently read a few bytes beyond
* the end of the buffer in the case of certain invalid
* input. This is not detected until after the fact. To
* prevent this from causing problems, and also to
* ensure the next frame's main_data_begin pointer is
* always accessible, MAD requires MAD_BUFFER_GUARD
* (currently 8) bytes to be present in the buffer past
* the end of the current frame in order to decode the
* frame."
*/
if(BstdFileEofP(iBstdFile))
{
iGuardPtr=ReadStart+ReadSize;
memset(iGuardPtr,0,MAD_BUFFER_GUARD);
ReadSize+=MAD_BUFFER_GUARD;
}
/* Pipe the new buffer content to libmad's stream decoder
* facility.
*/
mad_stream_buffer(&iStream,InputBuffer,ReadSize+Remaining);
iStream.error=MAD_ERROR_NONE;
}
/* Decode the next MPEG frame. The streams is read from the
* buffer, its constituents are break down and stored the the
* Frame structure, ready for examination/alteration or PCM
* synthesis. Decoding options are carried in the Frame
* structure from the Stream structure.
*
* Error handling: mad_frame_decode() returns a non zero value
* when an error occurs. The error condition can be checked in
* the error member of the Stream structure. A mad error is
* recoverable or fatal, the error status is checked with the
* MAD_RECOVERABLE macro.
*
* {4} When a fatal error is encountered all decoding
* activities shall be stopped, except when a MAD_ERROR_BUFLEN
* is signaled. This condition means that the
* mad_frame_decode() function needs more input to complete
* its work. One shall refill the buffer and repeat the
* mad_frame_decode() call. Some bytes may be left unused at
* the end of the buffer if those bytes forms an incomplete
* frame. Before refilling, the remaining bytes must be moved
* to the beginning of the buffer and used for input for the
* next mad_frame_decode() invocation. (See the comments
* marked {2} earlier for more details.)
*
* Recoverable errors are caused by malformed bit-streams, in
* this case one can call again mad_frame_decode() in order to
* skip the faulty part and re-sync to the next frame.
*/
if(mad_frame_decode(&iFrame,&iStream))
{
if(MAD_RECOVERABLE(iStream.error))
{
MadHandleError();
continue;
}
else
if(iStream.error==MAD_ERROR_BUFLEN)
continue;
else
{
return -3;
}
}
/* The characteristics of the stream's first frame is printed
* on stderr. The first frame is representative of the entire
* stream.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -