《微软:DirectShow编程》第一章 DirectShow的基本概念

The basics Chapter 1 DirectShow Concepts

From the viewpoint of the application programmer, Microsoft DirectShow is composed of two types of

classes of objects: filters, the atomic entities of DirectShow; and filter graphs, collections of filters

connected together to provide specific functionality. Just as atoms are composed of electrons, protons,

and neutrons, filters are composed of pins, which can either receive an input stream or send an output

stream to another filter. Conceptually, filters can be thought of as function calls in a DirectShow

programming language, while a filter graph is the program composed of those function calls. Here is

what it might look like, in pseudo C++ code:

从应用层的程序员的角度来看,DirectShow由两种类型的类对象组成:filter, 它是DirectShow的原子组成; filter graph, 用来提供特定功能的彼此连接的filter的集合。正如原子是由电子,质子和中子组成的类似,filter是由pin组成的,这些pin要么用来接收输入流,要么用来发送输出流到其它的filter。在概念上,filter可以被认为是DirectShow编程语言实现的函数调用,而filter graph则是由这些函数调用组成的程序。依据这个概念,可以将DirectShow的程序用如下C++伪码来表示:


  1. FilterGraph() {
  2.   SourceFilter(); // A source filter
  3.   TranformFilter(); // Usually, a transform filter
  4.   … // As many other filters as needed
  5.   RendererFilter(); // A renderer filter
  6. }

As is the case in most programming languages, the DirectShow filter graphs execute sequentially,

from the first filter to the last. Data enters at the first filter in the filter graph, passes along to the second

filter, and so on. What makes a DirectShow filter graph different from a common C++ program is that it

also executes continuously. When a filter graph starts its execution, data begins to flow across the

filters in a filter graph like a waterfall descending a series of stairs. This data flow is commonly known

as a stream. This stream is operated on by all filters in a filter graph simultaneously. Chapter 10

contains a detailed exploration of exactly how data flows across a filter graph and how DirectShow

adjusts its operation to keep the filter graph from running dry or being overwhelmed with a data stream.

和其它的编程语言一样,DirectShow的filter graph是顺序执行的----从第一个filter到最后一个。数据也是从filter graph的第一个filter进入,处理后到第二个filter,依次往下。DirectShow的filter graph和一般的C++程序不同之处在于:它的执行是连续的。意即,当一个filter graph启动后,数据就像瀑布一样,在filter graph的filter中一级一级往下流。这种数据流被称为流。从这种角度来看,filter graph中的流被所有的filter同时处理。第10章详细解释了数据流是如何流过filter graph的,并且描述了如何调整以使filter graph的数据流不被流干或淹没。

 

One important point distinguishes a DirectShow filter graph from an ordinary computer program: a

filter graph can have multiple streams flowing across it and multiple paths through the filter graph. For

example, a DirectShow application can simultaneously capture video frames from a webcam and

audio from a microphone. This data enters the filter graph through two independent source filters,

which would likely later be multiplexed together into a single audio/video stream. In another case, you

might want to split a stream into two identical streams. One stream could be sent to a video renderer

filter, which would draw it upon the display, while the other stream could be written to disk. Both

streams execute simultaneously; DirectShow sends the same bits to the display and to the disk.

DirectShow的filter graph和普通的程序一个重要的区别是:一个filter graph可以有多个流经过不同的路径流过它。例如,一个DS应用程序可以在从摄像头捕捉视频帧的同时从话筒捕捉音频。数据从两个独立的源filter进入到filter graph,而这两个数据可能在随后的处理中混合成一个音视频流。而在另一种情形中,可以将一个流分割成两个独立的流,一流可以送到的视频渲染filter用于显示,另一个流可以存成文件,而且这两者同时进行,流数据也相同。

 

DirectShow filters make computations and decisions internally—for instance, they can change the

values of bits in a stream—but they cannot make decisions that affect the structure of the filter graph.

A filter simply passes its data along to the next filter in the filter graph. It can’t decide to pass its data

to filter A if some condition is true or filter B if the condition is false. This means that the behavior of a

filter graph is completely predictable; the way it behaves when it first begins to operate on a data

stream is the way it will always operate.

DS的filter可以进行内部的计算和判断—例如,filter可以改变流中的比特位的值—但是,它们不能改变filter graph的结构。Filter只能在filter graph中将它的数据处理后传给下一个filter,它不能做如果条件为真则将数据传给A filter,条件为假则将数据传给B filter的判断。这就意味着,一个filter graph的行为是完全可预知的。它的行为方式是数据一开始如何处理,后面也会如何处理。

 

Although filter graphs are entirely deterministic, it is possible to modify the elements within a filter

graph programmatically. A C++ program could create filter graph A if some condition is true and filter

graph B if it’s false. Or both could be created during program initialization (so that the program could

swap between filter graph A and filter graph B on the fly) as the requirements of the application

change. Program code can also be used to modify the individual filters within a filter graph, an

operation that can change the behavior of a filter graph either substantially or subtly. So, although filter

graphs can’t make decisions on how to process their data, program code can be used to simulate that

capability.

尽管filter graph的行为是完全确定的,但是可以通过程序的方式来修改filter graph中的元素。如果条件为真,C++程序可以创建filter graph A, 条件为假时,则可以创建filter graph B。或者,在程序初始化时,可以两者都创建(这样应用程序可以在filter graph A 和 B之间快速地切换)。应用程序同样还可以去修改filter graph中各个独立的filter,如可能通过应用程序的操作来大幅或微小地改变filter graph的行为。因此,尽管filter graph不能在如何处理它们的数据上做判断,但是应用程序可以实现这个功能。

 

For example, consider a DirectShow application that can capture video data from one of several

different sources, say from a digital camcorder and a webcam. Once the video has been captured, it

gets encoded into a compact Windows Media file, which could then be dropped into an e-mail

message for video e-mail. Very different source and transform filters are used to capture and process

a video stream from a digital camcorder than those used with a webcam, so the same filter graph

won’t work for both devices. In this case, program logic within the application could detect which input

device is being used—perhaps based on a menu selection—and could then build the appropriate filter

graph. If the user changes the selection from one device to another, program logic could rebuild the

filter graph to suit the needs of the selected device.

例如,DirectShow的应用层能从多个不同的源—从DC或Webcam—捕捉视频数据。当视频被捕捉后,它被编码压缩成Windows Media文件—它能够通过e-mail进行发送。因此,对于DC和Webcam来说,同一个filter graph是无法工作在两种设备上,从而要使用不同的源和转换filter来进行捕捉和处理这两者的视频流。在这种情况下,应用程序的逻辑需要检测—可能通过菜单选项—当前是使用哪个设备并创建相应的filter graph。如果用户的选择从一个设备换到了另一个设备,程序逻辑同样能重新创建filter graph来适应新设备的需要。

Modular Design

The basic power and flexibility of DirectShow derives directly from its modular design. DirectShow

defines a standard set of Component Object Model (COM) interfaces for filters and leaves it up to the

programmer to arrange these components in some meaningful way. Filters hide their internal

operations; the programmer doesn’t need to understand or appreciate the internal complexities of the

Audio Video Interleaved (AVI) file format, for example, to create an AVI file from a video stream. All

that’s required is the appropriate sequence of filters in a filter graph. Filters are atomic objects within

DirectShow, meaning they reveal only as much of themselves as required to perform their functions.

DirectShow的能力和灵活性源于它的模块化设计。DirectShow为filter定义了一个COM接口的标准集并让程序员以想要的方式组织这些组件。Filter隐藏了它们的内部操作。例如,程序员并不需要理解AVI文件格式的内部细节也能使用视频流创建一个AVI文件。所有要做的工作只是以恰当的方式组织filter graph中的filter。Filter是DirectShow中的原子对象,这意味着他们只会按它们的定制要求执行它们的函数。

Because they are atomic objects, filters can be thought of and treated just like puzzle pieces. The

qualities that each filter possesses determine the shape of its puzzle piece, and that, in turn,

determines which other filters it can be connected to. As long as the pieces match up, they can be

fitted together into a larger scheme, the filter graph.

filter都是原子对象,因此可以将它们看作是一个个的拼图用的块,只有将这些拼图块按正确的方式匹配成功,才能真正组成一个大的主题,即filter graph。

All DirectShow filters have some basic properties that define the essence of their modularity. Each

filter can establish connections with other filters and can negotiate the types of connections it’s willing

to accept from other filters. A filter designed to process MP3 audio doesn’t have to accept a

connection from a filter that produces AVI video—and probably shouldn’t. Each filter can receive some

basic messages—run, stop, and pause—that control the execution of the filter graph. That’s about it;

there’s not much more a filter needs to be ready to go. As long as the filter defines these properties

publicly through COM, DirectShow will treat it as a valid element in a filter graph.

所有的DS filter都具有一些基本的属性,即这些模块的本质。每个filter都能和其它的filter建立连接并能协商这些连接的类型。如一个用来处理MP3音频的filter就不能接受一个用来生成AVI视频的filter的连接。每个filter都能够接受一些基本的消息—运行,停止和暂停—这些消息控制了filter graph的执行。真实情况可能是这样:不会有多于一个filter需要准备运行。当filter通过COM定义了这些公共属性后,DirectShow将会把这些消息当作filter graph的有效元素。

 

This modularity makes designing custom DirectShow filters a straightforward process. The

programmer’s job is to design a COM object with the common interfaces for a DirectShow filter, plus

whatever custom processing the filter requires. A custom DirectShow filter might sound like a complex

affair, but it’s really a routine job, one that will be covered extensively in the examples in Part III.

这种模块化使得设计一个定制化的DS filter成为一件很容易的事情。程序员的工作只是先为DS filter设计一个有通用接口的COM对象,再加个这个filter要求的定制的处理。定制化的DS filter听起来像是一件很复杂的工作,但它实际上只是一件有规律的日常工作,Part III将会对它进行示例化的解释。

 

The modularity of DirectShow extends to the filter graph. Just as the internals of a filter can be hidden

from the programmer, the internals of a filter graph can be hidden from view. When the filter graph is

treated as a module, it can assume responsibility for connecting filters together in a meaningful way.

It’s possible to create a complete, complex filter graph by adding a source filter and a renderer filter to

the filter graph. These filters are then connected with a technique known as Intelligent Connect.

Intelligent Connect examines the filters in the filter graph, determines the right way to connect them,

adds any necessary conversion filters, and makes the connections—all without any intervention from

the programmer. Intelligent Connect can save you an enormous amount of programming time because

DirectShow does the tedious work of filter connection for you.

DS的模块化还扩展到了filter graph。如同filter对程序员隐藏了它内部的细节一样,filter graph同样也隐藏了这些细节。当把filter graph看作一个模块时,可以认为它是一个以一定有意义方式连接的filter。可以通过给已有的filter graph添加一个源filter和一个渲染filter来生成一个完整的,复杂的filter graph。而这些filter可以通过称为智能连接的技术连接起来。智能连接会检查filter graph中的这个filter, 确实连接它们的正确方式,添加必要的转换filter,并且这些连接不需要程序员的任何参与。智能连接能节省程序员大量的开发时间,因为DS替程序员做了这些单调乏味的连接工作。

There is a price to be paid for this level of automation: the programmer won’t know exactly which filters

have been placed into the filter graph or how they’re connected. Some users will have installed

multiple MPEG decoders—such as one for a DVD player and another for a video editing application.

Therefore, these systems will have multiple filters to perform a particular function. With Intelligent

Connect, you won’t know which filter DirectShow has chosen to use (at least, when a choice is

available). It’s possible to write code that will make inquiries to the filter graph and map out the

connections between all the filters in the filter graph, but it’s more work to do that than to build the filter

graph from scratch. So, modularity has its upsides—ease of use and extensibility—and its

downsides—hidden code.

但是这种智能化有一定的代价:程序员并不知道哪些filter被添加到了filter graph中或者它们是如何连接。有时,有些用户安装了多个MPEG解码器—例如一个是用于DVD 播放器的,而另一个用于视频编辑的应用。因此,这样的系统会有多个filter来执行特定的功能。但对于智能连接来说,程序员可能会并不知道DS采用了哪个filter。对于这种情况,可以通过代码来查询filter graph到底使用了哪些filter来建立连接,这无形中添加了一些额外的工作。因此,模块化有它的上限—容易使用和扩展,也有它的下限—隐藏代码。

 

Hiding complexity isn’t always the best thing to do, and you might choose to build DirectShow filter

graphs step by step, with complete control over the construction process. Overall, the modular nature

of DirectShow is a huge boon for the programmer, hiding gory details behind clean interfaces. This

modularity makes DirectShow one of the very best examples of object-oriented programming (OOP),

which promises reusable code and clean module design, ideals that are rarely achieved in practice.

DirectShow achieves this goal admirably, as you’ll see.

隐藏复杂性也不总是好事情,因为有时程序员可能要以完全控制的方式一步一步地构建DS 的filter graph的处理过程。但是,总之,对于程序员来说,DS的模块化带来了极大的方便,在简洁的接口后面隐藏了大量的细节。这种模块化使得DS成为了OOP一个最生动的实例,而后者正是为了实现代码重用和简洁的模块设计。

 

Filters

Filters are the basic units of DirectShow programs, the essential components of the filter graph. A filter

is an entity complete unto itself. Although a filter can have many different functions, it must have some

method to receive or transmit a stream of data. Each filter has at least one pin, which provides a

connection point from that filter to other filters in the filter graph. Pins come in two varieties: input pins

can receive a stream, while output pins produce a stream that can be sent along to another filter.

Filter是DS程序的基本单元,也是filter graph的基本组件。一个filter是一个完整的实体。尽管一个filter可以有多个不同的函数,但是它们都要以相同的方式接受或传输数据流。每个filter至少有一个pin, 它提供了一个filter连接到另一个filter的连接点。Pin可以分成两种类型:输入pin,用来接收流; 输出pin,生成可连接到其它filter的流。

 

Filter Types

There are three basic classes of DirectShow filters, which span the path from input, through

processing, to output (or, as it’s often referred to, rendering). All DirectShow filters fall into one of these

broad categories. A filter produces a stream of data, operates on that stream, or renders it to some

output device.

DS的filter可以分为三种类型,它涵盖了从输入,处理,到输出的整个路径。所有DS filter必为其中之一。

 

Source Filters

Any DirectShow filter that produces a stream is known as a source filter. The stream might originate in

a file on the hard disk, or it might come from a live device, such as a microphone, webcam, or digital

camcorder. If the stream comes from disk, it could be a pre-recorded WAV (sound), AVI (movie), or

Windows Media file. Alternately, if the source is a live device, it could be any of the many thousands of

Windows-compatible peripherals. DirectShow is closely tied in to the Windows Driver Model (WDM),

and all WDM drivers for installed multimedia devices are automatically available to DirectShow as

source filters. So, for example, webcams with properly installed Windows drivers become immediately

available for use as DirectShow source filters. Source filters that translate live devices into DirectShow

streams are known as capture source filters. Chapter 12 covers the software design of a source filter

in detail.

所有能生成流的DS filter都可以认为是源filter。这个流可以源自硬盘上的文件,也可以是实时设备,如话筒,摄像头,或是DC。如果这个流是源自磁盘,那么它可以是预先记录的WAV, AVI或是Windows Media文件。相应的,如果源是一个实时设备,那么它可以是Window兼容的所有外设。DS是紧密绑定在WDM上,所有的安装后的多媒体设备的WDM驱动都自动可作为DS的源filter。因此,例如,安装了驱动的摄像头可以立即成为DS的源filter。将实时设备转换成DS流的源filter又可以称作捕捉源filter。第12章详细描述了源filter的设计实现。

 

Transform Filters

Transform filters are where the interesting work gets done in DirectShow. A transform filter receives

an input stream from some other filter (possibly a source filter), performs some operation on the

stream, and then passes the stream along to another filter. Nearly any imaginable operation on an

audio or video stream is possible within a transform filter. A transform filter can parse (interpret) a

stream of data, encode it (perhaps converting WAV data to MP3 format) or decode it, or add a text

overlay to a video sequence. DirectShow includes a broad set of transform filters, such as filters for

encoding and decoding various types of video and audio formats.

转换filter是DS着墨最多的工作。转换filter从其它filter(可能是源filter)接收一个输入流,对流执行某些操作后,将流传输给下一个filter。几乎所有能相像得到的对音视频流的操作都可以在转换filter中实现。一个转换filter可以解析流的数据,编码它(可能将WAV数据转换成MP3格式)或解码它,或对一个视频序列添加一个文字层。DS包含有大量的转换filter,如编码或解码各种各样的音视频格式。

 

Transform filters can also create a tee in the stream, which means that the input stream is duplicated

and placed on two (or more) output pins. Other transform filters take multiple streams as input and

multiplex them into a single stream. Using a transform filter multiplexer, separate audio and video

streams can be combined into a video stream with a soundtrack.

转换filter同样还可以给流创建一个多通管道,意思是一个输入流可以复制到一个或多个输出pin上。而有些转换filter可以将多个输入流混合成一个流。

 

Renderer Filters

A renderer filter translates a DirectShow stream into some form of output. One basic renderer filter can

write a stream to a file on the disk. Other renderer filters can send audio streams to the speakers or

video streams to a window on the desktop. The Direct in DirectShow reflects the fact that DirectShow

renderer filters use DirectDraw and DirectSound, supporting technologies that allow DirectShow to

efficiently pass its renderer filter streams along to graphics and sound cards. This ability means that

DirectShow’s renderer filters are very fast and don’t get tied up in a lot of user-to-kernel mode

transitions. (In operating system parlance, this process means moving the data from an unprivileged

level in an operating system to a privileged one where it has access to the various output devices.)

渲染filter将DS流转换成某种形式的输出。如基本的渲染filter可以将流写到文件。而其它的渲染filter可以将音频流发送到扬声器,或将视频流发送到桌面上的窗口。DirectShow中的Direct反映的是:使用DirectDraw和DirectSound的渲染filter支持将它的流高效传输给显卡和声卡的技术。这个能力意味着DS的渲染filter能进行快速且无关用户-内核模式的传输。(对于OS来说,这个处理意味着将数据从用户层传输到内核层)

 

A filter graph can have multiple renderer filters. It is possible to put a video stream through a tee,

sending half of it to a renderer filter that writes it to a file, and sending the other half to another

renderer filter that puts it up on the display. Therefore, it is possible to monitor video operations while

they’re happening, even if they’re being recorded to disk—an important feature we’ll be using later on.

一个filter graph可以有多个渲染filter。如使用一个多通管道将一路视频流送到一个渲染filter以生成文件,另一路则将它送到另一个渲染filter以用于显示。从而可以实现监视视频的同时写文件。

 

The Complete Picture

All DirectShow filter graphs consist of combinations of these three types of filters, and every

DirectShow filter graph will have at least one source filter, one renderer filter, and (possibly) several

transform filters. In each filter graph, a source filter creates a stream that is then operated on by any

number of transform filters and is finally output through a renderer filter. These filters are connected

together through their pins, which provide a well-defined interface point for transfer of stream data

between filters.

所有的filter graph都是由这三种类型的filter组成,并且至少要有一个源filter,一个渲染filter,和可能多个的转换filter。在每个filter graph中,源filter创建流,经一个或多个转换filter处理后输出给渲染filter。这些filter通过它们的pin进行连接,这些pin为filter之间的数据流的传输提供了预先定义好的接口点。

 

Connections Between Filters

Although every DirectShow filter has pins, it isn’t always possible to connect an input pin to an output

pin. When two filters are connecting to each other, they have to reach an agreement about what kind

of stream data they’ll pass between them. For example, there are many video formats in wide use,

such as DV (digital video), MPEG-1, MPEG-2, QuickTime, and so on. A transform filter that can

handle DV might not be able handle any other video format. Therefore, a source filter that creates an

MPEG-2 stream (perhaps read from a DVD) should not be connected to that transform filter because

the stream data would be unusable.

尽管每个DS filter都已经有pin了,但是这些现成的pin不是一定能匹配地将一个输入pin连接到一个输出pin上。当两个filter试图建立连接时,它们需要对它们之间进行传输的数据流的类型达成一致。例如,有多种视频格式需要处理,如DV, MPEG-1, MPEG-2, QuickTime等等。但一个转换filter可能只能处理DV格式而不能处理其它格式。因此,当源filter创建了一个MPEG-2流(可能从DVD读取得到的)时,就不能和这个转换filter进行连接,因为它处理不了这种数据流。

 

The pins on a DirectShow filter handle the negotiation between filters and ensure that the pin types are

compatible before a connection is made between any two filters. Every filter is required to publish the

list of media types it can send or receive and a set of transport mechanisms describing how each filter

wants the stream to travel from output pin to input pin. (Both media types and transport mechanisms

will be covered in detail in Part III.)

DS filter的pin用来处理filter之间的协商并确保两个filter之间的pin连接的类型是兼容的。每个filter都被要求发布它能发送或接收的媒体类型列表,以及描述了每个filter想要从输出pin传输到输入pin的流的转换机制集合(媒体类型和转换机制都将在Part III详细讲述)。

 

When a DirectShow filter graph attempts to connect the output pin of one filter to the input pin of

another, the negotiation process begins. The filter graph examines the media types that the output pin

can transmit and compares these with the media types that the input pin can receive. If there aren’t

any matches, the pins can’t be connected and the connection operation fails.

当DS的filter graph尝试连接一个filter的输出pin到另一个filter的输入pin时,协商机制就开始了。Filter graph会先检查输出pin能传输的媒体类型并和输入pin能接受的媒体类型进行比较。如果没有一对是匹配的,那么这个pin的连接就不建立,即连接操作失败。

 

Next the pins have to agree on a transport mechanism. Once again, if they can’t agree, the connection

operation fails. Finally one of the pins has to create an allocator, an object that creates and manages

the buffers of stream data that the output pin uses to pass data along to the input pin. The allocator

can be owned by either the output pin or the input pin; it doesn’t matter, so long as they’re in agreement.

紧接着,pin之间的连接要在传输机制上取得协商一致。再次,如果不匹配,这个连接也会失败。如果上述的两个步骤都协商成功后,那么其中的一个pin将会创建一个分配器—一个用来创建和管理流数据buffer(输出pin用来将数据传输给输入pin)的对象。只要两个pin之间是协商一致的,这个分配器是输出pin所有还是输入pin所有都是可以的。

 

If all these conditions have been satisfied, the pins are connected. This connection operation must be

repeated for each filter in the graph until there’s a complete, uninterrupted stream from source filter,

through any transform filters, to a renderer filter. When the filter graph is started, a data stream will

flow from the output pin of one filter to the input pin of the other through the entire span of the filter

graph.

如果上述的三个条件都满足,那么这两个pin的连接就建立成功了。上述的三个连接操作必须对filter graph中的每个filter之间的连接重复执行,直到建立了一个完整的,不中断的从源filter,经转换filter到渲染filter的流。当filter graph启动后,数据流将会从一个filter的输出pin传输到另一个filter的输入pin并最终流经整个filter graph。


  1. Pin连接时的调用实例分析:
  2. 函数调用堆栈:
  3. CVCamPin::GetMediaType(int iPosition, CMediaType * pmt)   //获得数据sample的媒体类型
  4. CEnumMediaTypes::Next();                                                             // 按序号检索枚举列表中的成员
  5. CBasePin::TryMediaTypes();                                                           // 对要进行的检查当前的媒体类型
  6. CBasePin::AgreeMediaType();                                // 在连接的过程中枚举出当前pin和接受连接pin之间首选的数据类型.
  7. CBasePin::Connect();                                               // Initiates a connection from this pin to the other pin. 

  8. 找到一个媒体类型时:
  9. CVCamPin::CheckMediaType(const CMediaType *pMediaType)  // 确定这个pin是否支持给定的媒体类型
  10. CBasePin::AttemptConnection()                                                           // 以给定的媒体类型尝试进行连接
  11. CBasePin::TryMediaTypes();                                                                 // 对要进行的检查当前的媒体类型
  12. CBasePin::AgreeMediaType();                                 // 在连接的过程中枚举出当前pin和接受连接pin之间首选的数据类型.
  13. CBasePin::Connect();                                                // Initiates a connection from this pin to the other pin. 

  14. 再之后:
  15. CVCamPin::SetMediaType(const CMediaType *pMediaType)        // 对数据sample设置它的媒体类型
  16. CBasePin::AttemptConnection()                                                           // 以给定的媒体类型尝试进行连接
  17. CBasePin::TryMediaTypes();                                                                 // 对要进行的检查当前的媒体类型
  18. CBasePin::AgreeMediaType();                              // 在连接的过程中枚举出当前pin和接受连接pin之间首选的数据类型.
  19. CBasePin::Connect();                                             // Initiates a connection from this pin to the other pin. 

  20. 协商完成后,开始进行分配器的工作:
  21. CVCamPin::DecideBufferSize(IMemAllocator * pAlloc, _AllocatorProperties * pProperties) //获得传输的buffer大小
  22. CBaseOutputPin::DecideAllocator()                                                    // 协商两者之间的分配器
  23. CBaseOutputPin::CompleteConnect()                                                // 执行和另一个filter的连接
  24. CBasePin::AttemptConnection()                                                           // 以给定的媒体类型尝试进行连接
  25. CBasePin::Connect();                                             // Initiates a connection from this pin to the other pin. 

  26. 最后
  27. CVCam::QueryInterface(REFIID riid, void **ppv)                             // 检查这个对象是否可用这个接口

Intelligent Connect

One of the greatest strengths of DirectShow is its ability to handle the hard work of supporting multiple

media formats. Most of the time it’s not necessary for the programmer to be concerned with what kinds

of streams run through a filter graph. Yet to connect two pins, DirectShow filters must have clear

agreement on the media types they’re handling. How can both statements be true simultaneously?

Intelligent Connect automates the connection process between two pins. You can connect two pins

directly, so long as their media types agree. In a situation in which the media types are not compatible,

you’ll often need one (or several) transform filters between the two pins so that they can be connected

together. Intelligent Connect does the work of adding and connecting the intermediate transform filters

to the filter graph.

DS最大的能力在于它能处理需要支持多种媒体格式下的复杂工作。很多时候它并不需要程序员关心filter graph中的流的类型。然而,对于两个pin之间的连接来说,DS的filter必须明确协商一致它们之间所要处理的媒体类型。如何使这两种需求都能满足呢?智能连接使两个pin之间的连接处理自动化了。如果两个pin之间的媒体类型是一致的,则这两个pin可以直接连接。但是当它们之间的媒体类型不兼容时,就通常需要在它们两者之间插入转换filter再使它们连接。智能连接就实现了这个插入和连接中间转换filter的工作。

 

For example, a filter graph might have a source filter that produces a stream of DV data—perhaps it’s

connected to a camcorder. This filter graph has a renderer filter that writes a file to disk. These two

filters have nothing in common. They don’t share any common media types because the DV data is

encoded and interleaved and must be decoded and de-interleaved before it can be written to a file.

With Intelligent Connect, the filter graph can try combinations of intermediate transform filters to

determine whether there’s a way to translate the output requirements of the pin on the source filter into

the input requirements of the render filter. The filter graph can do this because it has access to all

possible DirectShow filters. It can make inquiries to each filter to determine whether a transform filter

can transform one media type to another—which might be an intermediate type—transform that type

into still another, and so on, until the input requirements of the renderer filter have been met. A

DirectShow filter graph can look very Rube Goldberg–esque by the time the filter graph succeeds in

connecting two pins, but from the programmer’s point of view, it’s a far easier operation. And if an

Intelligent Connect operation fails, it’s fairly certain there’s no possible way to connect two filters. The

Intelligent Connect capability of DirectShow is one of the ways that DirectShow hides the hard work of

media processing from the programmer.

例如,filter graph的源filter可以生成DV数据流—可能连接了录像机。而它的渲染filter用来写文件。这两个filter没有一个相同的地方。它们没有一个共有的媒体类型,因为DV数据是编码并且隔行扫描,而存成文件的必须是解码并去隔行扫描了的。对于智能连接来说,filter graph会尝试连接一个中间转换filter,将源filter输出pin的数据类型转换成渲染filter的输入pin要求的数据类型。Filter graph的这个功能是通过访问DS所有可能的filter来实现的。它可以请求每个filter来确认是否这个转换filter能将一种媒体类型转换到另一种媒体类型—可能是一个中间类型—转换这种类型直到匹配渲染filter最终要的媒体类型。DS filter graph可以快速查找并连接,从程序员的角度来说,它是一个很容易的操作。并且,如果智能连接失败,就可以很肯定地说这两个filter是无法连接的。这种智能连接的能力同样也是一种对程序员隐藏了复杂工作的实现。

 

Filter Graphs

The DirectShow filter graph organizes a group of filters into a functional unit. When connected, the

filters present a path for a stream from source filters, through any transform filters, to renderer filters.

However, it isn’t enough to connect the filters; the filter graph has to tell the filters when to start their

operation, when to stop, and when to pause. In addition, the filters need to be synchronized because

they’re all dealing with media samples that must be kept in sync. (Imagine the frustration if the audio

and video kept going out of sync in a movie.)

filter graph将多个filter组织成一个功能单元。当这些filter连接后,它们就表示了一条从源filter,通过转换filter,到达渲染filter的数据路径。但是,光连接上filter是不够的。Filter graph还要告诉这些filter什么时候开始它们的操作,什么时候停止,和什么时候暂停。另外,它们可能还要进行媒体数据的同步。

 

For this reason, the filter graph generates a software-based clock that is available to all the filters in

the filter graph. This clock is used to maintain synchronization and allows filters to keep their stream

data in order as it passes from filter to filter. Available to the programmer, the filter graph clock has

increments of 100 nanoseconds. (The accuracy of the clock on your system might be less precise than

100 nanoseconds because accuracy is often determined by the sound card or chip set on your

system.)

基于上面的要求,filter graph将会生成一个所有filter使用的基于软件的时钟。这个时钟用于保持同步并使流数据按顺序从一个filter到另一个filter。对于程序员来说,filter graph的时钟精度为100ns。

 

When the programmer issues one of the three basic DirectShow commands—run, stop, or pause—the

filter graph sends the messages to each filter in the filter graph. Every DirectShow filter must be able

to process these messages. For example, sending a run message to a source filter controlling a

webcam will initiate a stream of data coming into the filter graph from that filter, while sending a stop

command will halt that stream. The pause command behaves superficially like the stop command, but

the stream data isn’t cleared out like it would be if the filter graph had received a stop command.

Instead, the stream is frozen in place until the filter graph receives either a run or stop command. If the

run command is issued, filter graph execution continues with the stream data already present in the

filter graph when the pause command was issued.

当程序员发送了DS三个基本命令之一时—运行,停止,或暂停—filter graph将会发送给每个filter这个消息。每个DS filter都必须能处理这个消息。例如,当发送了运行消息后,控制摄像头的源filter将会生成送入filter graph的数据流,当发送了停止命令后将会停止这个流。暂停命令类似于停止命令,但是此时的流数据不像停止命令那样将数据清除。而是将流数据原地冻结直到filter graph收到了运行或停止命令。如果发送了运行命令,filter graph将会从暂停后的数据开始继续运行。

 

The Life Cycle of a Sample

To gain a more complete understanding of DirectShow, let’s follow a sample of video data gathered

from a DV camcorder as it passes through the a filter graph on its way to the display. Figure 1-1

illustrates the path.

为了更全面地理解DS,下面以DV数据采集并显示的例子来具体说明。

《微软:DirectShow编程》第一章 DirectShow的基本概念_第1张图片

Figure 1-1. Path of video data gathered from a camcorder

 

The video sample is generated in a source filter—in this case, a capture source filter because the filter

is capturing from a live device, a camera, rather than reading from a disk. Video camcorders in the

United States, Canada, and Japan (and some other regions and countries) generate 30 frames of

video data per second; it’s reasonably safe to assume that one DirectShow sample will be equivalent

to one frame of video captured by the camcorder. In this case, the source capture filter is a WDM

object that speaks directly to the computer’s hardware (which, in turn, is communicating directly with

the camcorder, probably over a FireWire interface). The capture source filter issues commands to the

driver for the camcorder, and in return, the filter receives data. Each packet of data is equivalent to

one frame of video.

视频样本由源filter生成—在这个例子中,是一个捕捉源filter,因为源filter是从摄像机这个实时设备来捕捉数据而不是从文件。摄像机以30帧/秒的速度生成数据。将DS的样本大小设置成视频帧大小是比较安全的方式。在这种情况下,源捕捉filter是一个WDM对象。捕捉源filter发送命令给摄像机的驱动,相应的,filter将收到数据且每个视频帧一个包。

 

In this example, the capture source filter’s primary role is to convert the packets of data arriving from

the camcorder into series of samples. When considered as a whole, these discrete samples compose

a stream of video data formatted for DirectShow. Once the camcorder data has been converted into a

stream, it can be presented on the source filter’s output pin so that it can be passed along to a

downstream filter. Additonally, the capture source filter provides a timestamp for each sample in the

stream so that DirectShow can maintain sample processing in the correct order; that is, samples

captured first will be processed first.

在这个例子中,捕捉源filter的主要作用是转换从摄像机得到的数据包成一系列的样本。当从整体上来看时,这些离散的样本组成了DS所要的视频数据流。一旦摄像机数据转换成流后,它就可以在源filter的输出pin中表示并传输到下一级的filter。另外,捕捉源filter还为流的每个样本打上了时间戳,以保持样本的正确的顺序,即,先捕捉到的样本先处理。

 

The next filter in the graph is a transform filter, a DV video decoder. This filter takes the raw video data

presented by the source capture filter and processes it in two significant ways. First it will likely convert

the color model of the video stream from the YUV model common in camcorders and other digital

imaging devices to the RGB model commonly used on computer displays. Many different color models

are used by imaging and display devices, and you’ll find that many of the DirectShow transform filters

convert from one color model to another to perform their tasks.

Graph中的下一个filter是一个转换filter,一个DV视频解码器。这个filter接收由源捕捉filter得到的原始视频数据,并对其进行两个重要的处理。首先是颜色模型的转换,如将其从YUV转换成RGB。

Next the DV video decoder might convert the interlaced video fields presented by the camcorder into

non-interlaced video images. Using interlacing, a single frame of video imagery is actually broken

down into two fields. The first field contains all the odd-numbered lines of video information, while the

second field contains all the even-numbered lines. The two fields must be combined—that is,

de-interlaced—to produce the non-interlaced (also known as progressive scan) image used on nearly

all computer displays. These two transformations, first of the color model and then de-interlacing, have

created a video stream that can now be rendered on the display. After processing, these samples are

presented at the output pin of the DV video decoder, which maintains the per-sample timestamp,

ensuring that the images stay correctly synchronized as they move from filter to filter.

DV视频解码器的下一个处理是去隔行。通过这两个转换,就生成了可以显示的视频流。经过这些处理,这些样本就可以发送到DV视频解码器的输出pin上,它们同时还保有每个样本的时间戳以同步。

 

Finally the stream arrives at its destination, the video renderer. The renderer filter accepts a properly

formatted video stream from the DV video decoder and draws it onto the display. As each sample

comes into the renderer filter, it is displayed within the DirectShow output window. Samples will be

displayed in the correct order, from first to last, because the video renderer filter examines the

timestamp of each sample to make sure that the samples are played sequentially. Now that the

sample has reached a renderer filter, DirectShow is done with it, and the sample is discarded once it

has been drawn on the display. The buffer that the filter allocated to store the sample is returned to a

pool of free buffers, ready to receive another sample.

最终,流到达了它的目的地,视频渲染。视频渲染filter从DV视频解码器接收合适格式的视频流并显示。当每个样本到达渲染filter后,它们都会以正确的顺序在DS的输出窗中显示,因为视频渲染filter会去检查每个样本的时间戳。样本到达后会进行显示,然后丢弃。渲染filter会分配一个buffer以存储这些样本。

 

This flow of samples continues until the filter graph stops or pauses its execution. If the filter graph is

stopped, all of its samples are discarded; if paused, the samples are held within their respective filters

until the filter graph returns to the running state.

这些样本流会一直持续直到filter graph接收到了停止或暂停的命令。当filter graph收到了停止命令时,所有的样本将会被丢弃。如果收到的是暂停,则样本会在filter中保持住直到graph 返回到运行状态。

 

Summary

At this point, you should have a basic understanding of how DirectShow works. DirectShow

applications create filter graphs; these filter graphs are composed of filters connected to form a path

from stream capture to the display or storage of a stream. Filters are independent, object-oriented

modules that handle one specific function in the processing of a media stream: capture or display of a

video image, playing a sound, and so on. Now that we’ve covered these basic points, we’ll begin to

explore GraphEdit, a useful DirectShow application that allows you to create your own, fully functional

filter graphs with just a few mouse clicks so that you can put these abstract concepts into practice.

到现在为止,应该对DS的工作流程有了一个大概的了解。接着进入的是GraphEdit的学习。

你可能感兴趣的:(编程,Stream,filter,video,Graph,微软)