上一篇介绍如何拍照,这一篇介绍一下如何录制摄像头视频和麦克风的声音,并合成一个视音频文件(avi)。
在上一篇的基础上,需要再创建一个本机音频采集设备的Filter,注意,如果你的机器没有音频采集设备,也就是麦克风,那就无法完成下面的工作,或者说只能生成一个视频文件。
首先,创建视频采集Filter,然后创建音频采集设备的Filter,创建过程跟上一篇中创建视频采集设备Filter类似,代码如下:
void CGetDeviceInfoDlg::CreateAudioFilter(CString strSelectedDevice, IBaseFilter **pBaseFilter)
{
ICreateDevEnum *pCreateDevEnum = NULL;
HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
IID_ICreateDevEnum, (void**)&pCreateDevEnum);
IEnumMoniker *pEm = NULL;
hr = pCreateDevEnum->CreateClassEnumerator(CLSID_AudioInputDeviceCategory, &pEm, 0);
if (hr != NOERROR)
return;
ULONG cFetched;
IMoniker *pM = NULL;
while(hr = pEm->Next(1, &pM, &cFetched), hr==S_OK)
{
IPropertyBag *pBag=0;
hr = pM->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pBag);
if(SUCCEEDED(hr))
{
VARIANT var;
var.vt = VT_BSTR;
hr = pBag->Read(L"FriendlyName", &var, NULL); //还有其他属性,像描述信息等等...
if(hr == NOERROR)
{
//获取设备名称
char camera_name[1024];
WideCharToMultiByte(CP_ACP,0,var.bstrVal,-1, camera_name, sizeof(camera_name) ,"",NULL);
CString str(camera_name);
SysFreeString(var.bstrVal);
if (strSelectedDevice == str)
{
hr = pM->BindToObject(0, 0, IID_IBaseFilter, (void**)pBaseFilter);
if (FAILED(hr))
{
OutputDebugString(_T("BindToObject Failed"));
}
}
}
pBag->Release();
}
pM->Release();
}
pEm->Release();
pCreateDevEnum->Release();
}
获取到后,将其加入到图表中去,
HRESULT hr = m_pGraphBuilder->AddFilter(m_pAudioFilter, L"Audio Capture Filter");
if (S_OK != hr)
{
MessageBox(_T("把m_pAudioFilter添加到IGraphBuilder失败"), _T("提示"));
return;
}
后面这一步比较重要,设置需要生产的文件信息,即:
IBaseFilter *pMux = NULL;
IFileSinkFilter *pSink = NULL;
hr = m_pCapture->SetOutputFileName(
&MEDIASUBTYPE_Avi, // Specifies AVI for the target file. MEDIASUBTYPE_Avi
L"D:\\JYSoft\\temp\\myvideo.avi", // File name.
&pMux, // Receives a pointer to the mux.
&pSink); // (Optional) Receives a pointer to the file sink.
//如果要录制多段,可以用下面的语句重命名文件,就能生成新的文件
//pSink->SetFileName(L"D:\\JYSoft\\temp\\Example", pmt);
由于是视音频都要采集,涉及到视音频的同步问题,这里要把音频流作为主流,也就说以音频的时钟为基准,让视频来同步音频。代码如下:
IConfigAviMux *pConfigMux = NULL;
hr = pMux->QueryInterface(IID_IConfigAviMux, (void**)&pConfigMux);
if (SUCCEEDED(hr))
{
pConfigMux->SetMasterStream(1);
}
//这一步要调用,否则时间戳可能不对
IConfigInterleaving *pInterleave = NULL;
hr = pMux->QueryInterface( IID_IConfigInterleaving, (void **)&pInterleave);
if(SUCCEEDED(hr))
{
pInterleave->put_Mode(INTERLEAVE_CAPTURE);
}
其实pMux就代表生成的视音频文件的Filter,下面将其加入图表
m_pGraphBuilder->AddFilter(pMux, L"Video Filter");
然后连接视音频采集设备的Filter到pMux上,即可完成采集到本地的工作,代码如下:
//视频音频都要连到pMux上
m_pCapture->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, m_pVideoFilter, NULL, pMux);
m_pCapture->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Audio, m_pAudioFilter, NULL, pMux);
if (pConfigMux)//记得释放
{
pConfigMux->Release();
}
if (pInterleave)
{
pInterleave->Release();
}
pMux->Release();
以上就是最简单的视音频采集方案,可以看到,视音频采集设备的Filter直接连到视音频文件的Filter上了,中间没有其他Filter,这样采集出来的视音频文件比较大,没有经过编码的处理,这是后面要解决的问题,具体工作后面再讲。
本篇的界面完成后如下: