DirectShow入门

http://blog.csdn.net/wcm130267/article/details/1466743

该文介绍如何编写DirectShow应用程序,属于入门级文章。

一环境设置 

该节介绍如何建立DirectShow应用程序。你可以建立一个控制台程序,或者Visual Studio环境下的其它Visual C++的项目。 

头文件 
所有DirectShow 程序都使用下表中的头文件。 

头文件     需     要 
dshow.h   所有DirectShow 程序。 
有些DirectShow接口会要求其他头文件,你可以去查看这些接口的参考手册。 

库文件 
DirectShow程序要使用的库文件如下: 
库文件               说            明 
Strmiids.lib   提供类标识(CLSIDs)和接口表示(IIDs)。所有的DirectShow程序都要求使用该库文件。 
Quartz.lib     提供AMGetErrorText函数,如果你不调用这个函数,就可以不加载该库文件。 
可以把DirectX SDK 的Include 和Lib目录放在Visual Studio的搜索路径的第一位。以确保你可以使用最新的版本!

二 DirectShow编程简介 
该节对DirectShow编程的基本术语和概念进行介绍,通过对该节的阅读,你可以写你的一个DirectShow应用程序。 

过滤器(Filters)和过滤器图表(Filter Graphs) 
过滤器(Filters)就是一个软件组件,它执行一些针对多媒体流的操作。比如: 
读入文件  
从视频捕获设备得到视频  
对多种流格式解码,如MPEG-1  
传送数据到显卡和声卡  

过滤器可以接收输入并提供输出,比如,一个MPEG-1视频解码过滤器,它接收MPEG编码的数据流,通过处理后输出非压缩的视频图像帧。 

在DirectShow, 应用程序执行的一些工作是在一串过滤器链接中完成,可能某个过滤器的输出到了下一步就是另一个过滤器的输入。这一组连接,我们就称为过滤器图表。 

例如下图显示了一个播放AVI文件的过滤器图表。 

File Source 过滤器从硬盘上读取AVI文件。AVI Splitter 过滤器把文件解析为两个数据流(压缩的视频流和音频流)。AVI Decompressor过滤器对视频流解码,Video Rendere把视频数据显示出来(通过DirectDraw 或 GDI)。Default DirectSound Device过滤器使用DirectSound播发音频数据 

应用程序不需要对数据流动进行管理,这些过滤器被级别更高的组件控制,过滤器图表管理器(Filter Graph Manager)管理这些过滤器。这样,你就可以使用更高级别的API来控制(比如”Run” , ”Stop”),如果你要控制流的操作,你也可以通过直接使用过滤器的COM接口实现。过滤器图表管理器通过事件来通知应用程序。 

过滤器图表管理器的另一个用途是:它通过把过滤器连接在一起,向应用程序提供了建立过滤器图表的方法。 

编写DirectShow 程序 

在大部分的情况下,DirectShow应用程序必须执行下面3个步骤: 

1.应用程序建立一个Filter Graph Manager的实例。 
2.应用程序使用Filter Graph Manager 去建立一个filter graph. Filter graph中的过滤器依赖与应用程序的需求。  
3.应用程序使用Filter Graph Manager 去控制filter graph 并通过过滤器去对数据解析分流。在整个处理过程中,应用程序都将响应Filter Graph Manager的事件。  

当处理完成后,应用程序将释放掉Filter Graph Manager和所有的过滤器。 
DirectShow 是基于COM的。Filter Graph Manager 和过滤器都是COM对象。你应该对COM编程有全面的了解。 

三播放文件例程 
这里提供一个控制台应用程序去播放一个音、视频文件。这个程序只有几行长。 
在前面介绍了一个基于DirectShow的应用程序,必须要进行如下几个基本步骤: 
1.建立一个Filter Graph Manager的实例.  
2.使用Filter Graph Manager 建立一个filter graph. 
3.运行这个graph。  

调用CoInitialize 去初始化一个这个COM 库。 
HRESULT hr = CoInitialize(NULL); 
if (FAILED(hr)) 

    // 在这里加入错误处理 


这里,我们跳过了对返回值的检查,当你调用了任何方法的时候都应该对返回值进行检查。下面调用CoCreateInstance创建Filter Graph Manager。 
IGraphBuilder *pGraph; 
HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL,  
    CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&pGraph); 
类ID是CLSID_FilterGraph,由于Filter Graph Manager是动态链接库提供(dll),所以使用CLSCTX_INPROC_SERVER。 

CoCreateInstance 将返回IgraphBuilder接口,在该例子中还需要两个接口: 
l         IMediaControl 用于控制数据流。它提供停止和开始的操作方法。  
l         IMediaEvent   可以获得Filter Graph Manager 事件。例如,可以获得播放完成事件。  

这两个接口都由Filter Graph Manager提供,可以通过IgraphBuilder指针去获得它们: 

IMediaControl *pControl; 

IMediaEvent   *pEvent; 

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

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

现在,你可以建立过滤器图表(Fileter Graph)。对于文件播放,这里只需要调用一个方法就可以了: 

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

IGraphBuilder::RenderFile方法将建立一个过滤器图表,通过它来播放指定的文件。第一个参数指定要播放的文件名称,它是个宽字符字符串。第二个参数是系统保留,必须为NULL。如果指定文件不存在或文件格式未知,那么该方法调用将失败。 

现在过滤器图表已经准备好了去播放文件,但是还必须调用IMediaControl::Run方法去播放。 

hr = pControl->Run(); 

当过滤器图表开始运行,数据从通过过滤器播放出来。播放动作将在一个独立的线程中进行。调用IMediaEvent::WaitForCompletion 方法可以等待文件播放完成。 

long evCode = 0; 

pEvent->WaitForCompletion(INFINITE, &evCode); 

这个方法将一直等待文件播放结束才返回。INFINITE就表示不能确定文件的播放时间长度。当应用程序完成播放后,应该释放掉接口指针和关闭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); 

        } 

    } 

    pControl->Release(); 

    pEvent->Release(); 

    pGraph->Release(); 

    CoUninitialize(); 

}
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值