I'm trying to create a WMV file with video and audio using IMFSikWriter. The video works perfectly, and the audio gets written without any errors. However, upon playing the resulting WMV file, there's no sound.
Further, the source video and audio content, when stored as a WMV file with ffmpeg, occupies about 2 megabytes. The one created with my code occupies about 77 megabytes.
These are the relevant portions of the code I've written - simplified here, with no error checking, as it's not actually running into any errors.
The audio is stored as a PCMWAVFORMAT followed by 16-bit short integer samples.
I suspect that I've omitted setting a parameter that the IMFSinkWriter interface and its various components wants to see.
Madness is setting in - if anyone has any suggestions as to what I should try, I'd be grateful.
Thanks.
HRESULT CreateAudioSinkWriter(IMFSinkWriter *pSinkWriter,DWORD *pStreamIndexAudio,HANDLE hAudio)
{
PCMWAVEFORMAT *pwave = NULL;
IMFMediaType *pAudioType = NULL;
DWORD streamIndexAudio = 0;
HRESULT hr;
long nChannels = 2;
long nSamplesPerSec = 44100;
long wBitsPerSample = 16;
long nBlockAlign = 4;
long nAvgBytesPerSec = 176400;
if(hAudio != NULL) {
if((pwave = (PCMWAVEFORMAT *)GlobalLock(hAudio)) != NULL) {
nChannels = pwave->wf.nChannels;
nSamplesPerSec = pwave->wf.nSamplesPerSec;
wBitsPerSample = pwave->wBitsPerSample;
nBlockAlign = nChannels * (wBitsPerSample / 8);
nAvgBytesPerSec = nBlockAlign * nSamplesPerSec;
GlobalUnlock(hAudio);
}
}
hr = MFCreateMediaType(&pAudioType);
hr = pAudioType->SetGUID(MF_MT_MAJOR_TYPE,MFMediaType_Audio);
hr = pAudioType->SetGUID(MF_MT_SUBTYPE,MFAudioFormat_WMAudioV8);
hr = pAudioType->SetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE,wBitsPerSample);
hr = pAudioType->SetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND,nSamplesPerSec);
hr = pAudioType->SetUINT32(MF_MT_AUDIO_NUM_CHANNELS,nChannels);
hr = pAudioType->SetUINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT,nBlockAlign);
hr = pAudioType->SetUINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND,nAvgBytesPerSec);
hr = pAudioType->SetUINT32(MF_MT_AUDIO_PREFER_WAVEFORMATEX,TRUE);
hr = pSinkWriter->AddStream(pAudioType,&streamIndexAudio);
*pStreamIndexAudio = streamIndexAudio;
SafeRelease(pAudioType);
return(hr);
}
HRESULT CreateSinkWriter(const WCHAR *outputFile,IMFSinkWriter **ppWriter,DWORD *pStreamIndex,DWORD *pStreamIndexAudio,long width,long height,long rate,HANDLE hAudio)
{
*ppWriter = NULL;
*pStreamIndex = NULL;
*pStreamIndexAudio = NULL;
IMFSinkWriter *pSinkWriter=NULL;
IMFAttributes *pAttributes=NULL;
HRESULT hr;
hr = MFCreateAttributes(&pAttributes,2);
hr = pAttributes->SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS,TRUE);
hr = pAttributes->SetUINT32(MF_SINK_WRITER_DISABLE_THROTTLING,TRUE);
hr = MFCreateSinkWriterFromURL(outputFile,NULL,pAttributes,&pSinkWriter);
hr = CreateVideoSinkWriter(pSinkWriter,pStreamIndex,width,height,rate);
hr = CreateAudioSinkWriter(pSinkWriter,pStreamIndexAudio,hAudio);
hr = pSinkWriter->BeginWriting();
*ppWriter = pSinkWriter;
(*ppWriter)->AddRef();
SafeRelease(pAttributes);
SafeRelease(pSinkWriter);
return(hr);
}
HRESULT WriteAudioData(IMFSinkWriter *pWriter,DWORD streamIndex,HANDLE hAudio)
{
HRESULT hr = S_OK;
IMFSample *pSample=NULL;
IMFMediaBuffer *pBuffer=NULL;
DWORD sampleSize = GlobalSize(hAudio) - sizeof(PCMWAVEFORMAT);
PCMWAVEFORMAT *pwave;
LONGLONG duration;
BYTE *pData;
char *ps;
DWORD chunkSize = 8192;
LONGLONG sampleTime = 0;
if((ps = (char *)GlobalLock(hAudio)) == NULL) return(E_OUTOFMEMORY);
pwave = (PCMWAVEFORMAT *)ps;
ps += sizeof(PCMWAVEFORMAT);
while(sampleSize > 0) {
DWORD currentChunkSize = min(chunkSize,sampleSize);
duration = (LONGLONG)((double)currentChunkSize / (pwave->wf.nSamplesPerSec * pwave->wf.nBlockAlign) * 10000000);
hr = MFCreateMemoryBuffer(currentChunkSize,&pBuffer);
hr = pBuffer->Lock(&pData,NULL,NULL);
memcpy(pData,ps,currentChunkSize);
hr = pBuffer->Unlock();
hr = pBuffer->SetCurrentLength(currentChunkSize);
hr = MFCreateSample(&pSample);
hr = pSample->AddBuffer(pBuffer);
hr = pSample->SetSampleTime(sampleTime);
hr = pSample->SetSampleDuration(duration);
hr = pWriter->WriteSample(streamIndex,pSample);
ps += currentChunkSize;
sampleSize -= currentChunkSize;
sampleTime += duration;
SafeRelease(pBuffer);
SafeRelease(pSample);
}
SafeRelease(pBuffer);
SafeRelease(pSample);
GlobalUnlock(hAudio);
return(hr);
}