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

  • Post author:
  • Post category:其他


原文请查看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

也是输入数据到创建输出数据。而且,

DMOs



APIs

比相应的

DirectShow



APIs

要简单的多。因此,

DMOs

是比较容易被创建,测试和使用。

DMOs

可以被用于很多方面:









基于

DirectShow

的应用程序通过一个

DirectShow filter

叫作

DMO Wrapper filter

来使用

DMOs

。而

filters



DMOs

的区别是,

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








3







DMOs



始终是同步数据处理,这样就消除了你写一个



filter



需要考虑的多线程问题(译者注:



filter



有独立的数据传送线程,需要考虑多线程编程问题)




4



、与传统的



ACM







VCM codecs



不同的是,



DMOs



是基于组件模型(



COM



)的,因此,它们通过



QueryInterface



(接口)的方式进行扩充。




5







DMOs



支持一个比



ACM



或者



VCM codecs




更大众化的流模型







a more generalized streaming model



)。如同



DirectShow filters







DMOs



能支持多输入和多输出。



由于这些原因,



DMOs



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







DMOs







DirectShow Filters



有什么不同?




DirectShow filters



运行离不开



DirectShow filter graph



。在



DirectShow



内,



Filter Graph Manager



用于应用程序和



filters



之间的调配。



DirectShow filters



要做很多数据流需求的工作,包括:



包括分配缓存。



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



filters







将数据通过



filter graph







发送事件给



Filter Graph Manager







多线程的同步。



相对比的是,一个



DMO



不需要做上面的这些事情。代替的是,这些任务被要求给使用



DMO







Client



去完成。



Client



负责分配缓存,填充它们数据和递送它们至



DMO







DMO



处理这些数据,并且



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








这部分描述一个应用程序怎样实现一个直接的



DMO







client



。应用程序递送输入至



DMO







DMO



创建输出,然后应用程序使用这个输出去绘制,更进一步处理或者其它处理。应用程序要负责一些问题,如内存分配,同步和线程问题。这些要求取决于应用程序的种类。






假如你正在写一个组件用于一个层在一个应用程序和一个



DMO



之间(举例,一个



ActiveX



控件使用一个



DMO



),这部分的信息同样适合你。更进一步讲,如果你正在写一个



DMO



,你应当阅读这部分内容,因为这部分内容描述了你的



DMO



必须实现的功能。







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









设置



DMO







Media Types



(媒体类型)




DMO



的数据处理




DMO







In-Place



处理(



In-Place processing








DMO



的自由流处理(



Optional Streams








IMediaBufferr



的实现







设置



DMO









Media 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-RGB







24-bit RGB







16-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



有两个流,并且每个流有



4







preferred



类型,有



16



个可能的联合,但是,它们并不是所有都确保是正确的。







client



为一个流设置媒体类型时,



DMO



可能会为其它的流表示一个新的状态而更新



preferred types



。它并不要求这样做。而一些流,



DMO



可能不提供任何的



preferred types



。具有代表性地,一个



DMO



应当为一些流至少提供一些



preferred types








DMO



不被要求去提供一个它接受的完全的列表。有可能



DMO



支持“



unadvertised







types



,但是不当成



preferred types



来提供。



简而言之,



client



应当仅仅将



preferred types



视为指导方向。唯一能知道其中某种类型被支持的方法就是去测试它们,这个会在下个部分去描述。






为一个流设置媒体类型






使用



IMediaObject::SetInputType







IMediaObject::SetOutputType



方法为任何一个流设置媒体类型。你必须提供一个包涵完整媒体类型的描述的



DMO_MEDIA_TYPE



结构。下面的例子使用



44.1-kHz 16-bit stereo PCM audio







input 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 DMO







client



将首先设置



input type



,然后选择一个



output type



。而对于一个



encoder DMO







client



将首先设置



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.







将适用于





lookahead









DMO



的最大数据统计数量。这上数字仅仅适用于输入流



(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



方法每次接受一个流输入。这个方法立即返回,而且



DMO







IMediaBuffer



对象上保持一个参考数。它处理完所有的缓存里的数据后,或者当



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



。应用程序要保持数据通顺可以通过测试这些标志和访问



ProcessInput







ProcessOutput



的结果。为了中断数据流通,可访问






IMediaObject::Flush






方法。这个方法使得



DMO



丢弃任何



DMO



内部正保持的缓存。




(未完待续)