DSHOW 中关于FILTER的连接内部实现过程

转载出处:http://blog.csdn.net/l5201314131413141314/article/details/7106596

应用程序通过调用filter 图表管理器的方法来连接filter,并不是来调用filter或者pin本身的函数。应用程序可以调用IFilterGraph::ConnectDirect or IGraphBuilder::Connect来指定不同的filter直接连接,也可以通过IGraphBuilder::RenderFile间接连接


只有两个 filter 都在graph里, 连接 才能成功。应用程序可以通过IFilterGraph::AddFilter将 filter  添加graph中,当一个 filter 被添加到graph中时, filter 图表管理器通过IBaseFilter::JoinFilterGraph来通知 filter

Pin 连接 的大致 过程 如下:

1、图表管理器首先调用输出pin上的IPin::Connect,然后传递一个指针给输入pin。

2、如果输出pin接受 连接 的邀请,它就调用输入pin上的IPin::ReceiveConnection。

3、如果输入pin也接受 连接 邀请,那么 连接 成功,pin之间的 连接 ok。

filter 处于活动状态的时候,许多pin可以断开 连接 和重新 连接 。这种类型的 连接 称为动态 连接 。当然,大多数的 filter 并不支持动态 连接

Filter 通常采用从上游到下游的 连接 顺序。也就是说 filter 上的输入pin总是比输出pin先 连接 Filter 应该支持这种 连接 顺序。然而有许多 filter 支持相反的 连接 顺序,输出pin先 连接 ,输入pin后 连接 。例如:在 连接 MUX filter 的输入pin之前一定要将MUX  filter 的输出pin和writer  filter连接 起来。

当pin的Connect or ReceiveConnection方法被调用的时候,pin必须检查一下自己是否支持这个 连接 。通常要进行下列检查:

1、检查媒体类型是否匹配。

2、就内存的分配达成一致。

3、请求其他pin的其他接口。

媒体类型匹配

当一个 filter  图表管理器调用IPin::Connect方法时,可能有下面的几种媒体类型。

1、完整类型

如果媒体类型每一个部分都定义的很完成,那么pin就严格按照定义的类型类型进行 连接 。如果不匹配, 连接 失败。

2、部分媒体类型

如果媒体类型的机构中,major type, subtype, or format type的值为GUID_NULL,这个值是一个通配符号。任何类型都可以匹配。

3、没有媒体类型

如果 filter 图表管理器传递过来一个NULL的指针,这个pin就可以和任意的类型的媒体类型匹配。 

一般在 连接过程 中,都有一个完整的媒体类型。图表管理器传递媒体类型的目的是为了限制 连接 类型。

一般来说,都是输出pin通过调用输入pin IPin::ReceiveConnection提供一个媒体类型。输入pin可以拒绝也可以接受这个媒体类型。这个 过程 一直重复,直到输入pin接受了一个类型,或者输出pin枚举完了它支持的所有的媒体类型, 连接 失败。

输出pin通过调用输入pin上的IPin::EnumMediaTypes枚举输入pin所支持的媒体类型。

看看如何匹配媒体类型的吧。

if ((pmt-formattype == FORMAT_VideoInfo) (pmt-cbFormat sizeof(VIDEOINFOHEADER) (PBFormat != NULL))

VIDEOINFOHEADER pVIH = (VIDEOINFOHEADER)pmt-pbFormat;
// Now you can dereference pVIH。


Pin 连接 中的内存分配

当两个pin 连接 起来后,他们需要一种机制来交换媒体数据。大多数数据交换采用的局部内存交换机制。所有的媒体数据都在主内存中。DirectShow为局部存储器传输定义了两种机制:推模式(push model)和拉模式(pull model)。在推模式中,源过滤器生成数据并提交给下一级过滤器。下一级过滤器被动的接收数据,完成处理后再传送给再下一级过滤器。在拉模式中,源过滤器与一个分析过滤器相连。分析过滤器向源过滤器请求数据后,源过滤器才传送数据以响应请求。推模式使用的是IMemInputPin接口,拉模式使用IAsyncReader接口,推模式比拉模式要更常用。

在局部存储器传输中,负责分配内存的对象称为allocator。每个allocator都支持一个IMemAllocator接口。所有的pin都共享一个allocator。

每个pin都提供一个allocator,但是输出pin选择使用哪个allocator。

输出pin可以设置allocator的属性。比如,分配内存的大小,在IMemInputPin 连接 中,allocator工作 过程 如下:

1、首先,输出pin调用IMemInputPin::GetAllocatorRequirements,这个方法检查输入pin对内存的要求,比如内存的队列,一般来说,输出pin要满足输入pin对内存的要求。

2、输出pin然后调用IMemInputPin::GetAllocator。,这个方法从输入pin请求一个allocator。

3、输出pin选择一个allocator,可以是输入pin提供,也可以是自己生产的。

4、输出pin调用IMemAllocator::SetProperties来设置allocator的属性。

5、然后输出pin通过IMemInputPin::NotifyAllocator来通知输入pin,选择的allocator。

6、输入pin通过IMemAllocator::GetProperties来检查是否能够接受allocator的属性。

7、当数据流开始和停止的时候,输出pin负责提交allocator。

在IAsyncReader 连接过程 如下:

1、输入pin调用输出pin上的IAsyncReader::RequestAllocator,输入pin确定内存的属性,并提供一个allocator。

2、输出pin选择一个allocator

3、输入pin检查 

如何提供一个自定义的allocator

这里只讲一下IMemInputPin 连接 ,IAsyncReader类似。

首先,定义一个C++类,你的allocator应该从一个标准的allocator类中派生,比如CBaseAllocator or CMemAllocator,你也可以自己创建一个新的allocator类,如果你是新建的类,你必须支持IMemAllocator接口。

下面看看在输入pin和输出pin中如何使用你定义的allocator。

在输入pin中提供allocator

在输入pin中提供allcator,必须重载CBaseInputPin::GetAllocator方法。在这个方法里,首先检查m_pAllocator是否可用,如果为非空,就表明allocator已经被选中,所以直接返回这个allocator指针即可,如果m_pAllocator为空,表明allocator还没有被选中,所以,就要返回输入pin的allocator,因此,创建一个allcaotor的实例,返回IMemAllocator接口。

看下面的代码把

STDMETHODIMP CMyInputPin::GetAllocator(IMemAllocator ppAllocator)

CheckPointer(ppAllocator, E_POINTER);
if (m_pAllocator) 

// We already have an allocator, so return that one。
ppAllocator = m_pAllocator;
(ppAllocator)-AddRef();
return S_OK;

// No allocator yet, so propose our custom allocator。 The exact code
// here will depend on your custom allocator class definition。
HRESULT hr = S_OK;
CMyAllocator pAlloc = new CMyAllocator(hr);
if (!pAlloc)

return E_OUTOFMEMORY;

if (FAILED(hr))

delete pAlloc;
return hr;

// Return the IMemAllocator interface to the caller。
return pAlloc-QueryInterface(IID_IMemAllocator, (void)ppAllocator);


当输出pin选择一个allocator,它就调用输入pin的IMemInputPin::NotifyAllocator,因此,要重载CBaseInputPin::NotifyAllocator方法来检查allocator的属性。

在输出pin中如何提供一个定制的Allocator

在输出pin中提供一个allcator,要重载CBaseOutputPin::InitAllocator。

HRESULT MyOutputPin::InitAllocator(IMemAllocator ppAlloc)

HRESULT hr = S_OK;
CMyAllocator pAlloc = new CMyAllocator(hr);
if (!pAlloc)

return E_OUTOFMEMORY;

if (FAILED(hr))

delete pAlloc;
return hr;

// Return the IMemAllocator interface。
return pAlloc-QueryInterface(IID_IMemAllocator, void)ppAllocator);}


缺省情况下CBaseOutputPin首先从输入pin中申请一个allocator。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值