关闭

关于微软的DMO(Directx Media Object)MSDN翻译文章(一)

标签: object微软typesfiltermicrosoftoutput
4415人阅读 评论(0) 收藏 举报
分类:

原文请查看MSDN:http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directshow/htm/directxmediaobjects.asp

译文为作者辛苦翻译的产品(可能有部分翻译不是很准确,望知情者,联系:tonxi@163.com),转贴请注明原作者,为中国软件业进步努力着

DirectX Media Objects(一)

译者:tonxi

Microsoft® DirectX® Media Objects (DMOs)是基于COM的数据流组件。在某些部分上,DMOS是类似于Microsoft DirectShow filters。比如对于DirectShow filters, DMOs也是输入数据到创建输出数据。而且,DMOsAPIs比相应的DirectShowAPIs要简单的多。因此,DMOs是比较容易被创建,测试和使用。DMOs可以被用于很多方面:

    基于DirectShow的应用程序通过一个DirectShow filter叫作 DMO Wrapper filter来使用DMOs。而filtersDMOs的区别是,DMOs对于应用程序是透明的。应用程序不用直接访问DMO APIs.

    基于Microsoft DirectSound的应用程序可以使用audio effect DMOs。另外,应用程序通过高级的DirectSound APIs从低级的DMO APIs隔离出来。

    应用程序能够直接使用DMOs.

 

 

关于DMOs

这部分包括如下主题:

       DMOs的优势

       DMO的体系机构

 

DMOs的优势

DMOs提供了如下优势:

 

1、它们通常要比DirectShow filters要小而且简单,因为它们支持较少的功能。

2、它们要比DirectShow filters灵活,因为它们不需要一个filter Graph。当你需要DirectShow提供的一些服务时你可以让DMOs跟随DirectShow,这些服务例如,同步,智能连接,自动处理数据流程和线程管理。那些不需要这些服务的用户能够直接访问DMOs

3DMOs始终是同步数据处理,这样就消除了你写一个filter需要考虑的多线程问题(译者注:filter有独立的数据传送线程,需要考虑多线程编程问题)

4、与传统的ACMVCM codecs不同的是,DMOs是基于组件模型(COM)的,因此,它们通过QueryInterface(接口)的方式进行扩充。

5DMOs支持一个比ACM或者VCM codecs更大众化的流模型a more generalized streaming model)。如同DirectShow filtersDMOs能支持多输入和多输出。

由于这些原因,DMOs现在被推荐为写编码器,解码器和音频效果的解决方案。许多其它的方案可能也很不错,这主要取决于应用程序的需要。

 

DMOsDirectShow Filters有什么不同?

DirectShow filters运行离不开DirectShow filter graph。在DirectShow内,Filter Graph Manager用于应用程序和filters之间的调配。DirectShow filters要做很多数据流需求的工作,包括:

包括分配缓存。

协商媒体类型与连接其它的filters

将数据通过filter graph

发送事件给Filter Graph Manager

多线程的同步。

相对比的是,一个DMO不需要做上面的这些事情。代替的是,这些任务被要求给使用DMOClient去完成。Client负责分配缓存,填充它们数据和递送它们至DMODMO处理这些数据,并且Client从输出缓存中重新得到数据。

 

DMO体系架构

这部分描述DMO的整个体系架构

Streams(流)

 

一个DMO是一个有m个输入n个输出的对象。这些输入与输出被叫做流。每个DMO有至少一个流。流不是对象;它们是通过索引数简单地从DMO上被引用的。这个流的索引数在设计时期就被固定了。

 

Media Types(媒体类型)

 

所有数据都被指明使用一种媒体类型,它定义了如何说明数据的内容。举例,320 x 240 24-bit RGB的视频是一个类型,44.1-kilohertz(kHZ) 16-bit stereo PCM的音频是另外一种类型。媒体类型是被描述使用DMO_MEDIA_TYPE的结构。在Client能处理任何数据之前,它必须在DMO上为任何的流设置媒体类型。

 

Buffers(缓存)

 

在默认的DMO模型里,client分配各个输入缓存和输出缓存。它填充数据至输入缓存然后递送它们至DMO处,接着DMO写入新的数据至输出缓存中。

 

自由地,一个DMO能支持“in-place”处理。通过“in-place”处理,DMO将输出缓存直接写入到输入缓存中,跳过初始数据。“in-place”处理消除了为个各个缓存分配的缓存的需求。在另一方面,它改变了初始数据,这一点并不能被一些应用程序所接收。

 

默认缓存模型(non-in-place)被IMediaObjec接口所支持。所有的DMOs必须实现这个接口。如果一个DMO支持“in-place”处理,它也有IMediaObjectInPlace接口。则那个Client被要求分配所有缓存,包括输入与输出。

 

使用DMOs

This section describes how to use DMOs. It contains the following topics.

这部分描述如何使用DMOs。它包括如下主题:

直接使用DMO

DirectShow中使用DMOs

 

直接使用DMO

 

这部分描述一个应用程序怎样实现一个直接的DMOclient。应用程序递送输入至DMODMO创建输出,然后应用程序使用这个输出去绘制,更进一步处理或者其它处理。应用程序要负责一些问题,如内存分配,同步和线程问题。这些要求取决于应用程序的种类。

 

假如你正在写一个组件用于一个层在一个应用程序和一个DMO之间(举例,一个ActiveX控件使用一个DMO),这部分的信息同样适合你。更进一步讲,如果你正在写一个DMO,你应当阅读这部分内容,因为这部分内容描述了你的DMO必须实现的功能。

 

这部分内容包括如下主题:

 

设置DMOMedia Types(媒体类型)

DMO的数据处理

DMOIn-Place处理(In-Place processing

DMO的自由流处理(Optional Streams

IMediaBufferr的实现

 

设置DMOMedia Types(媒体类型)

 

DMO能处理数据之前,client必须为任何流设置media type(媒体类型)(有一个局部例外:查看Optional Streams(自由流))。为了寻找流的索引数,可以访问ImediaObject::GetStreamCount方法:

 

DWORD cInput = 0, cOutput = 0;

pDMO->GetStreamCount(&cInput, &cOutput);

 

这个方法返回两个值,输入的数与输出的数。这些值始终被固定在DMO中。

 

Preferred Types(优先选择类型)

 

对于每个流,DMO分配一个可能的媒体类型列表,按照优先选择的顺序。举个例子,preferred type可能是32-RGB24-bit RGB16-bitRGB的顺序。当client设置媒体类型时,它能使用这些序列作为提示。为流检索一个preferred type,访问IMediaObject::GetInputType方法或IMediaObject::GetOutputType方法。为一个类型(开始于0)指定流的数和一个索引值。举例,下面的代码从第一个输入流中检索第一个preferred type

 

DMO_MEDIA_TYPE mt

hr = pDMO->GetInputType(0, 0, &mt)

if (SUCCEEDED(hr))

{

    // Examine this media type (not shown).

    /* ... */

 

    // Free the format block.

    MoFreeMediaType(&mt);

}

 

从一个给定的流中枚举所有的preferred media types,可以使用一个循环通过增量类型索引直到方法返回DMO_E_NO_MORE_ITEMS,如下面的例子:

 

DMO_MEDIA_TYPE mt;

DWORD dwType = 0;

while (hr = pDMO->GetInputType(0, dwType, &mt), SUCCEEDED(hr))

{

    // Examine this media type (not shown).

    /* ... */

 

    // Free the format block.

    MoFreeMediaType(&mt);

    ++dwType;

}

 

你应当注意下面几个关于preferred types的注意点

 

DMO可以返回一个类型没有format块。举例,一个DMO可以指定一个video类型,例如24-bitRGB,没有提供图像的宽和高。当你设置一个类型的时候,你必须提供一个完整的format块(当然,有些媒体类型除外,比如MIDI,从不要求一个format块,由于这个并不适用)。

DMO并不被要求支持返回的每个联合的preferred types。举例,假如一个DMO有两个流,并且每个流有4preferred类型,有16个可能的联合,但是,它们并不是所有都确保是正确的。

client为一个流设置媒体类型时,DMO可能会为其它的流表示一个新的状态而更新preferred types。它并不要求这样做。而一些流,DMO可能不提供任何的preferred types。具有代表性地,一个DMO应当为一些流至少提供一些preferred types

DMO不被要求去提供一个它接受的完全的列表。有可能DMO支持“unadvertisedtypes,但是不当成preferred types来提供。

简而言之,client应当仅仅将preferred types视为指导方向。唯一能知道其中某种类型被支持的方法就是去测试它们,这个会在下个部分去描述。

 

为一个流设置媒体类型

 

使用IMediaObject::SetInputTypeIMediaObject::SetOutputType方法为任何一个流设置媒体类型。你必须提供一个包涵完整媒体类型的描述的DMO_MEDIA_TYPE结构。下面的例子使用44.1-kHz 16-bit stereo PCM audioinput stream 0上设置媒体类型。

 

DMO_MEDIA_TYPE mt;

ZeroMemory(&mt, sizeof(DMO_MEDIA_TYPE));

// Allocate memory for the format block.

HRESULT hr = MoInitMediaType(&mt, sizeof(WAVEFORMATEX));

if (SUCCEEDED(hr))

{

    // Set the type GUIDs.

    mt.majortype  = MEDIATYPE_Audio;

    mt.subtype    = MEDIASUBTYPE_PCM;

    mt.formattype = FORMAT_WaveFormatEx;

 

    // Initialize the format block.

    WAVEFORMATEX *pWave = reinterpret_cast<WAVEFORMATEX*>(mt.pbFormat);

    pWave->wFormatTag = WAVE_FORMAT_PCM;

    pWave->nChannels = 2;

    pWave->nSamplesPerSec = 44100;

    pWave->wBitsPerSample = 16;

    pWave->nBlockAlign = (pWave->nChannels * pWave->wBitsPerSample) / 8;

    pWave->nAvgBytesPerSec = pWave->nSamplesPerSec * pWave->nBlockAlign;

    pWave->cbSize = 0;

 

    // Set the media type.

    hr = pDMO->SetInputType(0, &mt, 0);

 

    // Release the format block.

    MoFreeMediaType(&mt);

}

 

对于一个还没有设置的媒体类型,需要测试它,使用DMO_SET_TYPE_TEST_ONLY标志访问SetInputType或者SetOutputType来测试这个类型是否被接受。如果这个类型被接受,这个方法返回S_OK,否则返回S_FALSE

 

if (S_OK == pDMO->SetInputType(0, &mt, DMO_SET_TYPEF_TEST_ONLY)

{

    // Media type is OK.

}

 

由于对一个流进行设置能影响到另一个流,你也许需要清空一个流的媒体类型。可以这样做,使用DMO_SET_TYPEF_CLEAR标志访问SetInputType或者SetOutputType来进行清空。

 

对于一个decoder DMOclient将首先设置input type,然后选择一个output type。而对于一个encoder DMOclient将首先设置output type,然后才是input type

 

DMO的数据处理

 

这部分解释了如何使用DMO去处理一个数据流。这部分列举了默认状态的步骤。所有DMOs必须支持的方法都在这里描述了。这些方法为输入和输出使用单独的缓存。一些DMOs同样支持in-place processing,使用一个简单的缓存。关于in-place的详细信息,请看In-Place Processing

分配缓存

 

client负责为所有的缓存进行分配。在你对DMO设置了媒体类型后,将要查询DMO为每个流的分配请求。这些能改变主要依靠媒体类型。对于每个流,可以访问IMediaObject::GetInputSizeInfo 或者 IMediaObject::GetOutputSizeInfo 方法。这些方法将返回下面的信息:

最小缓存大小,以字节形式

Alignment requirements, if any. A buffer is aligned if the start address is a multiple of some specified integer.

将适用于lookaheadDMO的最大数据统计数量。这上数字仅仅适用于输入流(input streams)。对于一些多样的数据(如,MPEG encoding),一个DMO也许需要为流的后期作出考虑。lookahead值指明了在它产生输出之前,DMO将需要多少输入数据。

client必须分配缓存来匹配这些需求。更进一步讲,DMO可能有关于client怎样打包输入数据需要。举例,DMO可能需要每个缓存包涵正确的一个例子(或者video frame)。为了确定这些需要,可以访问IMediaObject::GetInputStreamInfo方法。这个 IMediaObject::GetOutputStreamInfo方法返回相似的输出流信息。

在这个默认的流模型里,client不能传递原始缓存指针给DMO。代替的是,它使用一个轻量级的COM对象(可见的接口IMediaBuffer)。IMediaBuffer接口为一个内存块扮演了 COM wrapper功能。因为它是一个COM对象,它支持访问统计(reference counting),这将有利于确认缓存没有被释放而仍然在使用。

注意:IMediaBuffer接口提供的一个功能类似于DirectShow里的IMediaSample接口。

client必须实现IMediaBuffer对象。要查看详情,查看Implementing IMediaBuffer

 

数据处理

处理数据,要做以下几步:

1、  为每个输入流,填充一个输入数据缓存

2、  访问来IMediaObject::ProcessInput传递每个缓存

3、  访问IMediaObject::ProcessOutput来处理数据。这个方法带来一个缓存数组,都是输出流

4、  重复执行直到没有输入数据

ProcessInput方法每次接受一个流输入。这个方法立即返回,而且DMOIMediaBuffer对象上保持一个参考数。它处理完所有的缓存里的数据后,或者当DMO被应用程序flush的时候释放IMediaBuffer对象。不要再用DMO已经释放掉的一个缓存。为了确定一个输入流是否能接收更多数据,可以访问IMediaObject::GetInputStatus方法。如果那个流能接受更多输入,则这个方法返回DMO_INPUT_STATUSF_ACCEPT_DATA 标志。

ProcessOutput方法立即为所有的输出流生成输出。应用程序传送在DMO_OUTPUT_DATA_BUFFER结构数组里,任何一个输出流。(The application passes in an array of DMO_OUTPUT_DATA_BUFFER structures, one for each output stream.每个数据里的结构有一个指向IMediaBuffer对象的指针。DMO能向缓存中写入尽量多的数据。它同样设置了不同的标志去报告运行的状态。DMO_OUTPUT_DATA_BUFFERF_INCOMPLETE标志指明了DMO能从存在的输入中产生更多的输出。在那个状态下,client能再次访问ProcessOutput。否则,它应当访问ProcessInput来调用再多的输入数据。DMO从不修改那些在输入缓存中的数据。它仅仅将数据写入到输出缓存中。

在你已经将所有的数据递送至一个输入流中之后,访问IMediaObject::Discontinuity方法。在你没处理完剩余的输出(或者flush DMO)的时候,DMO不接受更多的输入到那个流。

At any point after streaming begins),DMO能够接收输入或产生输出或者两者都有。因此,不是GetInputStatus返回DMO_INPUT_STATUSF_ACCEPT_DATA,就是ProcessOutput返回DMO_OUTPUT_DATA_BUFFERF_INCOMPLETE。应用程序要保持数据通顺可以通过测试这些标志和访问ProcessInputProcessOutput的结果。为了中断数据流通,可访问IMediaObject::Flush方法。这个方法使得DMO丢弃任何DMO内部正保持的缓存。

 

 (未完待续)

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:54225次
    • 积分:661
    • 等级:
    • 排名:千里之外
    • 原创:9篇
    • 转载:16篇
    • 译文:1篇
    • 评论:3条
    最新评论
    程序员文章