Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3425970
  • 博文数量: 864
  • 博客积分: 14125
  • 博客等级: 上将
  • 技术积分: 10634
  • 用 户 组: 普通用户
  • 注册时间: 2007-07-27 16:53
个人简介

https://github.com/zytc2009/BigTeam_learning

文章分类

全部博文(864)

文章存档

2023年(1)

2021年(1)

2019年(3)

2018年(1)

2017年(10)

2015年(3)

2014年(8)

2013年(3)

2012年(69)

2011年(103)

2010年(357)

2009年(283)

2008年(22)

分类: WINDOWS

2009-07-05 07:48:17

本节描述DirectShow的整体结构。本节包含的内容比较丰富,我们可能不需要知道所有的这些知识。因此,我们首先应该选择浏览全部的内容,然后根据实际应用程序的需要查看Using DirectShow的内容。如果有关于DirectShow结构的特殊问题,可以再回过来参考本节的内容。

About DirectShow
 
    本节描述DirectShow的整体结构。本节包含的内容比较丰富,我们可能不需要知道所有的这些知识。因此,我们首先应该选择浏览全部的内容,然后根据实际应用程序的需要查看Using DirectShow的内容。如果有关于DirectShow结构的特殊问题,可以再回过来参考本节的内容。
 
1. DirectShow System Overview
 
    1.1 The Challenge of Multimedia
    进行多媒体编程主要存在如下几个挑战:
    ·多媒体流包含大量的数据,这些数据又要求进行快速的处理
    ·音频、视频必须同步,以使它们在相同时间开始、停止,以相同的频率播放
    ·数据来源多,包括本地文件,计算机网络,电视广播和视频摄像机
    ·数据源的格式多,比如音频、视频交叉存取的(AVI),高级流格式(ASF),运动图像专家组(MPEG)和数字视频(DV)。
    ·程序员不能预先知道在用户终端系统存在的硬件设备
 
    1.2 The DirectShow Solution
    DirectShow就是被设计来解决这些挑战的。DirectShow通过把应用程序从复杂的数据传输、硬件区别和同步隔离起来。它的主要目标是简化在Windows平台创建数字媒体程序的任务。
    为了达到流递音频、视频所需的流量,DirectShow在可能的任何时候使用DirectDrawDirectSound。这些提交数据的数据有效的利用了用户的声卡和图形卡。DirectShow通过把媒体数据包装为带时间戳的Samples实现回放的同步。为了处理可能不同的数据源、格式和硬件设备,DirectShow使用模块化结构,通过这种结构应用程序可以混合、匹配不同的软件组件,这种组件称为Filters.
    DirectShow提供Filters支持捕捉和基于WDM的调频设备,Filters还支持旧的VFW捕捉卡,为音频压缩管理(ACM)编写的编解码器以及视频压缩管理器(VCM)接口。
    应用程序、DirectShow组件、以及DirectShow所支持的部分硬件、软件组件之间的关系如图。

    如同所示,DirectShow与各种不同的设备进行通信,并控制它们。包括本地文件系统,TV Tuner,视频捕捉卡,VFW编解码器,视频显示(通过DirectDraw或者GDI),以及声卡(通过DirectSound)。因此,DirectShow把应用程序与这些设备的复杂性隔离开来。DirectShow还为某些文件格式提供了本地的压缩、解压Filters.
 
2. The Filter Graph and Its Components
    本条款描述DirectShow的主要组件。主要目的是为应用程序开发人员和编写自定义DirectShow Filter的开发人员做些介绍。应用程序开发人员通常可忽略DirectShow的一些低级细节。但是,阅读此节仍是好主义,可以对DirectShow的结构有一个大概理解。
 
    2.1 About DirectShow Filters
    DirectShow基于模块化结构,每个处理阶段都由称为FilterCOM对象完成。DirectShow提供了一系列标准Filter用于应用程序开发,开发者也可以开发自己的Filter来扩展DirectShow的功能。为了举例说明,这里是一个播放AVI视频文件所需要的步骤,连同完成每步的Filters:
    ·从原始文件读取数据为字节流(File Source Filter
    ·检测AVI头,把字节流分析为单独的视频帧和音频SamplesAVI Splitter Filter
    ·解码视频帧(各种解码Filters, 取决于压缩格式)
    ·画视频帧(Video Renderer Filter
    ·把音频Samples发送到声卡(默认的DirectSound设备Filter
    这些Filters及结构如图所示:
    如图所示,每个Filter都与一个或多个Filter相连接。连接点也是一个COM对象,称为PinsFilters使用PINS把数据从一个Filter移动到下一个。图中的箭头表示数据的流向。在DirectShow,一个Filters的集合称为Filter Graph
    Filter有三种可能的状态,运行,停止,暂停。当一个Filter运行时,它就处理媒体数据流,当停止时,Filter就不处理数据,暂停状态用来在运行前Cue Data, Data Flow in the Filter Graph一节对这些概念有更详细的描述。除非特别的例外,状态改变都是协调贯穿在整个Filter GraphGraph的所有Filter的状态改变都是统一的。因此,Filter Graph也可说是运行,停止,暂停。
    Filter 一般分为下面几种类型。
    (1)、源FilterSource Filter):源Filter引入数据到Filter Graph,数据来源可以是文件、网络、照相机或者是任何地方。每个源Filter处理不同类型的数据源。
    (2)、变换FilterTransform Filter):变换Filter的工作是获取输入流,处理数据,并生成输出流。编码、解码读书变换Filter的例子。
    (3)、提交FilterRenderer Filter):提交FilterFilter图表里处于最后一级,它们接收数据并把数据提交给用户。比如,视频Renderer把视频帧画在显示器,音频Renderer把音频数据发送到声卡,File-Writer Filter把数据写入文件。
    (4)、分割FilterSplitter Filter):分割Filter把输入流分割成多个输出。例如,AVI分割Filter把一个AVI格式的字节流分割成视频流和音频流。
    (5)、混合FilterMux Filter):混合Filter把多个输入组合成一个单独的数据流。例如,AVI混合Filter把视频流和音频流合成一个AVI格式的字节流。它进行AVI分割Filter相反的操作。
    这些Filters种类的区别并非绝对。比如ASF Reader Filter既是Source Filter又是Splitter Filter.
    所有的Filters都暴露了IBaseFilter接口,所有的Pin都暴露了IPin接口。DirectShow也定义了一些其他的接口实现更特殊的功能。
 
    2.2 About the Filter Graph Manager
    Filter Graph Manager也是一个COM对象,用来控制Filter Graph中的所有的Filter,主要有以下的功能:
    ·协调Filters之间的状态改变
    ·建立参考时钟
    ·传递事件到应用程序
    ·提供应用程序建立Filter Graph的方法
    下面就这些功能做一个简单的说明。可以本文档的其他地方找到详细说明。
    状态改变:Filters的状态改变必须以一种特殊顺序发生。因此,应用程序并不将状态改变的命令直接发给Filter,而是发送给Filter Graph Manager一个简单命令,由Manager将命令分发给Graph中每一个FiltersSeeking也是按同样的方式工作,先由应用程序将Seek命令发送到Filter Graph Manager,然后由其分发给每个Filters
    参考时钟:Graph中的Filter都采用的同一个时钟,称为参考时钟(Reference Clock),参考时钟可以确保所有的数据流同步,视频桢或者音频Sample应该被提交的时间称为Presentation Time。它是相对于参考时钟来确定的。Filter Graph Manager应该选择一个参考时钟,可以选择声卡上的时钟,也可以选择系统时钟。
    Graph事件:Filter Graph Manager采用事件队列机制将Graph中发生的事件通知给应用程序,这个机制类似于Windows的消息循环。
    Graph构建的方法:Filter Graph Manager给应用程序提供了将Filter添加进Graph的方法,连接Filter的方法,断开Filter连接的方法。
    Filter Graph Manager没有的一个功能就是把数据从一个Filter移动到另一个Filter。这是由Filters自己通过它们的PIN连接完成的。处理过程总是在不同的线程进行。
    注意:Filters总是与Filter Graph Manager在同一进程,被进程类服务器加载。在Filters之间,FiltersFilter Graph Manager之间的函数调用都不会存在列举(Marshall)。
 
    2.3 About the Media Type
    因为DirectShow是基于模块化的,就需要有一种方式来描述Filter Graph每一个点的数据格式,例如,我们还以播放AVI文件为例,数据以RIFF块的形式进入Graph中,然后被分割成视频和音频流,视频流由一系列视频桢组成,而且还可能是压缩的。解码后,视频流由一系列的非压缩的位图组成,音频流也是同样的处理过程。
 
    2.3.1   Media Types: How DirectShow Represents Format
    媒体类型是一种很普遍的,可以扩展的用来描述数字媒体格式的方法,当两个Filter连接的时候,他们会在某种媒体类型达成一致。媒体类型决定了上一级Filter将要给下游的Filter发送什么类型的数据,以及数据的物理布局。如果两个Filters在媒体类型上没有达成一致,那么他们就没法连接起来。
    对于某些应用程序,我们不需要担心媒体类型。比如在文件回放中,DirectShow处理了所有的细节。其他类型的应用程序可能需要直接在媒体类型上操作。
    媒体类型是通过AM_MEDIA_TYPE结构定义的,此结构包含如下信息:
    ·主类型:它是一个GUID值,定义的全部的数据种类。主类型包括视频、音频、未解析的字节流、MIDI数据等等。
    ·子类型:也是GUID值,进一步定义媒体类型。比如,主类型是视频时,子类型可能是RGB-24RGB-32UYVY等等。对于音频,子类型可能是PCM音频、MPEG-1 Payload等等。主类型提供了比子类型更多的信息,但是它还没有定义格式的所有信息。比如,视频子类型没有定义图像大小和帧率。这些通过下面的格式子块说明。
    ·格式子块:它是描述格式细节的数据块。它是从AM_MEDIA_TYPE结构单独分配。AM_MEDIA_TYPEpbFormat指针指向格式子块。
    pbFormat是一个void*的指针,因为格式块会因为媒体类型的不同而有不同的布局。PCM音频使用WAVEFORMATEX结构。视频块结构包括VIDEOINFOHEADERVIDEOINFOHEADER2AM_MEDIA_TYPEformattype成员是指明在格式块所包含结构类型的GUID。每种结构都有一个GUIDcbForamt成员指定了格式块的大小。总是需要在废弃pbFormat指针前检测它的值。
    如果格式块被填充,主类型和子类型的信息可以忽略。但是,在没有完整的格式块时,主类型和子类型提供了一种方便的方法来识别格式。比如我们可指定一个通用的24RGB格式(MEDIASUBTYPE_RGB24,而不需要知道VIDEOINFOHEADER结构所需要的所有信息,比如图像大小和帧率。
    比如,Filter可能使用下面的代码来检测媒体类型:
HRESULT CheckMediaType(AM_MEDIA_TYPE *pmt)
{
    if (pmt == NULL)         return E_POINTER;
    // Check the major type. We're looking for video.
    if (pmt->majortype != MEDIATYPE_Video)
       return VFW_E_INVALIDMEDIATYPE;
    // Check the subtype. We're looking for 24-bit RGB.
    if (pmt->subtype != MEDIASUBTYPE_RGB24)
    return VFW_E_INVALIDMEDIATYPE;
    // Check the format type and the size of the format block.
    if ((pmt->formattype == FORMAT_VideoInfo) &&
    (pmt->cbFormat >= sizeof(VIDEOINFOHEADER) && (pmt->pbFormat != NULL))
    {
        // Now it's safe to coerce the format block pointer to the
        // correct structure, as defined by the formattype GUID.
        VIDEOINFOHEADER *pVIH = (VIDEOINFOHEADER*)pmt->pbFormat;
         return S_OK;
    }
    return VFW_E_INVALIDMEDIATYPE;
}
    AM_MEDIA_TYPE结构也包含了一些可选信息。它们可提供一些附加信息。但是Filters并不要求使用它们:
    ·lSampleSize: 如果非0就表示每个Sample的大小。如果是0,表示Sample大小可能随时改变
    ·bFixedSizeSamples: 如果是TRUE,表示lSampleSize值有效,否则应该忽略lSampleSize
    ·bTemporalCompression: 如果是FALSE,表示所有的帧都是关键帧
 
    2.4 About Media Samples and Allocators
    Filters通过Pin的连接来传递数据,数据流是从一个Filter的输出Pin流向相连的Filter的输入Pin。虽然有其他不少的传输机制存在,输出Pin最常用的传递数据的方式是调用输入Pin上的IMemInputPin::Receive方法。
    根据的Filter不同,有多种方式来分配媒体数据的内存块,可以在堆上分配,可以在DirectDraw的表面,也可以采用GDI共享内存,还有其他的一些分配机制。内存分配的响应对象被称为Allocator,也是一个COM对象,暴露了IMemAllocator接口。
    当两个Pin连接的时候,必须有一个Pin提供AllocatorDirectShow定义了一系列函数调用来确定由哪个Pin提供Allocator. PIN之间还会在Buffer的数量和大小上达成一致。
    在数据流开始之前,Allocator会创建一个Buffer池,在数据流动期间,上一级Filter就会将数据填充到Buffers然后传递给下一级Filter。但是,上一级Filter并不是直接将内存Buffer的指针直接传递给下一级的Filter,而是通过一个Media SampleCOM对象,这个COM对象是Allocator创建的用来管理内存BufferMedia Sample暴露了IMediaSample接口,一个Sample包含如下内容:
    ·指向内部Buffer的指针
    ·时间戳
    ·一些标志
    ·可选的媒体类型
    时间戳定义了Presentation TimeRenderer Filter就根据这个时间来安排Render顺序的。标志用来标示数据从前一个Sample后是否中断等等,媒体类型提供了一种中途改变数据格式的方法。通常,一般Sample没有媒体类型,表明它的格式从前一个Sample后没有改变。
    当一个Filter正在使用Buffer,它就会保持一个Sample的引用计数,Allocator通过引用计数用来确定是否可以重新使用一个Buffer。这样就防止了覆盖另一个Filter正在使用的Buffer。当所有的Filter都释放了对Sample的引用,Sample才返回到Allocator的内存池重新使用。 
阅读(703) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~