Direct Show 笔记

一、 总览:

Graph、Filter、Pin、Simple

Graph:可以理解为媒体处理的流程图。

Filter:可以理解为媒体处理流程图中的一个步骤。

Pin:可以理解为媒体处理各个步骤之间的数据流节点。

Simple:可以理解为各个形态的数据。

Direct Show 笔记_第1张图片

Filter的分类:

· source filter:将数据从源(比如媒体文件)引入Graph。

· transform filter:数据流入、改变、流出。

· Renderer filters:把最终结果展现给用户。

· splitter filter:比如把一个媒体流分解为视频和音频。

· mux filter:和splitter filter相反。

1. Graph Manager

主要对处于同一个Graph的Filter(s)进行统一的管理。

比如:

· 各个Filter的状态切换

· 建立同步时钟

· 事件回发

· 创建

为什么要统一管理状态切换?

因为处于同一Graph中的各个Filter的状态切换往往需要遵循严格的先后顺序。所以一般通过发送命令给Graph Manager的方式进行各Filter的状态变更。

为什么要建立同步时钟?

比如声像需要同步。

2. Media Types

结构体AM_MEDIA_TYPE定义了媒体类型。

主要包含如下结构:

· Major type: 由一个GUID来表示。通常包含音视频、未知流、MIDI等等。

· Subtype: 由一个GUID来表示。Major type为视频,则子类型可以包括RGB-24, RGB-32, UYVY

· Format block: 说明图形尺寸、帧率等信息。如果Major type为视频,sub type为RGB-24,则Format block的信息会被自动辨识。

3. Sample和Allocator

需要注意的是,各个filter之间并不直接传送它们各自进行处理的数据的指针。它们通过一个暴露IMemAllocator接口的Com组件来分配内存。填充了数据的内存被封装到Sample里面。各个Filter真正使用的是Sample。Sample通常包含:

· 内存指针

· 时间戳

· 标识

· 媒体类型(可选)

这里当一个Filter使用Sample的时候,它同时掌握这个Sample的引用计数,这样就有效杜绝了资源争用现象的发生。

4. Filter Graph中的硬件

硬件被封装到Filter中,任何与硬件的交互都转化为与Filter的交互。

二、 Graph-Building 组件

Filter Graph Manager.

Capture Graph Builder:设计的初衷是视频捕获,但是可以衍生很多用途。

Filter Mapper and System Device Enumerator:枚举可用的filter.

DVD Graph Builder

Video Control

1. 智能拼接

1) 如果在Graph里面有一个没有输入的Filter,那么Graph在完成自己的时候,就会考虑这个Filter。如果有一个已有的Filter的流出恰好与这个没有输入的Filter的流入相匹配,则将这两个Filter连接。

2) Graph在完成自己的过程中也会查找所有注册过的Filter与当前非终点Filter的流出进行匹配。注册的Filter会有一个权值,作为Graph进行连接尝试的优先级依据。

步骤:

1) 使用IStreamBuilder(如果pin实现了这个接口,但大多数情况没有)。(否则2)

2) 查找被缓存的Filter。(否则3)

3) 查找Graph现有的Filter。(否则4)

4) 查找所有注册了的Filter。

2. 关键方法

IFilterGraph::ConnectDirect:直接连接两个Filter,如不成功,返回失败。

IGraphBuilder::Connect:连接两个Filter,如果可能,直接连接,否则通过中间Filter(s)进行连接。

IGraphBuilder::Render:你自己建立了一系列从源开始的Filter,基于这些Filter(s)完成Graph。

IGraphBuilder::RenderFile:从一个文件开始完成Graph.

IFilterGraph::AddFilter:向Graph中添加一个Filter

通过这些方法,你可以:

1、 由Graph Manager建立整个Graph。(通过RenderFile)

2由Graph Manager建立部分Graph。(比如你想自己写一个AVI文件,当然也可以通过Render来生成预览)

3完全手动建立整个Graph。(需要自己AddFilter,还需要自己Connect)。

三、 Direct Show 数据流概述

1. 关键接口(方法)

IMediaSample:对Filter之间使用的内存的封装。

IMemAllocator::GetBuffer:从allocator获取Buffer(即ImediaSimple的实现对象)

摘要:

由于Render会按照时间戳来Render数据,所以它会一直占用它的上一级Filter流入的Simple,直到时间戳所标识的时间到达。所以当上一级Filter用完了allocator的Simple池中的Simple时,会阻塞而不处理,进而反向影响到更上一级的Filters,从而使它们变为等待的状态。同时由于时间戳对于Render的时间上的要求,所有上级Render都必须在Simple的时间戳标识的时间到达之前处理完自己对于该Simple的动作。

2. Transport(传送)

· Push Model(推送模型):上层filter(pin-out)将处理好的数据推送给下层filter(pin-in)。下层filter在需要数据的时候通过IMemInputPin::Receive来获取数据。

· Pull Model(抓取模型):下层filter(pin-in)在需要数据的时候,通过IAsyncReader异步向上层filter请求数据。(通常用于视频文件的回放)

3. Samples and Allocators

1) 引用计数

上层Filter(pin-out)通过IMemAllocator::GetBuffer向Allocator申请Simple,如果此时没有Simple的引用计数为0,则说明Allocator的Simple池中没有可用的Simple,则GetBuffer的调用会被阻塞。一旦Simple池中出现可用的Simple,则先前阻塞的GetBuffer放行,并获取一个引用计数变为1的Simple。此Simple处理后,传递给下层Filter(pin-in),下层Filter如果在Receive方法中处理Simple,则它与上层Filter的处理处于同一线程中,Simple的引用计数不会变化,如果下层Filter需要通过创建线程异步使用上层推入的Simple进行处理,则该Simple的引用计数会加1,变为2.之后如果上层Filter的推送线程结束,则Simple的引用计数减1,变为1.

2) 提交和撤销Allocator

IMemAllocator::Commit,在被调用之前,所有的GetBuffer无效,

调用IMemAllocator::Decommit之后,所有的GetBuffer调用无效.

4. Filter 状态变化

Filter状态的变化由Graph Manager进行控制。

所有的状态变化都是自低(Render Filter)向上(Source Filter)进行的。比如暂停的时候,Render Filter会首先暂停,这时候Render之上的Filter中都会存有未能推送的Simple,此时相当于在各个Filter之前都堆积了一些等待处理的数据。沿着Render向上的Filter逐个暂停,直到Source。当状态从暂停变化为开始的时候,Render会首先变化为开始状态,处理在它之前堆积的数据,并释放那些被占用的Simple。然后逐步向上直到Source,Source在能够获取Simple之后,数据继续流入Graph,整个Graph进入开始状态。

你可能感兴趣的:(视频/音频/流媒体)