2.使用DShow进行摄像头预览

上一篇已经获取了视音频设备和编解码器,可能大家有疑问,获取到这些后怎么使用,这里必须得说说Filter了,可以把每个Filter理解成与设备是一一对应关系,每个Filter就像是一个黑盒子,它把与硬件打交道的工作都封装好了,只留出一个个交互的接口。Filter分三种:源Filter,中间处理Filter和目标Filter。源Filter可以是采集设备,比如摄像头、麦克风等;也可以是一个视音频文件。中间处理Filter可以是编解码器,主要是对源Filter进行处理;目标Filter可以是渲染设备,也可以是一个文件。

下面就是三个典型的Filter

2.使用DShow进行摄像头预览_第1张图片

上图中就是采集-》解码-》渲染这样一个过程,下面我们来实现这一过程。

首先,要用代码获得这三个Filter,由于第三个Filter,也就是Video Renderer Filter是系统默认的,所以可以不获取它。那就先获取前两个

由于相机可能是多个,所以选择一个,获取相机Filter代码如下:

//选择设备,并获取Video Capture Filter
void CGetDeviceInfoDlg::CreateVideoFilter(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_VideoInputDeviceCategory, &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);//就是这句获得Filter
					if (FAILED(hr))
					{
						OutputDebugString(_T("BindToObject Failed"));
					}
				}
			}
			pBag->Release();
		}
		pM->Release();
    }

	pEm->Release();
	pCreateDevEnum->Release();
}

代码跟前一篇中获取设备差不多一样,只是加了一句:

hr = pM->BindToObject(0, 0, IID_IBaseFilter, (void**)pBaseFilter);//就是这句获得Filter
获取AVI解码Filter也只有一句话:

HRESULT hr = CoCreateInstance(CLSID_AVIDec, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&m_pAviDecoderFilter); 

然后把这两个Filter添加到图表中

	hr = m_pGraphBuilder->AddFilter(m_pVideoFilter, L"Video Capture Filter");
	if (S_OK != hr)
	{
		MessageBox(_T("把m_pVideoFilter添加到IGraphBuilder失败"), _T("提示"));
		return;
	}
	//将AVI解码过滤器加入图表
	hr = m_pGraphBuilder->AddFilter(m_pAviDecoderFilter, L"Avi Decoder Filter");
	if(S_OK != hr)
	{
		MessageBox(_T("Add Avi Decoder Filter Failed"));
		return;
	}

之后的工作就是连接这两个Filter,并把AVI解码Filter连接到默认的渲染Filter上,也只有一句代码:

HRESULT hr = m_pCapture->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, m_pVideoFilter, m_pAviDecoderFilter, NULL);

之后就是现实预览画面了,代码也很简单,就放在下方的工程中了,下载看看就明白了。

结果如下图:

2.使用DShow进行摄像头预览_第2张图片


详细代码请到这里下载,工程代码下载



你可能感兴趣的:(DShow)