VS2010 C++学习(5):基于DirectShow的视频预览录像程序(二)

2014-11-24 08:11:26 · 作者: · 浏览: 1
滤器呢?

用户可以采用枚举的方式列举系统中安装的设备。

以列举系统中的视频捕捉设备为例,

(1) 首先定义一个设备列举接口 ICreateDevEnum的一个指针;

(2) 调用CoCreateInstance方法创建ICreateDevEnum实例。

(3) 然后定义一个列举监视器 IEnumMoniker的一个指针;

(4) 调用ICreateDevEnum实例的CreateClassEnumerator方法创建 IEnumMoniker实例。

(5) 最后以循环的方式调用IEnumMoniker实例的Next方法遍历系统设备;

(6) 调用IEnumMoniker实例的 BindToObject方法将系统设备绑定到过滤器上。

在上面的描述中,ICreateDevEnum实例的CreateClassEnumerator方法的第一个参数确定枚举的系统设备。例如,第一个参数为CLSID_VideoInputDeviceCategory,表示将要枚举系统中的视频捕捉卡,为 CLSID_VideoCompressorCategory,表示枚举系统中的视频压缩器。

下面的代码演示了如何枚举系统中的视频捕捉卡。

//枚举视频设备;值= CLSID_VideoInputDeviceCategory

// 音频设备的值= CLSID_ AudioInputDeviceCategory;

ICreateDevEnum *pDevEnum = NULL;

CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,

IID_ICreateDevEnum, (void **)&pDevEnum);

IEnumMoniker *pClassEnum = NULL;

pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pClassEnum, 0);

ULONG cFetched;

while (pClassEnum->Next(1, &pMoniker, &cFetched) == S_OK)

{

pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pSrc);

pMoniker->Release();

break;

}

pClassEnum->Release();

而下面的代码则用于判断系统中是否安装了指定的视频压缩器。

ICreateDevEnum *pDevEnum = NULL;

CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,

IID_ICreateDevEnum, (void **)&pDevEnum);

IEnumMoniker *pClassEnum = NULL;

//列举视频压缩设备;值=CLSID_VideoCompressorCategory

pDevEnum->CreateClassEnumerator(CLSID_VideoCompressorCategory, &pClassEnum, 0);

while (pClassEnum->Next(1, &pMoniker, &cFetched) == S_OK)

{

IPropertyBag* pProp= NULL;

pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void**)&pProp);

VARIANT varName;

varName.vt = VT_BSTR;

pProp->Read(L"FriendlyName", &varName,0);

CString str = varName.bstrVal;

if (str.Find("Microsoft Video 1",0)!= -1)

{

pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pCompress);

pMoniker->Release();

break;

}

VariantClear(&varName);

}

pClassEnum->Release();

4) 查找Filter Pin过滤器引脚

每一个过滤器(Filter)至少应有一个引脚(Pin),或者是输入引脚或者是输出引脚。有些过滤器还拥有多个引脚,即又输入引脚又有输出引脚。但是过滤器的输入、输出引脚并不是对应的,有些过滤器可以有多个输入引脚,而只有一个输出引脚或者没有输出引脚。在程序中为了连接过滤器间的引脚,通常需要获得过滤器的各个引脚。

用户可以使用IEnumPins接口来枚举某一个过滤器的输入、输出引脚。过滤器 IBaseFilter提供了一个EnumPins方法用于生成一个IEnumPins接口实例,这样,通过调用IEnumPins的Next方法便可以访问各个引脚了。

下面的代码定义了一个FindPin函数,用于获得某个过滤器的输入或输出引脚。

//查找引脚

IPin* CKinescopeDlg::FindPin(IBaseFilter *pFilter, PIN_DIRECTION dir)

{

IEnumPins* pEnumPins;

IPin* pOutpin;

PIN_DIRECTION pDir;

pFilter->EnumPins(&pEnumPins);

while (pEnumPins->Next(1,&pOutpin,NULL)==S_OK)

{

pOutpin->QueryDirection(&pDir);

if (pDir==dir) {return pOutpin;}

}

return 0;

}

用户可以按下面的方式获得某个过滤器的输入、输出引脚。

IPin * pComOut,*pComIn ;

pComIn = FindPin(pCompress,PINDIR_INPUT);

pComOut = FindPin(pCompress,PINDIR_OUTPUT);

5) 连接Filter Pin过滤器引脚

使用Graph Edit工具,用户可以利用鼠标非常方便地连接两个过滤器间的引脚。但是在程序中却没这么简单了。首先需要按照上面介绍的方法获得两个过滤器的输入、输出引脚,然后将第一个过滤器的输出引脚连接到第二个过滤器的输入引脚,其中,连接两个引脚需要调用IGraphBuilder接口的 ConnectDirect方法。

下面的代码演示了如何连接两个过滤器的引脚。

IPin * pComOut,*pComIn ;

pComIn = FindPin(pCompress,PINDIR_INPUT);

pComOut = FindPin(pCompress,PINDIR_OUTPUT);

IPin* pOutpin = FindPin(pSrc,PINDIR_OUTPUT); //pSrc的输出引脚

HRESULT result ;

result = pGraph->ConnectDirect(pOutpin,pComIn,NULL);