本文主要是介绍DirectX Media Objects,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
DirectX Media Objects
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对象。要查看详情,查看ImplementingIMediaBuffer。
数据处理
处理数据,要做以下几步:
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内部正保持的缓存。
而对于DMO的直接使用,以下几点是要特别注意的。
1. 在处理数据之前,必须为每条输入输出stream设置media type(Optional stream除外);
2. 从DMO从获取的media type未必包含format块,但是在给DMO设置media type时,务必带上这部分信息(MIDI除外);
3. 应用程序必须自己负责分配数据缓存。缓存的大小可以通过调用DMO的IMediaObject::GetInputSizeInfo或IMediaObject::GetOutputSizeInfo得到。DMO使用的数据缓存也是一个COM对象,支持ImediaBuffer接口,与DirectShow filter的Media Sample类似。
4. 一般的DMO依次调用IMediaObject::ProcessInput和IMediaObject::ProcessOutput处理数据,In-Place的DMO调用IMediaObjectInPlace::Process处理数据。两套方法不能混用。
5. 在调用ProcessOutput时,如果返回的标记是DMO_OUTPUT_DATA_BUFFERF_INCOMPLETE,说明数据的数据还没有完全取出,需要再次调用ProcessOutput。
6. 所有输入数据都已输入完成,应该调用DMO的IMediaObject::Discontinuity方法。
7. 如果你想中断数据处理流程,调用DMO的IMediaObject::Flush。
8. 区别两种不同的可丢弃stream,标记分别为DMO_OUTPUT_STREAMF_OPTIONAL和DMO_OUTPUT_STREAMF_DISCARDABLE。注意,后者是要设置media type的。
这篇关于DirectX Media Objects的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!