1.       概述
这本篇文章给出创建DirectShow程序的一个简单的示例。DirectShow中使用了大量的COM,确切讲DirectShow就是构建在COM基础上的,但关于COM的基础知识不在这里敷述。这个程序是一个简单的可以播放声音或者是视频的控制台程序。这个示例程序只有简单的几行,但是却演示了一个强大的DirectShow的程序。
一个DirectShow应用程序包括以下几个步骤:
1.       创建一个Filter Graph Manager 的实例;
2.       使用Filter Graph Manager创建一个Filter Graph
3.       运行这个 graph,这样就会使数据通过这些过滤器(filter)
2.       详细叙述
首先,调用CoInitialize初始化COM库:
//初始化COM库.
HRESULT hr = CoInitialize(NULL);
if (FAILED(hr))
{
    printf("ERROR - 不能初始化COM库");
    return 1;
}
 
为了使这个示例程序简单一些,程序中忽略了返回值,但是你可以从任何方法调用中检查HRESULT的值。
其次,调用CoCreateInstance创建Filter Graph Manager:
    //创建过滤器图像管理器,查询接口
    hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,  
  IID_IGraphBuilder, (void **)&pGraph);
    if (FAILED(hr))
    {
        printf("ERROR - 不能够创建 Filter Graph Manager.");
        return 0;
    }
 
如上面的代码所示,这个类标识符(CLSID)CLSID_FilterGraph。这个Filter Graph Manager由进程中的Dll提供,所以创建时的执行空间上下文是CLSCTX_INPROC_SERVERDirectShow支持自由线程模式,所以你也可以用CoInitializeEx调用COINIT_MULTITHREADED标识符。
调用CoCreateInstance返回IGraphBuilder这个接口,这个接口包含了创建filter graph的大多数方法。另外示例中还需要其余的两个接口:
l  IMediaControl接口控制数据流。这个接口里面包含了开始和结束播放画面的方法。
l  IMediaEvent接口包含从Filter Graph Manager中取得的事件。在这个示例里面,这个接口用来等待视频播放完成。
这两个接口都是通过Filter Graph Manager暴露出来的。使用IGraphBuilder指针可以查询这两个接口:
hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl);
hr = pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);
 
现在,你可以创建Filter Graph。这个可以用一个简单的命令调用。
// 创建graph,此处为要打开的影片
hr = pGraph->RenderFile((LPCWSTR)wText, NULL);
        IGraphBuilder::RenderFile 这个方法用来创建一个Filter Graph 用来播放一个特定的文件。第一个参数是一个文件名,这个文件名为一个Unicode字符串,第二个参数是一个保留字符,一般为NULL
    如果打开的文件不存在,或者是文件格式识别这个返回值HRESULTFAIL。假设这个方法成功了,filter就可以播放了。调用IMediaControl::Run就可以播放视频了。
//运行graph.
hr = pControl->Run();
    当这个过滤器开始运行后,数据通过filter过滤器后分解成视频和音频。系统播放视频时会创建一个独立的进程,你可以通过调用IMediaEvent::WaitForCompletion事件方法来监视播放事件当前的状态。
// 等待影片播放完成
long evCode;
pEvent->WaitForCompletion(INFINITE, &evCode);
    这个事件阻塞到文件完成播放时,或者是到这个线程分配到的时间片丢失掉的时候。INFINITE这个值意味着应用程序阻塞到整个影片播放完成。
当应用程序完成了整个影片的播放,释放这些接口的指针,然后关闭这些COM组件库。
pControl->Release();
pEvent->Release();
pGraph->Release();
//卸载COM组件
CoUninitialize();
3. 源程序

3.1. 说明

程序中用到了DirectShow示例文件中的基本类库,在编译之前先编译DX安装目录\Samples\C++\DirectShow \BaseClasses  下面的工程,进行以下设置菜单Project->Setting
添加strmbase.lib
创建一个基于命令行的简单的播放器_示例
 

3.2.       源码

1.        /********************************************************************
2.               created: 2008/05/15
3.               created: 15:5:2008   13:39
4.               file base:       FirstDX
5.               file ext:  cpp
6.               author:          ZJY
7.              
8.               purpose: 这个小程序主要是为了演示DirectShow的最基本的一个步骤
9.        *********************************************************************/
10.    #include "stdafx.h"
11.    #include <dshow.h>
12.    #include <iostream>
13.     
14.    int main(int argc,char *argv[])
15.    {
16.           char strAviName[256];
17.           if (argc == 1)
18.           {
19.                  std::cout << "没有输出影片,请添加要播放的影片..." <<std::endl;
20.                  return 1;
21.           }
22.           else if (argc == 2)
23.           {
24.                  strcpy(strAviName,argv[1]);
25.           }
26.           else
27.           {
28.                  std::cout <<"参数传递错误..." <<std::endl;
29.                  return 1;
30.           }
31.     
32.        IGraphBuilder *pGraph = NULL;
33.        IMediaControl *pControl = NULL;
34.        IMediaEvent   *pEvent = NULL;
35.          
36.        //初始化COM.
37.        HRESULT hr = CoInitialize(NULL);
38.        if (FAILED(hr))
39.        {
40.            printf("ERROR - 不能初始化COM");
41.            return 1;
42.        }
43.          
44.           //创建过滤器图像管理器,查询接口
45.        hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
46.                  IID_IGraphBuilder, (void **)&pGraph);
47.        if (FAILED(hr))
48.        {
49.            printf("ERROR - 不能够创建 Filter Graph Manager.");
50.            return 0;
51.        }
52.          
53.        hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl);
54.        hr = pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);
55.          
56.           //由于DirectShow主要是Unicode格式,我们使用Windows自带函数
57.           //转换文件名char数组为Unicode格式
58.           int len = strlen(strAviName)+1;
59.           wchar_t *wText = new wchar_t[len];
60.           if ( wText == NULL)
61.           {
62.                  std::cout <<"ERROR - 文件打开错误..."<<std::endl;
63.                  return 1;
64.           }
65.           memset(wText,0,len);
66.           ::MultiByteToWideChar( CP_ACP, NULL,strAviName, -1, wText,len );
67.     
68.           // 创建graph,此处为要打开的影片
69.           hr = pGraph->RenderFile((LPCWSTR)wText, NULL);
70.     
71.        if (SUCCEEDED(hr))
72.        {
73.            //运行graph.
74.            hr = pControl->Run();
75.            if (SUCCEEDED(hr))
76.            {
77.                // 等待影片播放完成
78.                long evCode;
79.                pEvent->WaitForCompletion(INFINITE, &evCode);
80.                         //注意:不要在真实的程序中使用INFINITE,因为这样会永久阻塞应用程序
81.            }
82.        }
83.           else
84.                  std::cout << "ERROR - 影片不存在或格式不支持..." <<std::endl;
85.        pControl->Release();
86.        pEvent->Release();
87.        pGraph->Release();
88.           //卸载COM组件
89.        CoUninitialize();
90.           return 0;
91.    }