void BuildAudioCaptureGraph(void) // Warning! No error checking here. { IBaseFilter *pSrc = NULL, *pWaveDest = NULL, *pWriter = NULL; IFileSinkFilter *pSink= NULL; IGraphBuilder *pGraph; // Create the Filter Graph Manager. CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void**)&pGraph); // Add the audio capture filter. FindAudioCapture(&pSrc); // Assume that this function enumerates // audio capture devices and picks one. pGraph->AddFilter(pSrc, L"Capture"); // Add the WavDest and the File Writer. AddFilterByClsid(pGraph, L"WavDest", CLSID_WavDest, &pWavDest); AddFilterByClsid(pGraph, L"File Writer", CLSID_FileWriter, &pWriter); // Set the file name. pWriter->QueryInterface(IID_IFileSinkFilter, (void**)&pSink); pSink->SetFileName(L"C:\\MyWackyWav.wav", NULL); // Hook everything up. ConnectTwoFilters(pGraph, pSrc, pWavDest); ConnectTwoFilters(pGraph, pWavDest, pWriter); }当然,在进行音频捕捉的同时,我们还可以实时监听音频源的输入。我们在Audio Capture Filter后面接了一个Infinite Pin Tee,这个Filter能够将一个Input pin输入的数据,复制成多份,分别通过各个Output pin发送出去。(这个Filter也是微软DirectX SDK带的一个例子,在samples\Multimedia\DirectShow\Filters\ InfTee目录下。)我们看到Tee Filter的一支连到了DirectSound Renderer,可以将声音放在声卡上输出。 创建音频捕捉的应用程序很简单吧!下面,我们还要来讨论一下音频捕捉前可能用到的一些参数设置。在声卡Filter的每个Input pin上,我们都可以得到IAMAudioInputMixer这个接口。通过这个接口,我们可以设置各个输入端子的音频属性,如进行音频合成时是否允许某个输入端子的音频参与混合、音频输入的音量,还有Tree、Bass等等。另外,在Filter上也可以得到IAMAudioInputMixer接口,这时调用接口方法就可以统一控制各个输入端子的属性。音频捕捉,还可以设置的是音频的采样频率以及声音的具体格式(8Bits或16Bits,单声道或双声道)。我们可以通过Capture output pin的IAMStreamConfig来完成。下面的代码可供参考:
HRESULT hr = pCapturePin->QueryInterface(IID_IAMStreamConfig, (void **)&pCfg); // Read current media type/format AM_MEDIA_TYPE *pmt={0}; hr = pCfg->GetFormat(&pmt); if (SUCCEEDED(hr)) { // Fill in values for the new format WAVEFORMATEX *pWF = (WAVEFORMATEX *) pmt->pbFormat; pWF->nChannels = (WORD) nChannels; pWF->nSamplesPerSec = nFrequency; pWF->nAvgBytesPerSec = lBytesPerSecond; pWF->wBitsPerSample = (WORD) (nBytesPerSample * 8); pWF->nBlockAlign = (WORD) (nBytesPerSample * nChannels); // Set the new formattype for the output pin hr = pCfg->SetFormat(pmt); DeleteMediaType(pmt); } // Release interfaces pCfg->Release();
pCapturePin->QueryInterface(IID_IAMBufferNegotiation, (void **)&pNeg); // Set the buffer size based on selected settings ALLOCATOR_PROPERTIES prop={0}; prop.cbBuffer = lBufferSize; prop.cBuffers = 6; prop.cbAlign = nBytesPerSample * nChannels; hr = pNeg->SuggestAllocatorProperties(&prop); pNeg->Release();
以上,我们讲述了音频捕捉程序的创建过程,以及一些捕捉参数的设置方法。相信大家对于如何写音频捕捉程序已经有了自己的认识。音频捕捉直接得到的是PCM数据,根据需要,我们还可以对其进行压缩,比如用Mp3格式(微软提供了一个免费的Mp3 Encoder)、AC3格式等等;压缩后数据量更少,可以符合很多场合的应用。
PS:对于格式,有一系列的选择,但是建议在11025HZ、16位、单通道;22050HZ、16位、单通道中选择。选择格式的时候,不要尝试使用立体声,立体声浪费处理时间,而且效果很难评估。同样也不要使用16位以外的采样精度,因为这会导致音质的大幅下降。对于采样频率来说,越高越好,但是也不要设置超过22050HZ,在这个采样频率下,也能表现出CD音质的水准而没有太多的损失。
// setup the WAVEFORMATEX structure WAVEFORMATEX wave_format; ZeroMemory(&wave_format, sizeof(WAVEFORMATEX)); wave_format.wFormatTag = WAVE_FORMAT_PCM; wave_format.nChannels = 1; // mono wave_format.nSamplesPerSec = 11025; wave_format.wBitsPerSample = 16; wave_format.nBlockAlign = (wave_format.wBitsPerSample / 8) * wave_format.nChannels; wave_format.nAvgBytesPerSec = wave_format.nSamplesPerSec * wave_format.nBlockAlign;