织梦CMS - 轻松建站从此开始!

罗索

DirectShow音频采集

落鹤生 发布于 2010-10-17 16:17 点击:次 
学习了好长一段时间的directshow,关于视频那一块的一些部分简单地过了一遍,如采集、解压缩、传输 等。现在回过头来学习音频的采集。现在将这几天的学习心得写下来。
TAG:

学习了好长一段时间的directshow,关于视频那一块的一些部分简单地过了一遍,如采集、解压缩、传输 等。现在回过头来学习音频的采集。现在将这几天的学习心得写下来。
 
我们知道directshow对我们的硬件的支持是通过特定的包装Filter来实现的,如我们的声卡是使用的Audio Captue Filter,他在内部有使用了以waveIn开头的一些API函数来实现(学过windows编程就知道,如waveInOpen).这些我们可以通过GraphEdit来检查。
 
下面我们在建一个完整的Filter Graph链路。如下:
 
                                     图(1)
注意:这里用到了一个Filter,WAV Dest。他是我们的DirectShow SDK中的一个例子,位于SDK安装目录的DirectShow\Samples\C++\DirectShow\Filters\WavDest下,主要的功能是在采集时,即PCM数据前部写入文件之后,再在文件头位置插入一个Wave格式的数据块。我们如果要使用到这里,我们必须首先需要编译这个例子并且注册成功后,才能从GraphEdit中添加到这里使用。
由于我们在写入文件的同时,我们需要实时监听,故我们可以使用Smart Tee,当然我们也可以使用Microsoft为我们在DirectShow SDK中提供的Infinite Pin Tee,位于SDK安装目录的DirectShow\Samples\C++\DirectShow\Filters\InfTee下,作用是将输入Pin上输入的数据复制多份(可以多于2份),然后通过输出Pin发送出去。他的使用同WAV Dest。
 
                                      图(2)
    好了,现在开始编写我们的代码了,当然首先要创建一个Audio Capture Filter,由于不同的机器有不同的声卡,还有的机子可能不止一块声卡,所以我们要像采集视频是创建Video Capture Filter一样去枚举系统设备,找到了后再创建。在这里这个过程不在重复了。
并且Microsoft为我们提供了一个好的例子,位于SDK安装目录的DirectShow\Sample\C++
\DirectShow\Capture下的AudioCap。我们可以来参考它。
我们在GraphEdit中加入我们的声卡后会发现它只有一个Capture Output Pin,却有好几个Input Pin。需要说明的是,在GraphEdit中,这些Input Pin 并没有真正的数据流入,他们只是声卡的各个输入端子的象征性表示,所以这些Input Pin永远也不用连接。但是我们在选择了输入端子后,我们必须保证我们的物理连接正确。
AudioCap例子中使用了一个列表控件,同时他还给我们提供了很多很好的工具函数(在mfcutil.cpp文件中, 当建立基于对话框的MFC应用程序时,它可以给我们带来方便),在这里我不赘述,大家可以自己看。
 
我们建立一个基于对话框的MFC应用程序AudioCap。下面是步骤:
①枚举并显示系统设备
  1. HRESULT AuGraph::EnumAudioDevices(CListBox &inListBox) 
  2.     HRESULT hr = NOERROR; 
  3.     // EnumFiltersWithMonikerToList是mfcutil.cpp中提供工具函数,可以为我们枚举系 
  4.     //统设备并添加到inListBox显示,inListBox为我们在对话框上的用于显示系统设备 
  5.     //CListBox控件的变量。 
  6.       hr= ::EnumFiltersWithMonikerToList(NULL,&CLSID_AudioInputDeviceCategory, 
  7. inListBox); 
  8.     if(FAILED(hr)) 
  9.         return hr; 
  10.     return hr; 
②枚举并显示声卡的给个输入pin
  1. HRESULT AuGraph::EnumAudioInputPin(CListBox &inListBox) 
  2.     HRESULT hr = NOERROR; 
  3.     // EnumPinsOnFilter是mfcutil.cpp中提供工具函数,可以为我们枚举声卡的输入Pin并 
  4.     //将他添加到inListBox中来显示,inListBox是我们在对话框上的用于显示声卡的 
  5.     //各个输入Pin的CListBox控件的变量。 
  6.     hr = ::EnumPinsOnFilter(m_pInputDev,PINDIR_INPUT,inListBox); 
  7.     if(FAILED(hr)) 
  8.         return hr; 
  9.     return hr; 
  10.   
③构建Filter Graph
  1. HRESULT AuGraph::GetInterface() 
  2.     HRESULT hr = NOERROR; 
  3.     hr = CoCreateInstance(CLSID_FilterGraph,NULL,CLSCTX_INPROC_SERVER, 
  4.                           IID_IGraphBuilder,(void **)&m_pGB); 
  5.     if(FAILED(hr)) 
  6.         return hr; 
  7.     hr |= m_pGB->QueryInterface(IID_IMediaControl,(void **)&m_pMC); 
  8.     hr |= m_pGB->QueryInterface(IID_IMediaEventEx,  (void **)&m_pME); 
  9.     if(FAILED(hr)) 
  10.         return hr; 
  11.     return hr; 
④现在创建声卡并加到Filter Graph
  1. HRESULT AuGraph::CreateDevices(IMoniker * inMoniker) 
  2.     HRESULT hr = NOERROR; 
  3.     if(inMoniker) 
  4.     { 
  5.         hr = inMoniker->BindToObject(0,0,IID_IBaseFilter,(void **)&m_pInputDev); 
  6.         if(FAILED(hr)) 
  7.             return hr; 
  8.         hr = m_pGB->AddFilter(m_pInputDev,L"Audio Capture"); 
  9.         if(FAILED(hr)) 
  10.             return hr; 
  11.     } 
  12.     return hr; 
⑤按图(1)或图(2)建立整个Filter Graph,在这里我就不写代码了,可以自己添加。
⑥设置输入端子。这是采集音频与采集视频不同的地方,也是最重要的必不可少的一步。
在声卡Filter的给个输入Pin上我们都可以得到IAMAudioInputMixer接口,通过这个接口我们可以设置各个输入端子的音频属性,包括进行音频的合成时是否允许某个输入端子的音频参与混合、音频输入的音量、高音、低音等参数,当然这个接口还可以设置那个输入Pin为我们的输入端子。
  1. HRESULT AuGraph::ActivateSelectInputPin(int inNum,int inIndex)// inNum是我们 
  2. //的声卡上输入pin的个数,inIndex是我们选择作为输入端子的pin的序号(注①) 
  3.     HRESULT hr = NOERROR; 
  4.     CComPtr<IPin>              pInputPin = NULL; 
  5.     CComPtr<IAMAudioInputMixer> pInputMixer = NULL; 
  6.     for(int i=0; i<inNum; i++) 
  7.     { 
  8.         hr = ::GetPin(m_pInputDev,PINDIR_INPUT,i,&pInputPin); 
  9.         if(SUCCEEDED(hr)) 
  10.         { 
  11.             hr = pInputPin->QueryInterface(IID_IAMAudioInputMixer, 
  12. (void **)&pInputMixer); 
  13.             if(SUCCEEDED(hr)) 
  14.             { 
  15.                 if(i == inIndex) 
  16.                     hr = pInputMixer->put_Enable(TRUE);//设置该输入Pin为输入端子 
  17.                 else 
  18.                     hr = pInputMixer->put_Enable(FALSE); 
  19.   
  20.                 if(pInputMixer) 
  21.                     pInputMixer = NULL; 
  22.             } 
  23.   
  24.             if(pInputPin) 
  25.                 pInputPin = NULL; 
  26.         } 
  27.     } 
  28.     return hr; 
⑦运行程序
   当然如果我们的Filter Graph构建成功并且各个Filter连接也成功,就可以运行了
  1. HRESULT AuGraph::AudioRun() 
  2.     HRESULT hr = NOERROR; 
  3.     if(m_pMC) 
  4.     { 
  5.         hr = m_pMC->Run(); 
  6.         if(S_FALSE == hr) 
  7.         { 
  8.             ::AfxMessageBox(L"The filter is not runing!"); 
  9.             return hr; 
  10.         } 
  11.         m_bIsCapture = TRUE; 
  12.     } 
  13.     return hr; 
 
    好了,这就是我们采集音频的整个过程,实际上他是很简单的,但也有一些问题需要我们注意。如:我们在选择了输入端子后,要保证它的物理连接。比如我们选择了麦克风作为输入端子,就要保证机子上的麦克风连接正确而且是可用的
注①:我在利用CListBox控件时,要注意它在显示时是对字符串自动排序显示的,所以我们要在它的属性Sort里去掉这个属性,设置Sort为false。不然我们在选择输入pin时会出错,因为CListBox控件里显示的可能与我们同枚举得到的序号并不一致。
(li_007)
本站文章除注明转载外,均为本站原创或编译欢迎任何形式的转载,但请务必注明出处,尊重他人劳动,同学习共成长。转载请注明:文章转载自:罗索实验室 [http://www.rosoo.net/a/201010/10325.html]
本文出处:CSDN博客 作者:li_007
顶一下
(4)
100%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
将本文分享到微信
织梦二维码生成器
推荐内容