开发环境:Win10 + VS2015
本文先介绍 DirectShow 中使用的基本术语和概念,然后就可以编写第一个 DirectShow 应用程序。这是一个播放音频或视频文件的简单控制台应用程序,虽然程序只有几行,但它演示了 DirectShow 编程的一些重要功能。
一、开发环境的配置
我们先来介绍一下 DirectShow 应用程序开发环境的配置。
1.1 需要包含的头文件
DirectShow SDK 建议,所有的 DirectShow 应用都需要 Dshow.h 这个头文件,某些 DirectShow 接口需要附加的头文件,参考接口的说明视具体情况定。
1.2 需要包含的库文件
DirectShow SDK 建议,DirectShow 应用程序应该至少连接库文件 Strmiids.lib 和 Quartz.lib。
- Strmiids.lib:定义了 DirectShow 标准的类标识(CLSID)和接口标识(IID)。
- Quartz.lib:定义了导出函数 AMGetErrorText,如果不调用此函数,此库不是必需的。
1.3 VC++ 的系统编译环境
确保 DirectShow SDK 的 Include 目录和 Lib 目录都已经加入了 VC++ 的系统编译环境。一般安装完 Visual Studio 即会自动配置。
二、一般开发过程
开发 DirectShow 应用程序,一般都有三个阶段,如下图:
第一阶段,创建一个 Filter Graph Manager 组件,代码如下:
IGraphBuilder *pGraph = NULL;
HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC, IID_IGraphBuilder, (void **)&pGraph);
第二阶段,根据实际的应用,创建一条完整的 Filter 链路,比如播放一个本地文件,最简单快速的代码如下:
hr = pGraph->RenderFile(L"D:\test.avi", NULL);
第三阶段,调用 Filter Graph Manager 上(或者直接在某个 Filter 上)的各个接口方法进行控制,并且完成 Filter Graph Manager 与应用程序的事件交互。比如调用 IMediaControl 接口方法控制 Filter Graph 的状态转换,代码如下:
IMediaControl *pControl = NULL;
hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl);
hr = pControl->Run();
处理完成后,应用程序要释放 Filter Graph Manager 和所有 Filter。
三、第一个 DirectShow 应用程序
创建工程:文件 -> 新建 -> 项目 -> Win32 控制台应用程序,注意包括头文件 Dshow.h 并链接到静态库文件 strmiids.lib。完整实例代码如下:
#include "stdafx.h"
#include <dshow.h>
// 用到的DirectShow SDK链接库
#pragma comment(lib,"strmiids.lib")
int _tmain(int argc, _TCHAR* argv[])
{
IGraphBuilder *pGraph = NULL; // Filter Graph Manager(实例)
IMediaControl *pControl = NULL; // 媒体控制
IMediaEvent *pEvent = NULL; // 媒体事件
// (一)初始化COM库
HRESULT hr = CoInitialize(NULL);
if (FAILED(hr))
{
printf("错误 - 无法初始化 COM 组件");
return -1;
}
// (二)创建Filter Graph Manager
hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&pGraph);
if (FAILED(hr))
{
printf("错误 - 无法创建 Filter Graph Manager.");
return -1;
}
// (三)查询媒体控制和媒体事件接口
hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl);
hr = pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);
// (四)建立Graph,在这里你可以更改待播放的文件名称
hr = pGraph->RenderFile(L"test.mp4", NULL);
if (SUCCEEDED(hr))
{
// 运行Graph.
hr = pControl->Run();
if (SUCCEEDED(hr))
{
// IMediaEvent接口用于等待播放完成
long evCode;
pEvent->WaitForCompletion(INFINITE, &evCode);
// 切记: 在实际应用当中,不能使用INFINITE标识, 因为它会不确定的阻塞程序
}
}
// (五)释放接口指针并关闭COM库
pControl->Release();
pEvent->Release();
pGraph->Release();
CoUninitialize();
return 0;
}
pControl->Run()
运行 Graph,数据在 Filter 中移动并呈现为视频和音频。播放发生在单独的线程上。您可以通过调用 IMediaEvent :: WaitForCompletion 方法来等待播放完成。该方法将阻塞,直到文件播放完毕或经过指定的超时间隔为止。值 INFINITE 意味着应用程序将无限期阻塞,直到文件播放完毕。
运行程序播放 "test.mp4" 的效果图如下:
代码下载(VC2015):Github - DShow_simpleVideo
参考:
MSDN - DirectShow Application Programming