本文的目的是给出DirectShow编程的样式。这是一个简单的控制台应用程序,用来播放一个音频或视频文件。程序只有几行,但是它示范了DirectShow编程的某些能力。
如<
DirectShow应用程序编程介绍>所写,一个DirectShow应用程序运行的基本步骤为:
1、创建一个筛选器表管理器的实例
2、使用筛选器表管理器生成一个筛选器表
3、运行表,使数据在筛选器中流动。
调用CoIntitialize来初始化COM库
HRESULT hr = CoInitialize(NULL);
if (FAILED(hr))
{
// 在这里添加错误处理代码(Omitted for clarity.)
}
为了简单化,此例子忽略了返回值,但是您最好在方法调用中检查HRESULT的值。
下面,调用CoCreateInstance来创建筛选器表管理器:
IGraphBuilder *pGraph;
HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL,
CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&pGraph);
如上所示,类标识(CLSID)为CLSID_FilterGraph。筛选器表管理器由一个进程内的DLL提供,所以执行上下文是 CLSCTX_INPROC_SERVER。DirectShow支持自由自由线程处理模式,因此您也可以使用COINIT_MULTITHREADED 标志调用CoInitializeEx。
对CoCreateInstance的调用返回IGraphBuilder接口,它主要包含了生成筛选器表的方法。此例中用到的另两个接口为:
- IMediaControl,作用是控制流。它包含了停止和启动表的方法
- IMediaEvent,它包含的方法是从筛选器表管理器中得到事件。在此例中,此接口用来等待播放的结束。
这两个接口都是出现在筛选器表管理器中。可以使用返回的IGraphBuilder指针来查询。
IMediaControl *pControl;
IMediaEvent *pEvent;
hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl);
hr = pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);
现在您可以生成筛选器表了。要播放文件,可以调用下列方法:
hr = pGraph->RenderFile(L"C://Example.avi", NULL);
IGraphBuilder::RenderFile方法生成一个筛选器表,用以播放指定的文件。第一个参数是文件名称,用一个宽字符(2字节)字符串表示。第二个参数是保留参数,必须为NULL。
如果指定的文件不存在,或文件格式无法,此方法将失败。如果方法调用成功,筛选器还原器就做好播放的准备了。要运行表,调用IMediaControl::Run方法。
hr = pControl->Run();
当筛选器运行时,数据从筛选器中移出,并以视频和音频的方式还原出来。播放会启动另一个线程。您可以调用IMediaEvent::WaitForCompletion方法。
long evCode = 0;
pEvent->WaitForCompletion(INFINITE, &evCode);
当应用程序结束时,将释放接口指针并关闭COM库。
pControl->Release();
pEvent->Release();
pGraph->Release();
CoUninitialize();
代码范例
这里列出了本文介绍的例子的完整代码:
#include <dshow.h>
void main(void)
{
IGraphBuilder *pGraph = NULL;
IMediaControl *pControl = NULL;
IMediaEvent *pEvent = NULL;
// 初始化COM库
HRESULT hr = CoInitialize(NULL);
if (FAILED(hr))
{
printf("ERROR - Could not initialize COM library");
return;
}
// 创建筛选器表管理器,并查询接口
hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, (void **)&pGraph);
if (FAILED(hr))
{
printf("ERROR - Could not create the Filter Graph Manager.");
return;
}
hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl);
hr = pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);
// 创建表。重点:将字符串改为您系统上的文件名称
hr = pGraph->RenderFile(L"C://Example.avi", NULL);
if (SUCCEEDED(hr))
{
// 运行表
hr = pControl->Run();
if (SUCCEEDED(hr))
{
// 等待结束
long evCode;
pEvent->WaitForCompletion(INFINITE, &evCode);
// 注意:在实际应用程序中不要使用INFINITE
// 因为它对应用程序的阻塞很不确定
}
}
pControl->Release();
pEvent->Release();
pGraph->Release();
CoUninitialize();
}
此方法将阻塞,直到文件播放完毕,或超出了指定的时间。INFINITE值是指应用程序将阻塞到文件播放完。