📄 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 <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <vfw.h>
#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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -