CPI_Player_CoDec_MPEG.c
上传用户:tuheem
上传日期:2007-05-01
资源大小:21889k
文件大小:17k
- /*
- * MPEG 音频解码 (using MAD)
- */
- #include "stdafx.h"
- #include "globals.h"
- #include "CPI_Player_CoDec.h"
- #include "libmad/mad.h"
- // #include "mmsystem.h"
- #include "CPI_Stream.h"
- #include "CPI_ID3.h"
- #pragma comment(lib, "winmm.lib")
- # define SAMPLE_DEPTH 16
- # define scale(x, y) dither((x), (y))
- struct xing {
- long flags;
- unsigned long frames;
- unsigned long bytes;
- unsigned char toc[100];
- long scale;
- };
- enum {
- XING_FRAMES = 0x00000001L,
- XING_BYTES = 0x00000002L,
- XING_TOC = 0x00000004L,
- XING_SCALE = 0x00000008L
- };
- # define XING_MAGIC (('X' << 24) | ('i' << 16) | ('n' << 8) | 'g')
- struct dither {
- mad_fixed_t error[3];
- mad_fixed_t random;
- };
- typedef struct {
- CPs_InStream* m_pInStream;
- unsigned long size;
- CPs_CoDecOptions options;
- struct xing xing;
- struct mad_stream stream;
- struct mad_frame frame;
- struct mad_synth synth;
- unsigned int samplecount;
- mad_timer_t timer;
- mad_timer_t length;
- unsigned long rate;
- unsigned long frames;
- CPs_FileInfo info;
- unsigned char buffer[40000];
- unsigned int buflen;
- } CPs_CoDec_MPEG;
- static
- int parse_xing(struct xing *xing, struct mad_bitptr ptr, unsigned int bitlen)
- {
- if (bitlen < 64 || mad_bit_read(&ptr, 32) != XING_MAGIC)
- goto fail;
- xing->flags = mad_bit_read(&ptr, 32);
- bitlen -= 64;
- if (xing->flags & XING_FRAMES) {
- if (bitlen < 32)
- goto fail;
- xing->frames = mad_bit_read(&ptr, 32);
- bitlen -= 32;
- }
- if (xing->flags & XING_BYTES) {
- if (bitlen < 32)
- goto fail;
- xing->bytes = mad_bit_read(&ptr, 32);
- bitlen -= 32;
- }
- if (xing->flags & XING_TOC) {
- int i;
- if (bitlen < 800)
- goto fail;
- for (i = 0; i < 100; ++i)
- xing->toc[i] = (unsigned char) mad_bit_read(&ptr, 8);
- bitlen -= 800;
- }
- if (xing->flags & XING_SCALE) {
- if (bitlen < 32)
- goto fail;
- xing->scale = mad_bit_read(&ptr, 32);
- bitlen -= 32;
- }
- return 0;
- fail:
- xing->flags = 0;
- return -1;
- }
- static
- int scan_header(CPs_InStream* pInStream, struct mad_header *header, struct xing *xing)
- {
- struct mad_stream stream;
- struct mad_frame frame;
- unsigned char buffer[8192];
- unsigned int buflen = 0;
- int count = 0, result = 0;
- mad_stream_init(&stream);
- mad_frame_init(&frame);
- if (xing)
- xing->flags = 0;
- while (1) {
- if (buflen < sizeof(buffer)) {
- DWORD bytes;
- if(pInStream->Read(pInStream, buffer + buflen, sizeof(buffer) - buflen, &bytes) == FALSE
- || bytes == 0)
- {
- result = -1;
- break;
- }
- buflen += bytes;
- }
- mad_stream_buffer(&stream, buffer, buflen);
- while (1) {
- if (mad_frame_decode(&frame, &stream) == -1) {
- if (!MAD_RECOVERABLE(stream.error))
- break;
- continue;
- }
- if (count++ ||
- (xing && parse_xing(xing, stream.anc_ptr,
- stream.anc_bitlen) == 0))
- break;
- }
- if (count || stream.error != MAD_ERROR_BUFLEN)
- break;
- memmove(buffer, stream.next_frame,
- buflen = &buffer[buflen] - stream.next_frame);
- }
- if (count) {
- if (header)
- *header = frame.header;
- }
- else
- result = -1;
- mad_frame_finish(&frame);
- mad_stream_finish(&stream);
- return result;
- }
- static __inline
- unsigned long prng(unsigned long state)
- {
- return (state * 0x0019660dL + 0x3c6ef35fL) & 0xffffffffL;
- }
- static __inline
- signed int dither(mad_fixed_t sample, struct dither *dither)
- {
- unsigned int scalebits;
- mad_fixed_t output, mask, random;
- enum {
- MIN = -MAD_F_ONE,
- MAX = MAD_F_ONE - 1
- };
- sample += dither->error[0] - dither->error[1] + dither->error[2];
- dither->error[2] = dither->error[1];
- dither->error[1] = dither->error[0] / 2;
- output = sample + (1L << (MAD_F_FRACBITS + 1 - SAMPLE_DEPTH - 1));
- scalebits = MAD_F_FRACBITS + 1 - SAMPLE_DEPTH;
- mask = (1L << scalebits) - 1;
- random = prng(dither->random);
- output += (random & mask) - (dither->random & mask);
- dither->random = random;
- if (output > MAX) {
- output = MAX;
- if (sample > MAX)
- sample = MAX;
- }
- else if (output < MIN) {
- output = MIN;
- if (sample < MIN)
- sample = MIN;
- }
- output &= ~mask;
- dither->error[0] = sample - output;
- return output >> scalebits;
- }
- static
- void pack_pcm(unsigned char **pcm, unsigned int nsamples,
- mad_fixed_t const *ch1, mad_fixed_t const *ch2)
- {
- register signed int s0, s1;
- static struct dither d0, d1;
- if (ch2) { /* stereo */
- while (nsamples--) {
- s0 = scale(*ch1++, &d0);
- s1 = scale(*ch2++, &d1);
- # if SAMPLE_DEPTH == 16
- (*pcm)[0 + 0] = s0 >> 0;
- (*pcm)[0 + 1] = s0 >> 8;
- (*pcm)[2 + 0] = s1 >> 0;
- (*pcm)[2 + 1] = s1 >> 8;
- *pcm += 2 * 2;
- # elif SAMPLE_DEPTH == 8
- (*pcm)[0] = s0 ^ 0x80;
- (*pcm)[1] = s1 ^ 0x80;
- *pcm += 2;
- # else
- # error "bad SAMPLE_DEPTH"
- # endif
- }
- }
- else { /* mono */
- while (nsamples--) {
- s0 = scale(*ch1++, &d0);
- # if SAMPLE_DEPTH == 16
- (*pcm)[0] = s0 >> 0;
- (*pcm)[1] = s0 >> 8;
- *pcm += 2;
- # elif SAMPLE_DEPTH == 8
- *(*pcm)++ = s0 ^ 0x80;
- # endif
- }
- }
- }
- static void cleanup(CPs_CoDec_MPEG *context)
- {
- if(context->m_pInStream)
- {
- context->m_pInStream->Uninitialise(context->m_pInStream);
- context->m_pInStream = NULL;
- mad_synth_finish(&context->synth);
- mad_frame_finish(&context->frame);
- mad_stream_finish(&context->stream);
- }
- }
- void CPP_OMMP3_Uninitialise(CPs_CoDecModule* pModule);
- BOOL CPP_OMMP3_OpenFile(CPs_CoDecModule* pModule, const char* pcFilename, DWORD dwCookie, HWND hWndOwner);
- void CPP_OMMP3_CloseFile(CPs_CoDecModule* pModule);
- void CPP_OMMP3_Seek(CPs_CoDecModule* pModule, const int iNumerator, const int iDenominator);
- void CPP_OMMP3_GetFileInfo(CPs_CoDecModule* pModule, CPs_FileInfo* pInfo);
- //
- BOOL CPP_OMMP3_GetPCMBlock(CPs_CoDecModule* pModule, void* pBlock, DWORD* pdwBlockSize);
- int CPP_OMMP3_GetCurrentPos_secs(CPs_CoDecModule* pModule);
- //
- void CP_InitialiseCodec_MPEG(CPs_CoDecModule* pCoDec)
- {
- CPs_CoDec_MPEG *pContext;
- pCoDec->Uninitialise = CPP_OMMP3_Uninitialise;
- pCoDec->OpenFile = CPP_OMMP3_OpenFile;
- pCoDec->CloseFile = CPP_OMMP3_CloseFile;
- pCoDec->Seek = CPP_OMMP3_Seek;
- pCoDec->GetFileInfo = CPP_OMMP3_GetFileInfo;
- pCoDec->GetPCMBlock = CPP_OMMP3_GetPCMBlock;
- pCoDec->GetCurrentPos_secs = CPP_OMMP3_GetCurrentPos_secs;
- pCoDec->m_pModuleCookie = malloc(sizeof(CPs_CoDec_MPEG));
- pContext = (CPs_CoDec_MPEG*)pCoDec->m_pModuleCookie;
- pContext->m_pInStream = NULL;
- pContext->size = 0;
- pContext->options.m_iPretendOption = 42;
- pContext->xing.flags = 0;
- pContext->samplecount = 0;
- pContext->timer = mad_timer_zero;
- pContext->length = mad_timer_zero;
- pContext->rate = 0;
- pContext->frames = 0;
- pContext->info.m_iFileLength_Secs = 0;
- pContext->info.m_iBitRate_Kbs = 0;
- pContext->info.m_iFreq_Hz = 0;
- pContext->info.m_bStereo = TRUE;
- pContext->info.m_b16bit = (SAMPLE_DEPTH == 16);
- pContext->buflen = 0;
- CPFA_InitialiseFileAssociations(pCoDec);
- CPFA_AddFileAssociation(pCoDec, "MP3", 0L);
- CPFA_AddFileAssociation(pCoDec, "MP2", 0L);
- CPFA_AddFileAssociation(pCoDec, "MP1", 0L);
- }
- void CPP_OMMP3_Uninitialise(CPs_CoDecModule* pModule)
- {
- CPs_CoDec_MPEG *context = (CPs_CoDec_MPEG *)pModule->m_pModuleCookie;
- CP_CHECKOBJECT(context);
- cleanup(context);
- free(context);
- CPFA_EmptyFileAssociations(pModule);
- }
- BOOL CPP_OMMP3_OpenFile(CPs_CoDecModule* pModule, char const *path, DWORD dwCookie, HWND hWndOwner)
- {
- CPs_CoDec_MPEG *context = (CPs_CoDec_MPEG *)pModule->m_pModuleCookie;
- int iStreamStart = 0;
- CP_CHECKOBJECT(context);
- cleanup(context);
- CP_TRACE1("CPI_CoDec__OpenFile: "%s"", path);
- context->m_pInStream = CP_CreateInStream(path, hWndOwner);
- if(!context->m_pInStream)
- {
- CP_TRACE0("CPI_CoDec__OpenFile: failed");
- return FALSE;
- }
- if(context->m_pInStream->IsSeekable(context->m_pInStream) == TRUE)
- {
- CIs_ID3v2Tag tag;
- unsigned int iBytesRead;
- memset(&tag, 0, sizeof(tag));
- context->m_pInStream->Read(context->m_pInStream, &tag, sizeof(tag), &iBytesRead);
- if(memcmp(tag.m_cTAG, "ID3", 3) == 0)
- {
- iStreamStart = sizeof(CIs_ID3v2Tag);
- iStreamStart += (tag.m_cSize_Encoded[0] << 21)
- | (tag.m_cSize_Encoded[1] << 14)
- | (tag.m_cSize_Encoded[2] << 7)
- | tag.m_cSize_Encoded[3];
- }
- context->m_pInStream->Seek(context->m_pInStream, iStreamStart);
- }
- mad_stream_init(&context->stream);
- mad_frame_init(&context->frame);
- mad_synth_init(&context->synth);
- if (scan_header(context->m_pInStream,
- &context->frame.header, &context->xing) == -1) {
- CP_TRACE0("CPI_CoDec__OpenFile: failed to read file header");
- cleanup(context);
- return FALSE;
- }
- context->m_pInStream->Seek(context->m_pInStream, iStreamStart);
- context->size = context->m_pInStream->GetLength(context->m_pInStream);
- context->synth.pcm.length = 0;
- context->samplecount = 0;
- context->timer = mad_timer_zero;
- if (context->xing.flags & XING_FRAMES) {
- context->length = context->frame.header.duration;
- mad_timer_multiply(&context->length, context->xing.frames);
- }
- else {
- mad_timer_set(&context->length, 0,
- 1, context->frame.header.bitrate / 8);
- mad_timer_multiply(&context->length, context->size);
- }
- context->rate = 0;
- context->frames = 0;
- context->info.m_iFileLength_Secs =
- mad_timer_count(context->length, MAD_UNITS_SECONDS);
- context->info.m_iBitRate_Kbs = context->frame.header.bitrate / 1000;
- context->info.m_iFreq_Hz = context->frame.header.samplerate;
- context->info.m_bStereo =
- context->frame.header.mode == MAD_MODE_SINGLE_CHANNEL ? FALSE : TRUE;
- context->info.m_b16bit = (SAMPLE_DEPTH == 16);
- context->buflen = 0;
- return TRUE;
- }
- void CPP_OMMP3_CloseFile(CPs_CoDecModule* pModule)
- {
- CPs_CoDec_MPEG *context = (CPs_CoDec_MPEG *)pModule->m_pModuleCookie;
- CP_CHECKOBJECT(context);
- CP_TRACE0("Close MPEG file");
- cleanup(context);
- }
- void CPP_OMMP3_Seek(CPs_CoDecModule* pModule, int const numer, int const denom)
- {
- CPs_CoDec_MPEG *context = (CPs_CoDec_MPEG *)pModule->m_pModuleCookie;
- double fraction;
- unsigned long position;
- CP_CHECKOBJECT(context);
- CP_ASSERT(context->m_pInStream);
- CP_ASSERT(numer >= 0 && denom > 0);
- if(context->m_pInStream->IsSeekable(context->m_pInStream) == FALSE)
- return;
- fraction = (double) numer / denom;
- position = (unsigned long)
- (mad_timer_count(context->length, MAD_UNITS_MILLISECONDS) * fraction);
- mad_timer_set(&context->timer, position / 1000, position % 1000, 1000);
- if (context->xing.flags & XING_TOC) {
- int percent, p1, p2;
- percent = (int) (fraction * 100);
- p1 = (percent < 100) ? context->xing.toc[percent ] : 0x100;
- p2 = (percent < 99) ? context->xing.toc[percent + 1] : 0x100;
- fraction = (p1 + (p2 - p1) * (fraction * 100 - percent)) / 0x100;
- }
- context->m_pInStream->Seek(context->m_pInStream, (LONG) (context->size * fraction));
- if(context->m_pInStream->Read(context->m_pInStream, context->buffer, sizeof(context->buffer),&context->buflen) == FALSE)
- context->buflen = 0;
- mad_stream_buffer(&context->stream, context->buffer, context->buflen);
- mad_frame_mute(&context->frame);
- mad_synth_mute(&context->synth);
- if (numer) {
- int skip;
- skip = 2;
- do {
- if (mad_frame_decode(&context->frame, &context->stream) == 0) {
- mad_timer_add(&context->timer, context->frame.header.duration);
- if (--skip == 0)
- mad_synth_frame(&context->synth, &context->frame);
- }
- else if (!MAD_RECOVERABLE(context->stream.error))
- break;
- }
- while (skip);
- }
- context->synth.pcm.length = 0;
- context->samplecount = 0;
- }
- BOOL CPP_OMMP3_GetPCMBlock(CPs_CoDecModule* pModule, void *block, DWORD *size)
- {
- CPs_CoDec_MPEG *context = (CPs_CoDec_MPEG *)pModule->m_pModuleCookie;
- unsigned char *samples = block;
- unsigned int nsamples;
- CP_CHECKOBJECT(context);
- CP_ASSERT(context->m_pInStream);
- nsamples = (*size / (SAMPLE_DEPTH / 8)) >>
- (context->info.m_bStereo ? 1 : 0);
- *size = 0;
- while (nsamples) {
- unsigned int count, bitrate;
- count = context->synth.pcm.length - context->samplecount;
- if (count > nsamples)
- count = nsamples;
- if (count) {
- mad_fixed_t const *ch1, *ch2;
- ch1 = context->synth.pcm.samples[0] + context->samplecount;
- ch2 = context->synth.pcm.samples[1] + context->samplecount;
- if (context->info.m_bStereo == FALSE)
- ch2 = 0;
- else if (context->synth.pcm.channels == 1)
- ch2 = ch1;
- pack_pcm(&samples, count, ch1, ch2);
- context->samplecount += count;
- nsamples -= count;
- if (nsamples == 0)
- break;
- }
- while (mad_frame_decode(&context->frame, &context->stream) == -1) {
- DWORD bytes;
- if (MAD_RECOVERABLE(context->stream.error))
- continue;
- if (context->stream.next_frame) {
- memmove(context->buffer, context->stream.next_frame,
- context->buflen = context->buffer +
- context->buflen - context->stream.next_frame);
- }
- if(context->m_pInStream->Read(context->m_pInStream,
- context->buffer + context->buflen,
- sizeof(context->buffer) - context->buflen, &bytes) == FALSE
- || bytes == 0)
- {
- return FALSE;
- }
- mad_stream_buffer(&context->stream,
- context->buffer, context->buflen += bytes);
- }
- bitrate = context->frame.header.bitrate / 1000;
- context->rate += bitrate;
- context->frames++;
- context->info.m_iBitRate_Kbs = bitrate;
- mad_synth_frame(&context->synth, &context->frame);
- context->samplecount = 0;
- mad_timer_add(&context->timer, context->frame.header.duration);
- }
- *size = samples - (unsigned char *) block;
- return TRUE;
- }
- void CPP_OMMP3_GetFileInfo(CPs_CoDecModule* pModule, CPs_FileInfo *info)
- {
- CPs_CoDec_MPEG *context = (CPs_CoDec_MPEG *)pModule->m_pModuleCookie;
- CP_CHECKOBJECT(context);
- if (!(context->xing.flags & XING_FRAMES) && context->frames) {
- mad_timer_set(&context->length, 0,
- 1, (context->rate / context->frames) * (1000 / 8));
- mad_timer_multiply(&context->length, context->size);
- if (mad_timer_compare(context->timer, context->length) > 0)
- {
- context->length = context->timer;
- context->size = context->m_pInStream->GetLength(context->m_pInStream);
- }
- context->info.m_iFileLength_Secs =
- mad_timer_count(context->length, MAD_UNITS_SECONDS);
- }
- *info = context->info;
- }
- int CPP_OMMP3_GetCurrentPos_secs(CPs_CoDecModule* pModule)
- {
- CPs_CoDec_MPEG *context = (CPs_CoDec_MPEG *)pModule->m_pModuleCookie;
- CP_CHECKOBJECT(context);
- return mad_timer_count(context->timer, MAD_UNITS_SECONDS);
- }