Directshow播放框架详解

DirectShow是一个 windows平台上的流媒体框架,原名为ActiveMovie,现在一部分API仍保留了"AM"的前缀,比如AM_MEDIA_TYPE和 IAMVideoAccelerator。

direcshow架构见下图,相关头文件和库dshow.h、quartz.dll

接口:

IFilterGraph 过滤通道接口
IFilterGraph2 增强的IFilterGraph
IGraphBuilder 最为重用的COM接口,用于手动或者自动构造过滤通道Filter Graph Manager

IMediaControl 用来控制流媒体,例如流的启动和停止暂停等,播放控制接口
IMediaEvent 播放事件接口 ,该接口在Filter Graph发生一些事件时用来创建事件的标志信息并传送给应用程序
IMediaEventEx 扩展播放事件接口
IMediaPosition 播放的位置和速度控制接口(控制播放位置只能为设置时间控制方式)
IMediaSeeking 另一个播放的位置和播放速度控制接口,在位置选择方面功能较强.设置播放格式,多种控制播放方式.常用的有:

(1)TIME_FORMAT_MEDIA_TIME单位100纳秒。(2)TIME_FORMAT_FRAME按帧播放

IBasicAudio 声音控制接口
IBasicVideo 图像控制接口(波特率,宽度,长度等信息)
IVideoWindow 显示窗口控制接口 (有关播放窗口的一切控制,包括caption显示,窗口位置控制等)
ISampleGrabber 捕获图象接口(可用于抓图控制)
IVideoFrameStep 控制单帧播放的接口

播放流程:

    大体说来,一般使用DirectShow接口编程无非3个步骤,初始化接口,利用接口中的控制函数使用控制操作,最后释放接口。

 流程图中关键函数的作用如下所示。
CoInitialize() :初始化COM运行环境。
CoCreateInstance(…,pGraph) :用指定的类标识符创建一个Com对象。在该播放器中类标识符为“CLSID_FilterGraph”,用于创建IGraphBuilder。
pGraph->QueryInterface(…,pControl) :通过QueryInterface()查询某个组件是否支持某个特定的接口。在这里查询IMediaControl接口。
pGraph->QueryInterface(…,pEvent) :同上。在这里查询IMediaEvent接口。
pGraph->RenderFile("xxx.mkv"):为指定的文件智能的构建一个Filter Graph,支持的输入是Unicode字符串
pControl->Run() :开始运行Filter Graph中的所有Filter。
pEvent->WaitForCompletion() :等待Filter Graph处理完所有数据。
CoUninitialize():释放CoInitialize()初始化的COM运行环境。

该流程图中包含如下变量:
IGraphBuilder *pGraph:继承自IFilterGraph,用于构建Filter Graph。
IMediaControl *pControl:提供和播放控制有关的一些接口。
IMediaEvent   *pEvent:用来处理Filter Graph发出的事件。
IBaseFilter *pF_source:源Filter。
IFileSourceFilter* pFileSource:源Filter的暴露的接口,用于设置输入文件的路径。
IBaseFilter *pF_demuxer:解复用Filter。
IBaseFilter *pF_decoder:解码Filter。
IBaseFilter *pF_render:渲染Filter。
IPin *pOut:输出Pin。
IPin *pIn:输入Pin。
IPin **pPin:内部变量Pin。
该流程图大体上可以分成以下步骤:
(1)       初始化DirectShow
包括以下几个步骤:
a)       CoInitialize():初始化COM运行环境。
b)       CoCreateInstance(…,pGraph):用指定的类标识符创建一个Com对象。在这里创建IGraphBuilder。
c)       pGraph->QueryInterface(…,pControl):通过QueryInterface()查询某个组件是否支持某个特定的接口。在这里查询IMediaControl接口。
d)       pGraph->QueryInterface(…,pEvent):同上。在这里查询IMediaEvent接口。
(2)       添加Source Filter
包括以下几个步骤:
a)       CoCreateInstance(…,pF_source):创建Source Filter。
b)       pGraph->AddFilter(pF_source,…):将Source Filter加入Filter Graph。
c)       pF_source->QueryInterface(…,pFileSource):查找Source Filter的IFileSourceFilter接口。
d)       pFileSource->Load(L"xxx.mpg",pF_source):调用IFileSourceFilter的Load()方法加载视频文件。
(3)       添加Demuxer Filter
包括以下几个步骤:
a)       CoCreateInstance(…,pF_demuxer):创建Demuxer Filter。
b)       pGraph->AddFilter(pF_demuxer,…):将Demuxer Filter加入Filter Graph。
(4)       添加Decoder Filter
包括以下几个步骤:
a)       CoCreateInstance(…,pF_decoder):创建Decoder Filter。
b)       pGraph->AddFilter(pF_decoder,…):将Decoder Filter加入Filter Graph。
(5)       添加Render Filter
包括以下几个步骤:
a)       CoCreateInstance(…,pF_render):创建Render Filter。
b)       pGraph->AddFilter(pF_render,…):将Render Filter加入Filter Graph。
(6)       连接Source Filter和Demuxer Filter
调用了一个函数connect_filters()用于连接2个Filter。
connect_filters()的执行步骤如下:
a)       调用get_unconnected_pin()从源Filter中选择一个没有链接的输出Pin。
b)       调用get_unconnected_pin()从目的Filter中选择一个没有链接的输入Pin。
c)       连接这两个Pin
get_unconnected_pin()的执行步骤如下:
a)       枚举Filter上的Pin。
b)       遍历这些Pin,查找符合输出方向(通过IPin的QueryDirection()方法),而且没有在使用的Pin(通过IPin的ConnectedTo()方法)。
(7)       连接Demuxer Filter和Decoder Filter
过程同上。
(8)       连接Decoder Filter和Render Filter
过程同上。
(9)       开始播放
包括以下步骤:
pControl->Run():开始运行Filter Graph中的所有Filter。
pEvent->WaitForCompletion():等待Filter Graph处理完所有数据。
 
上述步骤可以理解为在GraphEdit软件中分别按照步骤添加以下控件。其中(1)、(2)、(3)、(4)为先添加的4个Filter,(5)、(6)、(7)为Filter之间的连接线。

 注意Render()方法和RenderFile()方法区别

RenderFile()是指定一个文件路径后,自动构建整个Filter Graph,相对来说更加简单些;而Render()方法则是首先要创建一个Source Filter之后,才可以自动构建整个Filter Graph。
可以通过修改源文件首部的宏定义ADD_MANUAL来设定是否手动添加Filter,如下所示。
//'1':Add filters manually
//'0':Add filters automatically
#define ADD_MANUAL 1
 
 

接口关系

 可以看出从上到下他们之间顺序的排列如下所示:

ICreateDevEnum-->IEnumMoniker-->IMoniker-->IBaseFilter-->IEnumPins-->IPin-->IEnumMediaTypes-->AM_MEDIA_TYPE

该流程图中涉及到以下接口:
ICreateDevEnum *pSysDevEnum:设备列举接口。
IEnumMoniker *pEnumCat:Moniker(别名)枚举接口。
IMoniker *pMoniker:Moniker(别名)接口。
IPropertyBag *pPropBag:存储属性值的接口。
IBaseFilter *pFilter:Filter接口。
IEnumPins * pinEnum:Filter枚举接口。
IPin * pin: Pin接口。
PIN_INFO pinInfo:存储Pin的信息的结构体。
IEnumMediaTypes *mtEnum:MediaType枚举接口。
AM_MEDIA_TYPE   *mt:描述媒体类型的结构体。
 

【初始化】

CoInitialize():初始化COM运行环境。

CoCreateInstance(…,pSysDevEnum):用指定的类标识符创建一个Com对象。在该示例中类标识符为“IID_ICreateDevEnum”,用于创建ICreateDevEnum。

【Filter的枚举】
pSysDevEnum->CreateClassEnumerator(…,pEnumCat):通过ICreateDevEnum查询IEnumMoniker枚举接口,枚举指定类型目录下的设备Moniker(别名)。
pEnumCat->Next(…,pMoniker):通过IEnumMoniker查询下一个IMoniker接口。
pMoniker->BindToStorage(…,pPropBag):通过IMoniker查询IPropertyBag接口(用于获取Filter信息)。
pPropBag->Read("FriendlyName"):通过IPropertyBag获取“FriendlyName”属性的值。
pMoniker->BindToObject(…,pFilter):通过IMoniker查询IBaseFilter接口(用于获取Filter,注意和BindToStorage()区别)。

【Pin的枚举】
pFilter->EnumPins(pinEnum):通过IBaseFilter查询IEnumPins枚举接口。
pinEnum->Next(…,pin):通过IEnumPins查询下一个IPin接口。
pin->QueryPinInfo(PinInfo):通过IPin获取Pin的信息。

【MediaType的枚举】
pin->EnumMediaTypes(&mtEnum):通过IPin查询IEnumMediaTypes枚举接口。
mtEnum->Next(…, &mt):通过IEnumMediaTypes查询下一个AM_MEDIA_TYPE。
GuidToString(mt->majortype):把AM_MEDIA_TYPE的GUID转换成字符串(方便输出)。

【释放】

CoUninitialize():释放CoInitialize()初始化的COM运行环境。
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

步基

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值