Directshow中Filter开发基础[1]

[入库:2005年8月19日] [更新:2007年3月24日]

本文简介:选择自 aoosang 的 blog

摘要:
关于开发自己的filter,我以前写过一篇文章,《利用directshow开发自己的filter》,里面详细介绍了开发filter一些步骤,这里我想介绍一些filter的基础知识,可以让你更好的理解filter。本篇文档主要包括下面一些内容

  • 1filter的连接
    2filter间的数据流动
    3pin连接时数据格式的动态改变
    4threads and critical sections
    5质量控制管理
    6directshow和com
1filter的连接
pin的连接
应用程序通过调用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中申请一个allo

本文关键:Directshow中Filter开发基础
  相关方案
Google
 

本站最佳浏览方式为 分辨率 1024x768 IE 6.0(或更高版本的 IE浏览器)

go top