4.使用DShow采集摄像头图像和麦克风声音到本地(摄像头录制)

上一篇介绍如何拍照,这一篇介绍一下如何录制摄像头视频和麦克风的声音,并合成一个视音频文件(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,这样采集出来的视音频文件比较大,没有经过编码的处理,这是后面要解决的问题,具体工作后面再讲。
本篇的界面完成后如下:

4.使用DShow采集摄像头图像和麦克风声音到本地(摄像头录制)_第1张图片

点击采集到本地,即可生成本地AVI视音频文件,注意工程中的路径请按照实际情况修改。
详细工程代码见这里: 工程代码下载
转载请一定注明出处,谢谢!


你可能感兴趣的:(DShow,DShow,DirectShow,filter,摄像头,视音频)