www.pudn.com > XvidQP.rar > AudioSource.cpp
// VirtualDub - Video processing and capture application // Copyright (C) 1998-2001 Avery Lee // // 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., 675 Mass Ave, Cambridge, MA 02139, USA. #include#include #include #include #include "AudioSource.h" #include "AVIReadHandler.h" #include "AC3FileSrc.h" AudioSourceWAV::AudioSourceWAV(char *szFile, LONG inputBufferSize) { MMIOINFO mmi; memset(&mmi,0,sizeof mmi); mmi.cchBuffer = inputBufferSize; hmmioFile = mmioOpen(szFile, &mmi, MMIO_READ | MMIO_ALLOCBUF); } AudioSourceWAV::~AudioSourceWAV() { mmioClose(hmmioFile, 0); } BOOL AudioSourceWAV::init() { if (!hmmioFile) return FALSE; chunkRIFF.fccType = mmioFOURCC('W','A','V','E'); if (MMSYSERR_NOERROR != mmioDescend(hmmioFile, &chunkRIFF, NULL, MMIO_FINDRIFF)) return FALSE; chunkDATA.ckid = mmioFOURCC('f','m','t',' '); if (MMSYSERR_NOERROR != mmioDescend(hmmioFile, &chunkDATA, &chunkRIFF, MMIO_FINDCHUNK)) return FALSE; if (!allocFormat(chunkDATA.cksize)) return FALSE; if (chunkDATA.cksize != mmioRead(hmmioFile, (char *)getWaveFormat(), chunkDATA.cksize)) return FALSE; if (MMSYSERR_NOERROR != mmioAscend(hmmioFile, &chunkDATA, 0)) return FALSE; chunkDATA.ckid = mmioFOURCC('d','a','t','a'); if (MMSYSERR_NOERROR != mmioDescend(hmmioFile, &chunkDATA, &chunkRIFF, MMIO_FINDCHUNK)) return FALSE; bytesPerSample = getWaveFormat()->nBlockAlign; //getWaveFormat()->nAvgBytesPerSec / getWaveFormat()->nSamplesPerSec; lSampleFirst = 0; lSampleLast = chunkDATA.cksize / bytesPerSample; lCurrentSample = 0; streamInfo.fccType = streamtypeAUDIO; streamInfo.fccHandler = 0; streamInfo.dwFlags = 0; streamInfo.wPriority = 0; streamInfo.wLanguage = 0; streamInfo.dwInitialFrames = 0; streamInfo.dwScale = bytesPerSample; streamInfo.dwRate = getWaveFormat()->nAvgBytesPerSec; streamInfo.dwStart = 0; streamInfo.dwLength = chunkDATA.cksize / bytesPerSample; streamInfo.dwSuggestedBufferSize = 0; streamInfo.dwQuality = 0xffffffff; streamInfo.dwSampleSize = bytesPerSample; return TRUE; } int AudioSourceWAV::_read(LONG lStart, LONG lCount, LPVOID buffer, LONG cbBuffer, LONG *lBytesRead, LONG *lSamplesRead) { LONG lBytes = lCount * bytesPerSample; if (buffer) { if (lStart != lCurrentSample) if (-1 == mmioSeek(hmmioFile, chunkDATA.dwDataOffset + bytesPerSample*lStart, SEEK_SET)) return AVIERR_FILEREAD; if (lBytes != mmioRead(hmmioFile, (char *)buffer, lBytes)) return AVIERR_FILEREAD; lCurrentSample = lStart + lCount; } *lSamplesRead = lCount; *lBytesRead = lBytes; return AVIERR_OK; } /////////////////////////// AudioSourceAVI::AudioSourceAVI(IAVIReadHandler *pAVI) { pAVIFile = pAVI; pAVIStream = NULL; } AudioSourceAVI::~AudioSourceAVI() { if (pAVIStream) delete pAVIStream; } BOOL AudioSourceAVI::init() { LONG format_len; pAVIStream = pAVIFile->GetStream(streamtypeAUDIO, 0); if (!pAVIStream) return FALSE; if (pAVIStream->Info(&streamInfo, sizeof streamInfo)) return FALSE; pAVIStream->FormatSize(0, &format_len); if (!allocFormat(format_len)) return FALSE; if (pAVIStream->ReadFormat(0, getFormat(), &format_len)) return FALSE; lSampleFirst = pAVIStream->Start(); lSampleLast = pAVIStream->End(); return TRUE; } void AudioSourceAVI::Reinit() { pAVIStream->Info(&streamInfo, sizeof streamInfo); lSampleFirst = pAVIStream->Start(); lSampleLast = pAVIStream->End(); } bool AudioSourceAVI::isStreaming() { return pAVIStream->isStreaming(); } void AudioSourceAVI::streamBegin(bool fRealTime) { pAVIStream->BeginStreaming(lSampleFirst, lSampleLast, fRealTime ? 1000 : 2000); } void AudioSourceAVI::streamEnd() { pAVIStream->EndStreaming(); } BOOL AudioSourceAVI::_isKey(LONG lSample) { return pAVIStream->IsKeyFrame(lSample); } int AudioSourceAVI::_read(LONG lStart, LONG lCount, LPVOID lpBuffer, LONG cbBuffer, LONG *lpBytesRead, LONG *lpSamplesRead) { int err; long lBytes, lSamples; // There are some video clips roaming around with truncated audio streams // (audio streams that state their length as being longer than they // really are). We use a kludge here to get around the problem. err = pAVIStream->Read(lStart, lCount, lpBuffer, cbBuffer, lpBytesRead, lpSamplesRead); if (err != AVIERR_FILEREAD) return err; // Suspect a truncated stream. // // AVISTREAMREAD_CONVENIENT will tell us if we're actually encountering a // true read error or not. At least for the AVI handler, it returns // AVIERR_ERROR if we've broached the end. *lpBytesRead = *lpSamplesRead = 0; while(lCount > 0) { err = pAVIStream->Read(lStart, AVISTREAMREAD_CONVENIENT, NULL, 0, &lBytes, &lSamples); if (err) return 0; if (!lSamples) return AVIERR_OK; if (lSamples > lCount) lSamples = lCount; err = pAVIStream->Read(lStart, lSamples, lpBuffer, cbBuffer, &lBytes, &lSamples); if (err) return err; lpBuffer = (LPVOID)((char *)lpBuffer + lBytes); cbBuffer -= lBytes; lCount -= lSamples; *lpBytesRead += lBytes; *lpSamplesRead += lSamples; } return AVIERR_OK; } /////////////////////////////////////////////////////////////////////////////////////////////////// // Dummy CRC pointer Crc16 *crc; AudioSourceMP3::AudioSourceMP3(char *szFile) { stream = new Ibitstream(szFile); header = new Header; f = fopen( szFile, "rb" ); } AudioSourceMP3::~AudioSourceMP3() { if( f ) fclose( f ); delete header; delete stream; } BOOL AudioSourceMP3::init() { if( !f ) return FALSE; if (!header->read_header(stream, &crc)){ return FALSE; } do { } while( header->read_header(stream, &crc) ); real s_len = (stream->current_frame()+1)*header->ms_per_frame()/1000; if (!allocFormat(sizeof MPEGLAYER3WAVEFORMAT)) return FALSE; MPEGLAYER3WAVEFORMAT *mp3format = (MPEGLAYER3WAVEFORMAT *)getWaveFormat(); mp3format->wfx.wFormatTag = WAVE_FORMAT_MPEGLAYER3; /* format type */ mp3format->wfx.nChannels = (header->mode() == single_channel) ? 1 : 2; /* number of channels (i.e. mono, stereo...) */ mp3format->wfx.nSamplesPerSec = header->frequency(); /* sample rate */ mp3format->wfx.nAvgBytesPerSec = stream->file_size()/s_len; /* for buffer estimation */ mp3format->wfx.nBlockAlign = 1152; /* block size of data */ mp3format->wfx.wBitsPerSample = 0; /* Number of bits per sample of mono data */ mp3format->wfx.cbSize = 12; /* The count in bytes of the size of extra information (after cbSize) */ mp3format->wID = 1; mp3format->fdwFlags = 2; mp3format->nBlockSize = stream->file_size()/(stream->current_frame()+1); mp3format->nFramesPerBlock = 1; mp3format->nCodecDelay = 0; lSampleFirst = 0; lSampleLast = stream->current_frame()+1; streamInfo.fccType = streamtypeAUDIO; streamInfo.fccHandler = 0; streamInfo.dwFlags = 0; streamInfo.wPriority = 0; streamInfo.wLanguage = 0; streamInfo.dwInitialFrames = 0; streamInfo.dwScale = 1152; streamInfo.dwRate = header->frequency(); streamInfo.dwStart = 0; streamInfo.dwLength = lSampleLast; streamInfo.dwSuggestedBufferSize = 0; streamInfo.dwQuality = 0xffffffff; streamInfo.dwSampleSize = 0; delete header; header = new Header; stream->reset(); pos = 0; header->read_header(stream, &crc); return TRUE; } int AudioSourceMP3::_read(LONG lStart, LONG lCount, LPVOID buffer, LONG cbBuffer, LONG *lBytesRead, LONG *lSamplesRead) { *lSamplesRead = 0; *lBytesRead = 0; if( buffer ) { if (lStart != stream->current_frame()) { delete header; header = new Header; stream->reset(); while( stream->current_frame() != lStart ) { pos = stream->file_pos(); header->read_header(stream, &crc); } } uint32 frame_size = stream->file_pos() - pos; if( frame_size>cbBuffer ) return AVIERR_OK; fseek( f, pos, SEEK_SET ); fread( buffer, frame_size, 1, f ); cbBuffer -= frame_size; buffer = (void *)(((unsigned long)buffer)+frame_size); (*lBytesRead) += frame_size; pos = stream->file_pos(); header->read_header(stream, &crc); (*lSamplesRead) = 1; } return AVIERR_OK; } /////////////////////////////////////////////////////////////////////////////////////////////////// AudioSourceOggVorbis::AudioSourceOggVorbis(char *szFile) { f = fopen( szFile, "rb" ); pos = 0; } AudioSourceOggVorbis::~AudioSourceOggVorbis() { if( f ) fclose( f ); } #ifndef _WAVEFORMATEXTENSIBLE_ #define _WAVEFORMATEXTENSIBLE_ #pragma pack(1) typedef struct { WAVEFORMATEX Format; union { WORD wValidBitsPerSample; /* bits of precision */ WORD wSamplesPerBlock; /* valid if wBitsPerSample==0 */ WORD wReserved; /* If neither applies, set to zero. */ } Samples; DWORD dwChannelMask; /* which channels are */ /* present in stream */ GUID SubFormat; } WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE; #pragma pack() #endif // !_WAVEFORMATEXTENSIBLE_ BOOL AudioSourceOggVorbis::streamInit() { char *buffer; int bytes; eos = 0; while( ogg_sync_pageout( &oy, &og )!=1 ) { buffer = ogg_sync_buffer( &oy, 1 ); bytes = fread( buffer, 1, 1, f ); ogg_sync_wrote( &oy, bytes ); } ogg_stream_init( &os, ogg_page_serialno( &og ) ); vorbis_info_init( &vi ); vorbis_comment_init( &vc ); if( ogg_stream_pagein( &os, &og )<0 ) { return FALSE; } if( ogg_stream_packetout( &os, &op )!=1 ) { return FALSE; } if( vorbis_synthesis_headerin( &vi, &vc, &op )<0 ) { return FALSE; } int i = 0; while( i<2 ) { while( i<2 ) { int result = ogg_sync_pageout( &oy, &og ); if( result==0 ) break; /* Need more data */ /* Don't complain about missing or corrupt data yet. We'll catch it at the packet output phase */ if( result==1 ) { ogg_stream_pagein( &os, &og ); /* we can ignore any errors here as they'll also become apparent at packetout */ while( i<2 ) { result = ogg_stream_packetout( &os, &op ); if( result==0 ) break; if( result<0 ) { /* Uh oh; data at some point was corrupted or missing! We can't tolerate that in a header. Die. */ return FALSE; } vorbis_synthesis_headerin( &vi, &vc, &op ); i++; } } } /* no harm in not checking before adding more */ buffer = ogg_sync_buffer( &oy, 1 ); bytes = fread( buffer, 1, 1, f ); if( bytes==0 && i<2 ) { return FALSE; } ogg_sync_wrote( &oy, bytes ); } fgetpos( f, &pos ); --pos; vorbis_synthesis_init( &vd, &vi ); vorbis_block_init( &vd, &vb ); return TRUE; } typedef unsigned __int8 uint8; //typedef unsigned __int32 uint32; typedef unsigned __int64 uint64; bool splitHeader( const uint8* Buffer, size_t BufferSize, size_t& SplitPosition, uint8** Header,size_t*HeaderSize ) { // Just for your information, here's the format of an Ogg Page header: #pragma pack(1) struct PageHeader { // Flag values enum { CONTINUED=1 ,BOS=2 ,EOS=4 }; char Magic[4]; // The String "OggS" in ASCII uint8 Version; // Currently 0 uint8 Flags; // Enf of stream, Beginning of stream uint64 GranulePos; // Not used for header packets. This is big endian !!! uint32 Serial; // serial number of the stream used for multiplexing/chaining uint32 PageNumber; // Page number within the stream uint32 CRC; // CRC value, similar to the ZIP CRC32, but with swapped bits. For more info I can provide a small Java class. uint8 LacingCount; }; #pragma pack() uint8*HeaderStart[3]={Header[0],Header[1],Header[2]}; const uint8*BufferStart=Buffer; for(size_t PacketIndex=0;PacketIndex<3;) { // Read the next header if(BufferSize (Buffer); Buffer+=sizeof(PageHeader); BufferSize-=sizeof(PageHeader); // Verify some fields if(CurrentPageHeader->Magic[0]!='O' ||CurrentPageHeader->Magic[1]!='g' ||CurrentPageHeader->Magic[2]!='g' ||CurrentPageHeader->Magic[3]!='S' ) return false; // Our minimum requirement failed, see above for details if(CurrentPageHeader->LacingCount>BufferSize) return false; // No data available for lacing values const uint8*CurrentLacings=Buffer; Buffer+=CurrentPageHeader->LacingCount; BufferSize-=CurrentPageHeader->LacingCount; for(uint8 LacingIndex=0;PacketIndex<3&&LacingIndex LacingCount;) { for(;PacketIndex<3&&LacingIndex LacingCount;++LacingIndex) { if(BufferSize LacingCount-1)) return false; ++PacketIndex; } } } } // Buffer points to the end of the last header page SplitPosition=Buffer-BufferStart; for(size_t i=0;i<3;++i) { HeaderSize[i]=Header[i]-HeaderStart[i]; Header[i]=HeaderStart[i]; } return true; } BOOL AudioSourceOggVorbis::init() { if( !f ) return FALSE; char *buffer; int bytes; ogg_sync_init(&oy); /* Now we can read pages */ if( streamInit()==FALSE ) return FALSE; fseek( f, 0, SEEK_SET ); uint8* Buffer = (uint8*)malloc( pos ); size_t Size = fread( Buffer, 1, pos, f ); uint8* Header = (uint8*)malloc( pos ); uint8* Comments = (uint8*)malloc( pos ); uint8* Codebook = (uint8*)malloc( pos ); if( Buffer==NULL || Header==NULL || Comments==NULL || Codebook==NULL ) { failed: if( Buffer ) free( Buffer ); if( Header ) free( Header ); if( Comments ) free( Comments ); if( Codebook ) free( Codebook ); return FALSE; } size_t SplitPosition; size_t PacketSizes[] = { pos, pos, pos }; uint8* PacketAddresses[] = { Header, Comments, Codebook }; if( splitHeader( Buffer, Size, SplitPosition, PacketAddresses, PacketSizes )==FALSE ) goto failed; int s = sizeof(WAVEFORMATEXTENSIBLE)+3*sizeof(size_t)+PacketSizes[0]+PacketSizes[1]+PacketSizes[2]; s = (s+7) & -8; if( !allocFormat( s ) ) goto failed; // prepare WAVEFORMAT WAVEFORMATEXTENSIBLE *wfext = (WAVEFORMATEXTENSIBLE *)getWaveFormat(); wfext->Format.wFormatTag = 0xFFFE; // WAVE_FORMAT_EXTENSIBLE wfext->Format.nChannels = vi.channels; wfext->Format.nSamplesPerSec = vi.rate; wfext->Format.nAvgBytesPerSec = 176400; wfext->Format.nBlockAlign = 20000; // ahem, testing... wfext->Format.wBitsPerSample = 0; wfext->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) +3*sizeof(size_t) +PacketSizes[0]+PacketSizes[1]+PacketSizes[2] -sizeof(WAVEFORMATEX); // wfext->Samples.wValidBitsPerSample = 0; /* bits of precision */ // wfext->Samples.wSamplesPerBlock = 0; /* valid if wBitsPerSample==0 */ wfext->Samples.wReserved = 0; /* If neither applies, set to zero. */ wfext->dwChannelMask = (1< SubFormat = guid; // append the Ogg headers to the Wav header char* p = (char*)getWaveFormat()+sizeof(WAVEFORMATEXTENSIBLE); *(size_t*)p = PacketSizes[0]; p += sizeof(size_t); *(size_t*)p = PacketSizes[1]; p += sizeof(size_t); *(size_t*)p = PacketSizes[2]; p += sizeof(size_t); memcpy( p, PacketAddresses[0], PacketSizes[0] ); p += PacketSizes[0]; memcpy( p, PacketAddresses[1], PacketSizes[1] ); p += PacketSizes[1]; memcpy( p, PacketAddresses[2], PacketSizes[2] ); p += PacketSizes[2]; // We need to know the length of the stream. Sure, there are other methods... int tot_pcm_samples = 0; // vorbis_synthesis_init( &vd, &vi ); // vorbis_block_init( &vd, &vb ); while( !eos ) { while( !eos ) { int result = ogg_sync_pageout( &oy, &og ); if( result==0 ) break; if( result<0 ){ //fprintf(stderr,"Corrupt or missing data in bitstream; continuing...\n"); }else{ ogg_stream_pagein( &os, &og ); while( TRUE ) { result = ogg_stream_packetout( &os, &op ); if( result==0 ) break; if( result<0 ) { /* no reason to complain; already complained above */ }else{ int samples; float **pcm; if( vorbis_synthesis( &vb, &op )==0 ) /* test for success! */ vorbis_synthesis_blockin( &vd, &vb ); if( (samples=vorbis_synthesis_pcmout( &vd, &pcm ))>0) { tot_pcm_samples += samples; vorbis_synthesis_read( &vd, samples ); } } } if( ogg_page_eos( &og ) ) eos = 1; } } if( !eos ) { buffer = ogg_sync_buffer( &oy, 1 ); bytes = fread( buffer, 1, 1, f); ogg_sync_wrote( &oy, bytes ); if( bytes==0 ) eos = 1; } } ogg_stream_clear( &os ); vorbis_block_clear( &vb ); vorbis_dsp_clear( &vd ); vorbis_comment_clear( &vc ); vorbis_info_clear( &vi ); // init some variables lSampleFirst = 0; lSampleLast = (tot_pcm_samples/20000)+1; pcm_samples = 0; pcm_written = 0; // reset the input fseek( f, 0, SEEK_SET ); streamInit(); while( pcm_samples<20000 ) { readPage(); decodePage(); } lCurrentSample = 0; if( Buffer ) free( Buffer ); if( Header ) free( Header ); if( Comments ) free( Comments ); if( Codebook ) free( Codebook ); // prepare StreamInfo streamInfo.fccType = streamtypeAUDIO; streamInfo.fccHandler = 0; streamInfo.dwFlags = 0; streamInfo.wPriority = 0; streamInfo.wLanguage = 0; streamInfo.dwInitialFrames = 0; streamInfo.dwScale = 20000; streamInfo.dwRate = vi.rate; streamInfo.dwStart = 0; streamInfo.dwLength = lSampleLast; streamInfo.dwSuggestedBufferSize = 0; streamInfo.dwQuality = 0xffffffff; streamInfo.dwSampleSize = 0; return TRUE; } void AudioSourceOggVorbis::readPage() { char *buffer; int bytes; while( eos==0 && ogg_sync_pageout( &oy, &og )!=1 ) { buffer = ogg_sync_buffer( &oy, 1 ); bytes = fread( buffer, 1, 1, f ); ogg_sync_wrote( &oy, bytes ); if( bytes==0 ) eos = 1; } } void AudioSourceOggVorbis::decodePage() { ogg_stream_pagein( &os, &og ); while( TRUE ) { int result = ogg_stream_packetout( &os, &op ); if( result==0 ) break; if( result<0 ) { /* no reason to complain; already complained above */ }else{ int samples; float **pcm; if( vorbis_synthesis( &vb, &op )==0 ) /* test for success! */ vorbis_synthesis_blockin( &vd, &vb ); if( (samples=vorbis_synthesis_pcmout( &vd, &pcm ))>0) { pcm_samples += samples; vorbis_synthesis_read( &vd, samples ); } } } if( ogg_page_eos( &og ) ) eos = 1; } int AudioSourceOggVorbis::_read(LONG lStart, LONG lCount, LPVOID buffer, LONG cbBuffer, LONG *lBytesRead, LONG *lSamplesRead) { *lSamplesRead = 0; *lBytesRead = 0; if( buffer ) { if (lStart != lCurrentSample) { ogg_stream_clear( &os ); vorbis_block_clear( &vb ); vorbis_dsp_clear( &vd ); vorbis_comment_clear( &vc ); vorbis_info_clear( &vi ); fseek( f, 0, SEEK_SET ); streamInit(); readPage(); lCurrentSample = 0; while( lStart != lCurrentSample ) { fgetpos( f, &pos ); readPage(); lCurrentSample++; } } __int64 pos2; fgetpos( f, &pos2 ); uint32 frame_size = (uint32)pos2 - pos; if( frame_size>cbBuffer ) return AVIERR_OK; fseek( f, pos, SEEK_SET ); fread( buffer, frame_size, 1, f ); cbBuffer -= frame_size; buffer = (void *)(((unsigned long)buffer)+frame_size); (*lBytesRead) += frame_size; pcm_samples -= 20000; pos = pos2; while( pcm_samples<20000 ) { readPage(); decodePage(); } lCurrentSample++; (*lSamplesRead) = 1; } return AVIERR_OK; } /////////////////////////////////////////////////////////////////////////////////////////////////////// AudioSourceAC3::AudioSourceAC3(char *szFile, LONG inputBufferSize) { ac3File = fopen(szFile,"rb"); } AudioSourceAC3::~AudioSourceAC3() { if (ac3File!=NULL) fclose(ac3File); } BOOL AudioSourceAC3::init() { WAVEFORMATEX *fmt, ac3WFmt; if( ac3File==NULL ) return FALSE; // extract WAVEFORMATEX from the AC3 file AC3FileSrc *ac3Src = new AC3FileSrc(ac3File); if( !ac3Src->Parse(&ac3WFmt) ) { delete ac3Src; return FALSE; } delete ac3Src; // allocate format structure if (!(fmt=(WAVEFORMATEX *) allocFormat(sizeof(WAVEFORMATEX)))) return FALSE; *fmt = ac3WFmt; { char szBuf[256]; sprintf(szBuf, "FmtTag: 0x%x, SampFreq: %d, Channels: %d, bitrate: %d kb/s", fmt->wFormatTag, fmt->nSamplesPerSec, fmt->nChannels, (fmt->nAvgBytesPerSec*8)/1000); MessageBox(NULL,szBuf,"AC3 file parameters",MB_OK); } // get the length of the file fseek(ac3File,0,SEEK_END); chunkDATA.cksize = ftell(ac3File); chunkDATA.dwDataOffset = 0; fseek(ac3File,0,SEEK_SET); bytesPerSample= getWaveFormat()->nBlockAlign; //getWaveFormat()->nAvgBytesPerSec / getWaveFormat()->nSamplesPerSec; lSampleFirst = 0; lSampleLast = chunkDATA.cksize / bytesPerSample; lCurrentSample= 0; streamInfo.fccType = streamtypeAUDIO; streamInfo.fccHandler = 0; streamInfo.dwFlags = 0; streamInfo.wPriority = 0; streamInfo.wLanguage = 0; streamInfo.dwInitialFrames = 0; streamInfo.dwScale = bytesPerSample; streamInfo.dwRate = getWaveFormat()->nAvgBytesPerSec; streamInfo.dwStart = 0; streamInfo.dwLength = chunkDATA.cksize / bytesPerSample; streamInfo.dwSuggestedBufferSize = 0; streamInfo.dwQuality = 0xffffffff; streamInfo.dwSampleSize = bytesPerSample; return TRUE; } int AudioSourceAC3::_read(LONG lStart, LONG lCount, LPVOID buffer, LONG cbBuffer, LONG *lBytesRead, LONG *lSamplesRead) { LONG lBytes = lCount * bytesPerSample; if (lStart != lCurrentSample) if (-1 == fseek(ac3File, chunkDATA.dwDataOffset + bytesPerSample*lStart, SEEK_SET)) return AVIERR_FILEREAD; if (lBytes != fread((char *)buffer, 1, lBytes, ac3File)) return AVIERR_FILEREAD; *lSamplesRead = lCount; *lBytesRead = lBytes; lCurrentSample = lStart + lCount; return AVIERR_OK; }