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&&LacingIndexLacingCount;) 
		 { 
			 for(;PacketIndex<3&&LacingIndexLacingCount;++LacingIndex) 
			 { 
				 if(BufferSizeLacingCount-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; 
}