`
gaofen100
  • 浏览: 1227905 次
文章分类
社区版块
存档分类
最新评论

DirectShow 视频捕获(5) 基类如何实现连接

 
阅读更多

How the Base Classes Implement Connection

原文:http://msdn.microsoft.com/en-us/library/ms899460.aspx

CBasePin类和它的派生类CBaseOutputPinCBaseInputPin实现了大部分共同的连接情况下的机制,大部分都可以在派生类中重写,以便更多的过程控制。

连接过程依赖于下面4个接口的实现

只要输入引脚的过滤器(叫做下游过滤器)期望提供共享内存分配器来传输采样,IMemInputPin 和 IMemAllocator就是必须的。然而,在CBaseInputPin类中的实现假设这种情况,并且在IMemInputPin实现中提供一个分配对象给连接的输出引脚的请求。

默认的基类在连接的时候,派生于CBaseInputPin 和 CBaseOutputPin的引脚类只需要重写和实现少部分成员函数,并让基类做剩下的工作。从这些类派生的基类如CTransformInputPinCTransformOutputPin做大部分所需的工作来提供一个默认的连接方案。

从CBaseInputPin和CBaseOutputPin继承的引脚类只需要重写下面的成员函数使得能够连接引脚。

  • CBasePin::CheckMediaType,… 。重写的成员函数必须接受或者拒绝目标媒体类型。
  • CBasePin::GetMediaType,被输出引脚枚举器的媒体类型调用,用来建议已经通过传输过滤器的输入引脚达成一致的媒体类型。这个成员函数也用来显示源过滤器会产生的媒体类型。

并且,从CBaseOutputPin继承的输出引脚必须重写CBaseOutputPin::DecideBufferSize成员函数。这个函数通过基类调用,用来输入引脚通知所有取得的分配器,它会提供的媒体采样的大小和类型。这个由过滤器的输出引脚完成,因为派生的类应该知道将要发送到相连过滤器输入引脚的数据的大小和类型。

明白重载函数的上下文,对于在类库中连接代码的执行的单步调试很有帮助。所有连接在一个CBasePin::Connect成员函数中发生。

这部分包含如下主题。

  • Filter Graph Manager 开始连接
  • 和CBasePin::AgreeMediaType协商媒体类型
  • 和CBasePin::TryMediaTypes决定一个媒体类型

Filter Graph Manager 开始连接

当Filter Graph Manager 在输出引脚调用IPin::Connect方法开始连接,传递一个指向要连接的输入引脚的指针。Filter Graph Manager 已经提前获取了直线两个过滤器的IPin指针,例如在连接过滤器的时候调用IBaseFilter::EnumPins方法。EnumPins方法创建一个CEnumPins对象来枚举引脚,枚举器通过重复调用派生过滤器必须实现的CBaseFilter::GetPin成员函数。

CBasePin::Connect实现IPin::Connect的方法,并在做了很多工作。它调用下面的方法。

CBasePin::CheckConnect简单实现判断引脚的方向是否不同。重写的CBaseOutputPin::CheckConnect成员函数调用连接的输入引脚的IUnknown::QueryInterface方法获取一个指向那个引脚的IMemInputPin接口的指针。这回在后面的连接过程中被使用来向连接的输入引脚请求一个分配器。(如果输出引脚已经有一个分配器,你的派生类可以重写CBaseOutputPin::CheckConnect方法并且忽略获取IMemInputPin接口;例如想从上游过滤器使用分配器来消除拷贝。)

和CBasePin::AgreeMediaType协商媒体类型

下一步调用CBasePin::AgreeMediaType成员函数,尝试协商两个引脚都适合的媒体类型。这通过尝试从连接的输入引脚上找一个符合输出引脚的媒体类型。如果这样找失败了,找一个输出引脚提供的连接的输入引脚符合的媒体类型。

CBasePin::AgreeMediaType 调用下面的成员函数和方法

调用 连接的输入引脚的IPin::EnumMediaTypes 方法返回一个媒体枚举器(IEnumMediaTypes).这允许输出引脚检查输入引脚首选的媒体类型。

枚举器的IEnumMediaTypes::Next 方法调用派生的输入引脚的GetMediaType成员函数获取每一个媒体类型。如果GetMediaType 没有实现,基类的实现返回一个错误,但这不是打断连接的充分条件。(引脚不要求有一个首选的媒体类型,如果一个引脚或者其他可以建议一个它们都能接受的媒体类型。如果两个引脚都不能建议一个类型,连接就会失败)

和CBasePin::TryMediaTypes决定一个媒体类型

然后,CBasePin::AgreeMediaType 调用 CBasePin::TryMediaTypes。TryMediaTypes成员函数在连接的输入引脚的首先媒体类型中循环,并且为每一个找到的媒体类型调用派生的输出引脚类的CBasePin::CheckMediaType成员函数。派生的输出引脚类必须实现CheckMediaType。如果CheckMediaType访问媒体类型,调用连接输入引脚的IPin::ReceiveConnection方法和媒体类型来决定连接的输入引脚是否接受这个媒体类型。如果这样,TryMediaTypes调用CBaseOutputPin::CompleteConnect成员函数来结束连接到输入引脚。

如果输入引脚没有输出类型可用的媒体类型,CBasePin::AgreeMediaType重复整个过程,使用枚举器枚举输出引脚的媒体类型。(换言之,它获取自己的枚举器并且为每个首选的媒体类型调用TryMediaTypes。)再次,枚举器为每个在列表中的媒体类型调用GetMediaType。在这种情况下,GetMediaType必须实现,以便提供媒体类型。如果过滤器是一个源过滤器,它会暴露一个明确的媒体类型。如果过滤器是转换过滤器,媒体类型将会在过滤器的输入引脚和它相连的引脚间建立;转换过滤器必须查询这个媒体类型或者简单的使用上游过滤器的枚举器(除非转换过滤器改变输入到输出的媒体类型)。

CBasePin::TryMediaTypes 调用CheckMediaType,即使当TryMediaTypes枚举输出引脚的首选媒体类型列表。这是因为拥有的过滤器可能是一个透明过滤器,就是简单使用上游过滤器的媒体类型(和枚举器);这样直线是否决定的媒体类型是否兼容。这种输入引脚的转换过滤器也许服从连接时选择的媒体类型,在这种情况下直到转换过滤器的输出引脚类确定媒体类型是否和这个转换是否兼容。

如果可以建立一个媒体类型,TryMediaTypes最终调用CBaseOutputPin::CompleteConnect成员函数类协商内存分配器。

首先,CBaseOutputPin::CompleteConnect成员函数调用CBaseOutputPin::DecideAllocator成员函数。这个成员函数协商一个和输入引脚共享的内存分配器。通过调用连接的输入引脚的IMemInputPin::GetAllocator方法,这样获得一个指向一个有输入引脚提供的IMemAllocator interface接口指针。

然后,CompleteConnect调用纯虚函数CBaseOutputPin::DecideBufferSize,这个函数你必须在输出引脚类中必须重写和实现,因为只有派生类可以为它自己的媒体类型决定请求的缓冲区大小。

最后,CompleteConnect调用连接引脚的IMemInputPin::NotifyAllocator方法来通知分配器的输入引脚使用并提供用一个指向这个的指针给它。在输出引脚可以用一个不同的分配器重试或者连接失败的情况下,输入引脚可以拒绝这个分配器。如果你的派生类没有使用连接的输入引脚的分配器,在你的派生类中重写 CBaseOutputPin::DecideAllocator用一个分配器调用NotifyAllocator成员函数。

什么时候应该重连

重连总是通过Filter Graph Manager 的IFilterGraph接口进行。通过调用IFilterGraph2::ReconnectEx或者IFilterGraph::Reconnect方法进行重连。两个方法都传递两个引脚的IPin接口来重连的。ReconnectEx方法指定了一个媒体类型,因此不要记住那个类型去连接引脚,这样就变得重连更容易成功。

典型的过滤器都先连接上游的过滤器,然后连接下游的过滤器。所以,过滤器在通知可以连接输出引脚之前和输入引脚进行协商。当过滤器的输出引脚连接时,也许为过滤器的输入引脚建立的媒体类型和分配器变得明显不可用。在这种情况下,可以打断输入连接或者重连。

例如,考虑下面的连接情况。一个音频特效过滤器(例如,混音效果)要插入到MPEG音频减压过滤器和另外一个音频特效过滤器之间。在于上游的减压过滤器连接时,媒体类型比如选择22.05kHz、16位声道。然而,在这种情况下,当混音过滤器连接它的输出引脚时,下游过滤器只能接受11.025kHz、16位声道的媒体类型。因此,在连接下游过滤器后,混音特效过滤器必须和上游过滤器重连并且为11.025kHz媒体类型协商。

但是,媒体类型不是重连的唯一因素。在很多情况下,过滤器是一个原位转换过滤器,也就是过滤器不要求改变媒体类型或者拷贝数据。这样的过滤器可以设计出使用其他过滤器(如上游或者下游过滤器)的分配器,同样的使用其他过滤器的媒体类型。换句话说,这个过滤器在另一个过滤器的缓冲区中做转换(例如,源过滤器的文件缓冲区或者渲染过滤器的视频缓冲区)。

通常的规则是这种类型的过滤器应提供下游过滤器的分配器给上游的过滤器,来和输出引脚建立分配器。当上游的输出引脚引脚请输入引脚的一个分配器时,要求和输入引脚重连,以便提供一个通过转换过滤器的输出引脚获得的下游过滤器的分配器。因此原位转换过滤器 总是要重连。

需要重连要遵守两个重要的规则。

首先,过滤器一次从不要求一个重连,除非它能保证重连能够成功。如果重连失败了,会导致在过滤器图表中产生一个不能确定清除的异步错误。产生的任何错误(例如,不相容的媒体类型)都因该在第一次连接时产生,那时(至少通过过滤器图表管理器或者应用程序)在多个级别有足够的重试选择可用。

其次,过滤器应该在和调用IPin::Connect同一个线程中请求重连。例如下面的情况在不同的线程中尝试重连会导致错误。

  • 过滤器图表管理器在一个引脚调用Connect。
  • 过滤器引脚实行 Connect方法并创建一个线程来检查连接准备是否做好。
  • 过滤器图表管理器返回应用程序
  • 应用程序调用过滤器图表管理器的IMediaControl::RunIMediaControl::Run方法来开始过滤器图表,过滤器开始运行。
  • 线程从开始连接调用IFilterGraph2::ReconnectEx或者IFilterGraph::Reconnect方法,而且过滤器图表管理器开始重连。
  • 失败产生,因为过滤器在运行状态下不能重连。

在过滤器图表还在执行IGraphBuilder::Connect方法的过程中,只要IFilterGraph2::ReconnectEx或者IFilterGraph::Reconnect开始执行了,过滤器图表没有方法来阻止这个失败。在IPin::Connect返回之前掉要过滤器图表来重连是确保这个错误不会发生的最好方法。达到这个最好的方法是所有运行在同一个线程中。

分享到:
评论

相关推荐

    Directshow 开发平台基类

    Directshow开发平台基类是构建Directshow应用程序的基础组件,它为开发者提供了丰富的接口和类,以便于实现多媒体数据的捕获、处理和播放。在Directshow框架中,这些基类库(BaseClasses)通常链接到`strmbasd.lib`...

    视频采集的基类

    5. **格式转换**:视频数据可能需要转换为特定的格式,如RGB、YUV等,这可能由类内部的函数实现。 6. **设备接口**:`CCaptureVideo`可能使用标准的API(如Windows的DirectShow,Linux的V4L2,或者跨平台的OpenCV库...

    视频采集基类 CaptureVideo

    "CaptureVideo"是一个视频采集基类,它集成了预览、压缩和采集等核心功能,这些功能是通过DirectShow框架来实现的。接下来,我们将深入探讨这个基类背后的原理和相关知识点。 **1. 视频采集基础** 视频采集是指将...

    directshow_SDK开发笔记

    它支持多种媒体格式,包括ASF、MPEG、AVI、DV、MP3、WAV等,能够方便地实现多媒体流的捕获、回放、后期处理和存储,同时集成DirectDraw和DirectSound技术,可播放DVD,支持视频非线性编辑和数字摄像机的数据交换。...

    Directshow 9头文件及库

    Directshow 9头文件及库是Visual Studio(VS)开发中用于处理多媒体流的重要组件,尤其在视频播放、捕获和处理领域具有广泛的应用。它是一个框架,允许开发者创建能够处理音频和视频数据的应用程序,提供了低级访问...

    DirextShow SDK 基类源码

    DirectShow是Microsoft提供的一种框架,用于在Windows操作系统上处理多媒体流,包括视频、音频的捕获、播放和编辑。深入研究DirectShow SDK基类源码对于理解其工作原理、自定义过滤器(Filter)的开发以及优化多媒体...

    DirectShow操作系统摄像头

    它在Windows平台上提供了丰富的API接口,使得开发者能够高效地实现音视频的捕获、处理和播放功能。在这个特定的场景中,我们关注的是如何利用DirectShow来操作系统的摄像头。 在DirectShow中,摄像头被看作是一个...

    windows mobile下的directshow Baseclasses

    DirectShow是微软开发的一个强大的多媒体处理框架,广泛应用于视频捕获、播放、编辑等领域。在Windows Mobile操作系统上,DirectShow同样被用来实现多媒体内容的处理和播放。"Baseclasses"是DirectShow的一部分,它...

    网狐家园版 视频源码 directshow开发 客户端 服务端 h.264解码

    2. 视频源码:这里的“视频源码”指的是实现视频播放功能的原始代码,包含了播放器的核心逻辑。开发者可以研究这些源码,理解其工作原理,或者根据自己的需求进行二次开发。 3. 客户端与服务端:在视频传输系统中,...

    directshow 开发技术文档

    - **实现接口**:每个 Filter 都需要实现一定的接口以支持 DirectShow 的基本功能。 - **注册 Filter**:为了使 Filter 可以被 DirectShow 系统识别,需要对其进行注册。 #### 六、总结 **DirectShow** 提供了一套...

    DirectShow SDK学习笔记

    视频捕捉是DirectShow中最常见的应用之一,它包括从摄像头或其他视频源捕获视频信号,并进行处理和存储。 - **选择一个视频捕捉设备**: 识别并选择可用的视频捕捉设备。 - **预览视频**: 在捕获之前预览视频流。 - ...

    DirectShow系统初级指南.doc

    DirectShow的主要功能在于为多媒体流的捕获和回放提供支持,它涵盖了从采集卡、DVD播放、非线性视频编辑到数字摄像机数据交换等多个领域。DirectShow支持多种媒体格式,如Asf、Mpeg、Avi、Dv、Mp3、Wave等,使得...

    DirectShow使用大全

    DirectShow 是微软开发的一个用于处理多媒体流的框架,主要用于音频和视频的捕获、播放以及处理。这个框架是DirectX的一部分,DirectX 包含了一系列的API,如DirectSound、Direct3D等,用于游戏开发和其他多媒体应用...

    directshow配置所需lib

    它允许开发者构建复杂的多媒体应用程序,包括视频播放、捕获、编辑等。在配置DirectShow项目时,正确地链接和使用相关的静态库至关重要。本压缩包提供的"directshow配置所需lib"包含了配置DirectShow时所需的五个...

    Directshow(SDK)学习笔记

    通过继承和实现DirectShow提供的基类,可以创建自己的Filter来处理特殊格式的媒体或执行特定的处理任务。 总的来说,DirectShow SDK的学习笔记涵盖了DirectShow的基础知识,包括环境配置、基本概念、Filter Graph的...

    directshow框架的amcap源码

    5. **BaseClasses**:这个文件夹可能包含了一些基础类库,用于简化DirectShow编程,如过滤器和连接符的基类、事件处理机制等。 通过分析AMCap源码,我们可以学习到如何配置和控制Filter Graph,如何处理设备枚举,...

    DirectShow源码分析

    DirectShow是一种由微软开发的多媒体框架,用于处理视频和音频流。它提供了丰富的API,使得开发者可以构建复杂的媒体处理管道,包括捕获、播放、编辑和转换等多种功能。本系列的源码分析将深入探讨DirectShow的核心...

    baseclasses.zip

    开发者在安装了Win7 SDK之后,可以从这些源代码中获取必要的接口和类,以便于实现视频流的捕获、处理和输出。 Win7 SDK(Windows Software Development Kit)是微软提供的开发工具,它包含了开发、调试和部署...

    DIRECTSHOW学习笔记

    自定义Filter需要对DirectShow的基类有深入理解,这样才能更好地设计和实现Filter的功能。 例如,要播放一个AVI视频文件,Filter Graph的工作流程大致如下: 1. 源Filter读取AVI文件数据。 2. AVI Splitter分析文件...

Global site tag (gtag.js) - Google Analytics