DirectShow初探

时间:2021-03-18 12:48:33

可能到现在为止,还没有哪个玩过游戏的人没有接触过Microsoft的DirectX的。因为现今大多数的游戏都是用DirectX开发出来的。

相比之下,DirectShow只是DirectX的一个子集。DirectX中还包括DirectSound、Direct3D等集合。DirectShow主要用来处理一些与音视频有关的多媒体任务,比如音视频采集、回放等。过年回来后,在一个项目中要求在WIN32下采集视频信号,以前做过GDI的,不过效率低下,而且效果也很烂,所以决定加速,怎样加速,答案就在DirectShow。

1、DirectShow的结构

我们知道,Windows操作系统只用了CPU中的两个特权级(0和3)。0是内核模式,它可以直接访问硬件;3是用户模式,它不能直接访问硬件。DirectShow的基本工作单元是Filter(过滤器),过滤器的就像一个筛子,它一般有输入引脚(PIN)和输出引脚,数据从输入引脚流入而从输出端口流出。DirectShow中的过滤器一般分为下列3类:

1) Source Filter (用于提供原始的多媒体数据,比如一个视频文件)

2)Transform Filter(用于处理从Source Filter 传过来的多媒体数据,比如MPEG-4解码器)

3)Rendering Filter(用于显示、回放和存储多媒体数据给用户,比如文件写入器)

要完成特定的多媒体功能,必须用相应的Filter组成特定的Filter Graph。多媒体数据在Graph中流动,到达Rendering Filter时回放给用户。

用户应用程序怎么样控制Filter Graph呢?他必须创建一个相应的Filter Graph Manager,应用程序向Manager发送相应的命令(Command),然后从Manager那接收相应的Event,最后做出相应的响应。

每个Filter都有操作硬件的能力,这就是为什么DirectShow能如此高效的使用多媒体了。

DirectShow的结构原理图如下:

DirectShow初探

2、使用DirectShow编写一个简单的应用程序

使用DirectShow编写应用程序的一般步骤如下:

1)根据系统完成的功能构建相应的Filter Graph。

2)构建Graph中的每个Filter,并将它们连接起来。

3)创建Filter Graph Manager,运用Application控制Manager,从而控制整个的流程。

4)DirectShow是基于COM(组件对象模型)的,所以在编写Filter前必须初始化COM库。

下面是一个完整的播放AVI文件的小程序,其中的注解说明了编程的步骤。

#include <stdio.h>

#include <dshow.h>    //DirectShow必须包含的头文件,LIB库为Strmiids.lib 和 Quartz.lib

int main()

{

 IGraphBuilder *pGraph = NULL;      //  用于创建Filter Graph的接口

 IMediaControl *pControl = NULL;    //  用于向Filter Graph Manager发送Command

 IMediaEvent   *pEvent = NULL;        //   用于接收Filter Graph Manager发出的Event

// Initialize the COM library.

 HRESULT hr = CoInitialize(NULL);   //初始化COM Library

if( FAILED(hr) )

 {

  fprintf(stderr,"could not init the COM library!");

  return 0;

 }

//创建Filter Graph Manager

hr = CoCreateInstance(CLSID_FilterGraph,NULL,CLSCTX_INPROC_SERVER,IID_IGraphBuilder,(void **)&pGraph);

if( FAILED(hr) )

 {

  fprintf(stderr,"could not create Filter Graph Manager!");

  return 0;

 }

//查询并获得接口指针

 hr = pGraph->QueryInterface(IID_IMediaControl,(void **)&pControl);

 hr = pGraph->QueryInterface(IID_IMediaEvent,(void **)&pEvent);

// RenderFile库函数是少数几个能够自动创建Graph的成页,所以这里省去了创建Graph这一步

 hr = pGraph->RenderFile(L"e://football.avi",NULL);

if( SUCCEEDED(hr) )

 {

  hr = pControl->Run();

if( SUCCEEDED(hr) )

  {

   // 等待视频结束

   long evCode;

   pEvent->WaitForCompletion(INFINITE, &evCode);

// 无限等待

}

  

 }

pControl->Release();

 pEvent->Release();

 pGraph->Release();

//释放接口

CoUninitialize();   //御载COM 库

return 0;

}