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

时间:2022-08-26 13:30:30

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

下面就是三个典型的Filter

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

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

首先,要用代码获得这三个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进行摄像头预览


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