Windows视频 - 添加音频流到AVI
问题描述:
我真的很简单的程序添加一个音频流添加到一个AVI文件与预先存在的视频流。 问题是生成的文件包含视频流,但流中没有任何数据。 音频文件由DirectX示例中的SDKwavefile读取。Windows视频 - 添加音频流到AVI
AVIFileInit();
PAVIFILE avi;
AVIFileOpen(&avi, argv[1], OF_WRITE, NULL);
CWaveFile wav;
wav.Open(argv[2], NULL, WAVEFILE_READ);
WAVEFORMATEX *wavFormat = wav.GetFormat();
PAVISTREAM audioStream;
AVIFileCreateStream(avi, &audioStream, &audioInfo);
AVISTREAMINFO audioInfo;
memset(&audioInfo, 0, sizeof(AVISTREAMINFO));
audioInfo.fccType = streamtypeAUDIO;
audioInfo.dwScale = wavFormat->nBlockAlign;
audioInfo.dwRate = wavFormat->nSamplesPerSec * wavFormat->nBlockAlign;
audioInfo.dwSampleSize = wavFormat->nBlockAlign;
audioInfo.dwQuality = (DWORD)-1;
AVIStreamSetFormat(audioStream, 0, wavFormat, sizeof(WAVEFORMATEX));
BYTE *data = (BYTE *)malloc(wav.GetSize());
DWORD sizeRead;
wav.Read(data, wav.GetSize(), &sizeRead);
AVIStreamWrite(audioStream, 0, (wav.GetSize() * 8)/wavFormat->wBitsPerSample, data, wav.GetSize(), 0, NULL, NULL);
AVIStreamRelease(audioStream);
free(data);
wav.Close();
AVIFileRelease(avi);
AVIFileExit();
(另外,我知道我不应该再使用VFW,但这一决定必须高于我的头的方式,我也知道我不检查任何事物的结果,可以晚一点。)
谢谢。
答
我试图用它来添加一个.wav到现有的.avi(虽然我有一个类CWaveSoundRead)。 如果你检查返回码,你会得到AVIStreamWrite(),它返回0x80044065,结果是AVIERR_UNSUPPORTED。
事后看来,我会说你在填充AVISTREAMINFO对象之前调用了AVIFileCreateStream()。实际上,现在我明白了,很难想象你的代码是按原样编译的,因为audioInfo是在AVIFileCreateStream之后定义的!
这里的东西我做到了,尽管它仍然失误音频流长:
struct FmtChunk {
char id[4]; //="fmt "
unsigned long size; //=16 or 0x28
short wFormatTag; //=WAVE_FORMAT_PCM=1
unsigned short wChannels; //=1 or 2 for mono or stereo
unsigned long dwSamplesPerSec; //=11025 or 22050 or 44100
unsigned long dwAvgBytesPerSec; //=wBlockAlign * dwSamplesPerSec
unsigned short wBlockAlign; //=wChannels * (wBitsPerSample==8?1:2)
unsigned short wBitsPerSample; //=8 or 16, for bits per sample
};
struct DataChunk {
char id[4]; //="data"
unsigned long size; //=datsize, size of the following array
unsigned char data[1]; //=the raw data goes here
};
struct WavChunk {
char id[4]; //="RIFF"
unsigned long size; //=datsize+8+16+4
char type[4]; //="WAVE"
};
bool Q_AVI_AddWav(cstring fnameVideo,cstring fnameAudio)
// Adds a .wav file to an existing .avi (with video stream)
{
IAVIStream* m_pStreamAudio=0;
HRESULT hr;
AVIFileInit();
PAVIFILE avi;
hr=AVIFileOpen(&avi, fnameVideo,OF_WRITE,NULL);
CHECK(hr,"AVIFileOpen");
WavChunk wav;
FmtChunk fmt;
DataChunk dat;
//read wav file
FILE *fr;
int pos;
fr=qfopen(fnameAudio,"rb");
// Read header
fread(&wav,1,sizeof(wav),fr);
// Read 'fmt' chunk; may be 16 or 40 in length
pos=ftell(fr);
fread(&fmt,1,sizeof(fmt),fr);
if(fmt.size==40)fseek(fr,40-16,SEEK_CUR); // Skip rest of fmt
// else it's ok
// Read data specs
fread(&dat,sizeof(dat),1,fr);
char *buf = new char[dat.size];
qdbg("Wav data %d bytes\n",dat.size);
fread(buf,1,dat.size,fr);
qfclose(fr);
// set wave format info
WAVEFORMATEX wfx;
wfx.wFormatTag=fmt.wFormatTag;
wfx.cbSize=0;
wfx.nAvgBytesPerSec=fmt.dwAvgBytesPerSec;
wfx.nBlockAlign=fmt.wBlockAlign;
wfx.nChannels=fmt.wChannels;
wfx.nSamplesPerSec=fmt.dwSamplesPerSec;
wfx.wBitsPerSample=fmt.wBitsPerSample;
// create audio stream
AVISTREAMINFO ahdr; ZeroMemory(&ahdr,sizeof(ahdr));
ahdr.fccType=streamtypeAUDIO;
ahdr.dwScale=wfx.nBlockAlign;
ahdr.dwRate=wfx.nSamplesPerSec*wfx.nBlockAlign;
ahdr.dwSampleSize=wfx.nBlockAlign;
ahdr.dwQuality=(DWORD)-1;
hr=AVIFileCreateStream(avi, &m_pStreamAudio, &ahdr);
CHECK(hr,"AVIFileCreateStream");
if(hr!=AVIERR_OK) {if (buf) QDELETE_ARRAY(buf); /*delete[] buf;*/ return false;}
hr = AVIStreamSetFormat(m_pStreamAudio,0,&wfx,sizeof(WAVEFORMATEX));
CHECK(hr,"AVIStreamSetFormat");
if(hr!=AVIERR_OK) {if (buf) QDELETE_ARRAY(buf); /*delete[] buf;*/ return false;}
//write audio stream
unsigned long numbytes = dat.size;
unsigned long numsamps = fmt.wChannels*numbytes*8/wfx.wBitsPerSample;
hr = AVIStreamWrite(m_pStreamAudio,0,numsamps,buf,numbytes,0,0,0);
CHECK(hr,"AVIStreamWrite");
qdbg("Write numsamps %d, numbytes %d\n",numsamps,numbytes);
QDELETE_ARRAY(buf); //if(buf)delete[] buf;
// Release audio stream
AVIStreamRelease(m_pStreamAudio);
// Close AVI
hr=AVIFileRelease(avi);
CHECK(hr,"AVIFileRelease");
// Close VFW
AVIFileExit();
return hr==AVIERR_OK;
}