libmad.c
资源名称:tcpmp.rar [点击查看]
上传用户:wstnjxml
上传日期:2014-04-03
资源大小:7248k
文件大小:10k
源码类别:
Windows CE
开发平台:
C/C++
- /*****************************************************************************
- *
- * 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
- *
- * $Id: libmad.c 543 2006-01-07 22:06:24Z picard $
- *
- * The Core Pocket Media Player
- * Copyright (c) 2004-2005 Gabor Kovacs
- *
- ****************************************************************************/
- #include "../common/common.h"
- #include "libmad.h"
- #include "libmad/frame.h"
- #include "libmad/synth.h"
- typedef struct libmad
- {
- codec Codec;
- buffer Buffer;
- struct mad_stream Stream;
- struct mad_frame Frame;
- struct mad_synth Synth;
- int BufferAlign;
- int AdjustBytes; // adjust (rewind) RefTime
- bool_t Skip; // skip next frame
- int AdjustTime;
- int FormatSet;
- } libmad;
- static INLINE void UpdateAdjustTime( libmad* p )
- {
- if (p->Codec.In.Format.ByteRate)
- p->AdjustTime = (TICKSPERSEC * 4096) / p->Codec.In.Format.ByteRate;
- else
- p->AdjustTime = 0;
- }
- static int UpdateInput( libmad* p )
- {
- BufferClear(&p->Buffer);
- mad_frame_finish(&p->Frame);
- mad_stream_finish(&p->Stream);
- mad_synth_finish(&p->Synth);
- if (p->Codec.In.Format.Type == PACKET_AUDIO)
- {
- PacketFormatPCM(&p->Codec.Out.Format,&p->Codec.In.Format,MAD_F_FRACBITS+1);
- p->Codec.Out.Format.Format.Audio.Flags = PCM_PLANES;
- p->FormatSet = 0;
- p->AdjustBytes = 0;
- UpdateAdjustTime(p);
- mad_stream_init(&p->Stream);
- mad_frame_init(&p->Frame);
- mad_synth_init(&p->Synth);
- }
- return ERR_NONE;
- }
- static int Process( libmad* p, const packet* Packet, const flowstate* State )
- {
- if (Packet)
- {
- // remove processed bytes from buffer
- BufferPack(&p->Buffer,p->Stream.next_frame - p->Stream.buffer);
- // set new reftime
- if (Packet->RefTime >= 0)
- {
- p->Codec.Packet.RefTime = Packet->RefTime;
- p->AdjustBytes = p->Buffer.WritePos - p->Buffer.ReadPos;
- }
- // add new packet to buffer
- BufferWrite(&p->Buffer,Packet->Data[0],Packet->Length,p->BufferAlign);
- mad_stream_buffer(&p->Stream, p->Buffer.Data+p->Buffer.ReadPos, p->Buffer.WritePos-p->Buffer.ReadPos);
- }
- else
- p->Codec.Packet.RefTime = TIME_UNKNOWN;
- for (;;)
- {
- while (mad_frame_decode(&p->Frame, &p->Stream) == -1)
- {
- if (p->Stream.error == MAD_ERROR_BUFLEN || p->Stream.error == MAD_ERROR_BUFPTR)
- return ERR_NEED_MORE_DATA;
- if (p->Stream.error == MAD_ERROR_NOMEM)
- {
- BufferDrop(&p->Buffer);
- return ERR_OUT_OF_MEMORY;
- }
- }
- if (p->Skip)
- {
- // the first frame, it may be corrupt
- p->Skip--;
- continue;
- }
- mad_synth_frame(&p->Synth,&p->Frame);
- // handle stereo streams with random mono frames (is this really a good mp3?)
- if (p->Codec.Out.Format.Format.Audio.Channels==2 && p->Synth.pcm.channels==1)
- {
- p->Synth.pcm.channels = 2;
- memcpy(p->Synth.pcm.samples[1],p->Synth.pcm.samples[0],
- p->Synth.pcm.length * sizeof(mad_fixed_t));
- }
- if (p->Codec.In.Format.ByteRate != (int)(p->Frame.header.bitrate >> 3))
- {
- p->Codec.In.Format.ByteRate = (p->Frame.header.bitrate >> 3);
- UpdateAdjustTime(p);
- }
- // adjust RefTime with AdjustBytes (now that we know the bitrate)
- if (p->Codec.Packet.RefTime >= 0)
- p->Codec.Packet.RefTime -= (p->AdjustBytes * p->AdjustTime) >> 12;
- // output format setup needed?
- if (p->Codec.Out.Format.Format.Audio.SampleRate != (int)p->Synth.pcm.samplerate ||
- p->Codec.Out.Format.Format.Audio.Channels != p->Synth.pcm.channels)
- {
- if (p->FormatSet)
- {
- p->FormatSet--;
- continue; // probably a bad frame, drop it
- }
- // set new output format
- p->Codec.In.Format.Format.Audio.SampleRate = p->Codec.Out.Format.Format.Audio.SampleRate = p->Synth.pcm.samplerate;
- p->Codec.In.Format.Format.Audio.Channels = p->Codec.Out.Format.Format.Audio.Channels = p->Synth.pcm.channels;
- ConnectionUpdate(&p->Codec.Node,CODEC_OUTPUT,p->Codec.Out.Pin.Node,p->Codec.Out.Pin.No);
- }
- p->FormatSet = 16; // reset countdown
- break;
- }
- // build output packet
- p->Codec.Packet.Length = p->Synth.pcm.length * sizeof(mad_fixed_t);
- p->Codec.Packet.Data[0] = p->Synth.pcm.samples[0];
- p->Codec.Packet.Data[1] = p->Synth.pcm.samples[1];
- return ERR_NONE;
- }
- static int Flush( libmad* p )
- {
- BufferDrop(&p->Buffer);
- p->Skip = 1;
- mad_frame_finish(&p->Frame);
- mad_synth_finish(&p->Synth);
- mad_stream_finish(&p->Stream);
- mad_frame_init(&p->Frame);
- mad_synth_init(&p->Synth);
- mad_stream_init(&p->Stream);
- return ERR_NONE;
- }
- #ifdef BUILDFIXED
- #include <math.h>
- extern struct fixedfloat {
- unsigned long mantissa : 27;
- unsigned long exponent : 5;
- } rq_table[8207];
- #endif
- static int Create( libmad* p )
- {
- p->Codec.Process = (packetprocess)Process;
- p->Codec.UpdateInput = (nodefunc)UpdateInput;
- p->Codec.Flush = (nodefunc)Flush;
- p->BufferAlign = Context()->LowMemory?4096:16384;
- return ERR_NONE;
- }
- #define XING_FRAMES 0x01
- #define XING_BYTES 0x02
- #define XING_TOC 0x04
- #define XING_SCALE 0x08
- typedef struct mp3
- {
- rawaudio RawAudio;
- int Frames;
- int Bytes;
- bool_t TOC;
- uint8_t TOCTable[100];
- int VBRITableSize;
- int VBRIEntryFrames;
- int* VBRITable;
- } mp3;
- static int Read(format_reader* Reader,int n)
- {
- int v=0;
- while (n--)
- {
- v = v << 8;
- v += Reader->Read8(Reader);
- }
- return v;
- }
- static int InitMP3(mp3* p)
- {
- static const int RateTable[4] = { 44100, 48000, 32000, 99999 };
- format_reader* Reader;
- int i,SampleRate,Id,Mode,Layer,SamplePerFrame;
- int Result = RawAudioInit(&p->RawAudio);
- p->TOC = 0;
- p->Bytes = p->RawAudio.Format.FileSize - p->RawAudio.Head;
- p->Frames = 0;
- p->RawAudio.VBR = 0;
- Reader = p->RawAudio.Format.Reader;
- for (i=0;i<2048;++i)
- if (Reader->Read8(Reader) == 0xFF)
- {
- filepos_t Frame;
- i = Reader->Read8(Reader);
- if ((i & 0xE0) != 0xE0)
- continue;
- Id = (i >> 3) & 3;
- Layer = (i >> 1) & 3;
- SampleRate = RateTable[(Reader->Read8(Reader) >> 2) & 3];
- if (Id==2)
- SampleRate >>= 1; // MPEG2
- if (Id==0)
- SampleRate >>= 2; // MPEG2.5
- Mode = (Reader->Read8(Reader) >> 6) & 3;
- SamplePerFrame = (Layer == 3)?384:1152;
- Frame = Reader->FilePos;
- //Xing offset
- if (Id==3)
- {
- // MPEG1
- Reader->Skip(Reader,Mode==3 ? 17:32);
- }
- else
- {
- // MPEG2/2.5
- Reader->Skip(Reader,Mode==3 ? 9:17);
- if (Layer == 1) // layer-3
- SamplePerFrame = 576;
- }
- if (Reader->ReadLE32(Reader) == FOURCCLE('X','i','n','g'))
- {
- int Flags = Reader->ReadBE32(Reader);
- if (Flags & XING_FRAMES)
- p->Frames = Reader->ReadBE32(Reader);
- if (Flags & XING_BYTES)
- p->Bytes = Reader->ReadBE32(Reader);
- if (Flags & XING_TOC)
- {
- p->TOC = 1;
- Reader->Read(Reader,p->TOCTable,100);
- }
- }
- else
- {
- Reader->Seek(Reader,Frame+32,SEEK_SET);
- if (Reader->ReadLE32(Reader) == FOURCCLE('V','B','R','I'))
- {
- int Scale,EntryBytes;
- Reader->Skip(Reader,2+2+2); //Version,Delay,Quality
- p->Bytes= Reader->ReadBE32(Reader);
- p->Frames = Reader->ReadBE32(Reader);
- p->VBRITableSize = Reader->ReadBE16(Reader)+1;
- Scale = Reader->ReadBE16(Reader);
- EntryBytes = Reader->ReadBE16(Reader);
- p->VBRIEntryFrames = Reader->ReadBE16(Reader);
- p->VBRITable = malloc(sizeof(int)*p->VBRITableSize);
- if (p->VBRITable)
- for (i=0;i<p->VBRITableSize;++i)
- p->VBRITable[i] = Read(Reader,EntryBytes)*Scale;
- }
- }
- if (p->Frames>0)
- {
- p->RawAudio.VBR = 1;
- p->RawAudio.Format.Duration = Scale(p->Frames,TICKSPERSEC*SamplePerFrame,SampleRate);
- if (p->Bytes>0)
- p->RawAudio.Format.Streams[0]->Format.ByteRate = Scale(p->Bytes,TICKSPERSEC,p->RawAudio.Format.Duration);
- }
- break;
- }
- Reader->Seek(Reader,p->RawAudio.Head,SEEK_SET);
- return Result;
- }
- static void DoneMP3(mp3* p)
- {
- if (p->VBRITable)
- {
- free(p->VBRITable);
- p->VBRITable = NULL;
- }
- }
- static int SeekMP3(mp3* p, tick_t Time, filepos_t FilePos,bool_t PrevKey)
- {
- if (FilePos < 0 && Time > 0 && p->RawAudio.Format.Duration > 0)
- {
- int i,a,b;
- if (Time > p->RawAudio.Format.Duration)
- Time = p->RawAudio.Format.Duration;
- if (p->VBRITable)
- {
- int i;
- tick_t Left;
- tick_t EntryTime = p->RawAudio.Format.Duration / p->VBRITableSize;
- FilePos = p->RawAudio.Head;
- Left = Time;
- for (i=0;Left>0 && i<p->VBRITableSize;++i)
- {
- FilePos += p->VBRITable[i];
- Left -= EntryTime;
- }
- if (i>0)
- FilePos += Scale(Left,p->VBRITable[i-1],EntryTime);
- }
- else
- if (p->TOC && p->Bytes>0)
- {
- i = Scale(Time,100,p->RawAudio.Format.Duration);
- if (i>99) i=99;
- a = p->TOCTable[i];
- if (i==99)
- b = 256;
- else
- b = p->TOCTable[i+1];
- a <<= 10;
- b <<= 10;
- a += Scale(Time - Scale(i,p->RawAudio.Format.Duration,100),b-a,p->RawAudio.Format.Duration);
- FilePos = p->RawAudio.Head + Scale(a,p->Bytes,256*1024);
- }
- }
- return RawAudioSeek(&p->RawAudio,Time,FilePos,PrevKey);
- }
- static int CreateMP3( mp3* p )
- {
- p->RawAudio.Format.Init = (fmtfunc)InitMP3;
- p->RawAudio.Format.Done = (fmtvoid)DoneMP3;
- p->RawAudio.Format.Seek = (fmtseek)SeekMP3;
- return ERR_NONE;
- }
- static const nodedef MP3 =
- {
- sizeof(mp3),
- MP3_ID,
- RAWAUDIO_CLASS,
- PRI_DEFAULT-5,
- (nodecreate)CreateMP3,
- };
- static const nodedef LibMad =
- {
- sizeof(libmad),
- LIBMAD_ID,
- CODEC_CLASS,
- PRI_DEFAULT-5,
- (nodecreate)Create,
- };
- void LibMad_Init()
- {
- #ifdef BUILDFIXED
- int x;
- struct fixedfloat* p=rq_table;
- for (x=0;x<8207;++x,++p)
- {
- int exp;
- double v = frexp(pow(x,4./3.),&exp);
- if (exp) ++exp;
- p->exponent = (unsigned short)exp;
- p->mantissa = (int)(0x10000000 * (v*0.5));
- }
- #endif
- NodeRegisterClass(&LibMad);
- NodeRegisterClass(&MP3);
- }
- void LibMad_Done()
- {
- NodeUnRegisterClass(LIBMAD_ID);
- NodeUnRegisterClass(MP3_ID);
- }