directx的媒体对象

微软的directx媒体对象简称DMOs,是一种写流数据的新方法。由于某些原因,DMOs非常象微软的directshow过滤器。DMO处理数据是利用输入数据来产生输出数据的。DMO比部件API函数更加类似directshow。因此,DMO非常容易创建、测试和使用。
DMO完全兼容directshow,但应用程序可以在没有directshow的情况下使用DMO。在directshow的应用程序里,DMO被directshow过滤器封装,称为DMO封装过滤器。过滤器和DMO的区别就在于对于应用程序的透明度,也就是哪个是不需要使用DMO的API,即应用程序可以不用directshow而直接使用DMO。因此写一个DMO,将创建一个在应用程序中可以被广泛使用的部件。 DMO和directshow过滤器的区别 Directshow过滤器仅仅工作在directshow过滤图像中。在图像中,过滤图像管理器在应用程序和过滤器之间作为一种媒介。DMO则没有这种要求,一个应用程序可以单独的使用DMO。 在directshow中,过滤器将为流数据作大量的工作。包括: · 分配缓冲。 · 裁决媒体类型和连接到其它的过滤器 · 通过滤波图形压栈数据 · 将事件发送给过滤图形管理器 · 同步多线程 相对照,一个DMO不作上述的任何事情。而是由客户使用这些DMO类型。客户给它们分配缓冲并进行数据填充。然后将缓冲传给DMO,DMO将处理它们。客户获得输出缓冲。 在DirectShow中,DMO封装过滤器是DMO的一个客户,因此可以处理所有这些任务,而其它应用程序能过提供自己的应用实例。 DMOs有以下先进特性: · 有较少的函数支持,因此通常较directshow过滤器小且简单。 · 因为不要求过滤图形因此比directshow要更加灵活。当需要directshow提供的服务时,便可以使用它,例如图形的同步、智能连接、自动处理流数据和线程管理。如果不需要这些服务,可以直接访问DMO。 · DMOs常常可以处理同步的数据,这样会避免过滤器开发者所必须考虑的很多线程的问题。 · 不象acm和vcm解码,DMO是基于组件对象模型的,因此可以通过QueryInterface接口进行扩展。 · DMOs比acm和vcm解码支持更多的无规律的流模式。像directshow过滤器,DMOs还支持多输入和多输出。 由于以上原因,应该尽可能的使用DMO而不是directshow。然而也由一些情况是DMO不适合的。例如: · 异常传输要求。DMO封装过滤器使用ImemInputPin传输。如果需要在directshow应用程序中用到别的传输机制,那么就必须重新写一个过滤器。 · 建立动态图形。如果应用程序执行了动态图形创建,或许需要写一个自己的过滤器。例如需要控制分配程序的创建。 DMO测试程序 Directx8.0 SDK包括了一个测试DMO的程序。名字叫:DMOtest。这个测试程序可以帮助检验DMO。这个程序安装在SDK的bin\DXUtils目录中。如果要进行DMO开发,那么DMO测试程序将是测试的一部分。 为了使用DMOtest,必须为DMO产生一个测试数据。为此SDK包含了一个 DMOdump.dll中的directshow过滤器,需要用regsvr32进行这个过滤器的注册。 使用DMO媒体对象 这一节描述了怎样在应用程序中使用DMO对象。这里只讲述直接访问DMOs的方法。在directshow中使用DMO的方法,将在下面的章节讲解。 本节包含以下部分。 · 流和缓冲 · 数据流 · 怎样处理数据 · 可丢弃和可选择的流 · 内部处理的DMOs 流和缓冲 一个DMO拥有m个输入产生n个输出的对象。输入和输出都叫做流。每一个DMO至少有一个流。一个DMO可以没有输入流或者没有输出流,但典型的DMO是包括输入和输出流的。 注意:流不是明晰的COM对象。它们是DMO对象自身的引用,是从基于0开始的索引。 一个DMO是通过输入流来获得数据。它首先处理数据然后通过输出流产生输出。 所有数据类型都使用一个媒体类型(media type)。媒体类型定义了怎样识别数据的内容。例如,320×240 的24位 rgb视频是一种类型;44.1千赫兹16位立体的pcm音频是另外一种类型。用DMO_MEDIA_TYPE结构描述媒体类型。 一个DMO中的每个流都可以接收某个范围的媒体类型。利用DMO,既可接收任意大位的视频流,也可只支持16位的视频。一个DMO可以被限制到特定关系的输入和输出。例如,如果一个输入流被设定到16位视频,可能相应的输出会要求同样的位。应用程序可以枚举每一个流首选的媒体类型和测试指定的输入输出关联。 例如: · 一个创建avi数据的DMO可以有两个输入流,一个是视频,一个是音频。它却可能产生一个输交叉存取音频视频的数据流。 · 一个多色调 分色印的rgb图像可能有24位的rgb的视频输入和8位的rgb视频输出。 应用程序提交的输入数据在内存块中被划分。每个内存块被一个叫缓冲区的COM对象封装,这个缓冲区必须支持ImediaBuffer接口。这个接口包含了设置缓冲数据长度,接收数据指针,接收缓冲分配的尺寸的方法。应用程序可以用这种方法来分配所有的缓冲区,这个针对输入和输出两者都适用。 数据流 这一节讲述了怎样在应用程序和DMO中进行数据的移动。应用程序交替的进行交付输入缓冲和请求输出两种动作。处理输入缓冲可以调用DMO中的ImediaObject::ProcessInput方法。处理输出缓冲可以调用ImediaObject::ProcessOutput方法。 有两种方法可以停止输入数据流。 · 中断方式:当一个应用程序输入数据完结,或者数据中有中断,那么应用程序会用信号通知终止。中断通知DMO后将不会再有输入,与此同时,DMO可以仍然进行数据处理,因此应用程序应该请求输出,直到DMO通知没有剩余数据时才可以真正结束。 · 冲洗 方式:应用程序可以用冲洗方式中断数据流。如果DMO有数据在缓冲中,那么数据将被立即释放。 流的开始是在应用程序第一次调用IMediaObject::ProcessInput。但是DMO会直到应用程序为每个流都设置了媒体类型之后才会开始流的运作。(非强制性的流除外)当应用程序以冲洗方式通知DMO,或者以中断方式通知每个流数据然后处理了所有的输出之后,流数据才会被停止。这些行为将会使DMO返回到非流状态。DMO将会保留所有的媒体类型设置,但将会释放掉所有的ImediaBuffer指针。以后不会在有任何的输出,直到应用程序再次调用ProcessInput。 处理流数据将执行以下步骤。 1.            查询DMO来获得流的数量和每一个流首选的媒体类型。 2.            为所有的流设置媒体类型。 3.            分配输入缓冲和输出缓冲。 4.            调用ProcessInput填充输入缓冲区。 5.            调用ProcessOutput接收输出数据。重复4和5,直到所有的输入数据被处理。 6.            发一个中断信号然后将剩余的输出处理完毕。 可以用冲洗数据的办法来中断步骤4到6。 怎样处理数据 这一节将更详细的解释前面列出的步骤。 步骤1 查询DMO 首先,查询DMO来获得流的数量和每一个流首选的媒体类型。为了得到输入流和输出流的数量,可以调用IMediaObject::GetStreamCount方法。对于每一个流来讲,DMO会将按照首选媒体类型的优先级的顺序来排列,然后为每一个类型分配索引,索引是从0开始的。为了得到一个首选的媒体类型的细节,可以调用IMediaObject::GetInputType 方法来处理输入,输出可以调用IMediaObject::GetOutputType方法。为了枚举一个流中所有的媒体类型,可以使用循环递增媒体类型的索引直到方法返回DMO_E_NO_MORE_ITEMS,下面是演示代码。   DWORD cInputs, cOutputs, type = 0
DMO_MEDIA_TYPE mt
 
pDMO->GetStreamCount(&cInputs, &cOutputs)
 
for (DWORD i = 0; i < cInputs; i++)
{
    while (pDMO->GetInputType(i, type, &mt) != DMO_E_NO_MORE_ITEMS)
    {
        if ( this media type is one you want )
            break
        MoFreeMediaType(&mt)
        type++
    }
}
GetInputType和GetOutputType方法返回一个DMO_MEDIA_TYPE结构。下面就是相应的结构成员。 · 主类型:被指定流媒体类型的GUID。主类型是一般的分类,象视频和音频一样。 · 子类型:一个指定流子类型的GUID。子类型是更细的分类。如MEDIASUBTYPE_RGB24 2特指24位rgb视频。 · pbFormat:一个指向结构里描述格式的指针。格式结构指定的信息比如是视频的宽高,或者一个音频速率等等。不同的媒体类型使用不同的格式。大部分视频数据使用VIDEOINFOHEADER结构。音频数据使用WAVEFORMATEX结构。 · formattype:指定了包含了pbFormat的格式结构。 媒体类型可能有一个NULL的格式结构,表示formattype是GUID_NULL的值。一个NULL的格式预示DMO可以接受指定媒体类型内部一定范围的格式。 例如,一个流要求PCM音频和其相近的采样率范围的格式。因此它将会返回MEDIATYPE_Audio作为主类型,NULL格式的MEDIASUBTYPE_PCMAudio子类型。应用程序必须调用MoFreeMediaType函数来释放pbFormat。 步骤2 设置媒体类型 在找到DMO的主媒体类型之后,设置每个流的媒体类型可以调用ImediaObject::SetInputType和IMediaObject::SetOutputType方法。 DMO不能保证每个被报告的媒体类型组合都是有效的。就象输出类型可能需要匹配输入类型。你可以测试一个媒体类型,用DMO_SET_TYPEF_TEST_ONLY标志来调用 SetInputType或者SetOutputType。对于解码器,你通常应该设定输入类型然后在选择一个输出类型。对于编码器,你应该设定输出类型然后选择一个输入类型。 因为设定一个流将会影响到别的流,因此你需要将以前设定的媒体类型清除。这个功能可以调用SetInputType或者SetOutputType,参数填充DMO_SET_TYPEF_CLEAR标志。 步骤3 分配缓冲 在设置媒体类型之后,每个缓冲请求查询DMO。这些可以依靠媒体类型来改变。对于每个流来讲,可以调用MediaObject::GetInputSizeInfo 或者IMediaObject::GetOutputSizeInfo方法。这些方法返回三个值: · 最小缓冲尺寸,以字节为单位 · 如果一个缓冲是被对齐的,如果起始地址是一些指定整数的倍数,这些情况下对齐方式是被要求的。 · 对于一些输入缓冲,最大数据的数量被DMO控制。要求输入的数据是缓冲的倍数 必须分配足够的缓冲来处理这些请求。为了符合尺寸要求,一个输入流可以要求每个缓冲包含唯一的完整的采样,或者包含精确的一个采样,或者使用一个固定的采样尺寸。为了实现这些要求,可以调用IMediaObject::GetInputStreamInfo方法。 步骤4 处理输入 现在可以交付一个输入缓冲给DMO。对于每一个输入流,用媒体数据填充一个或者多个输入缓冲。可以直接的向缓冲写数据,或者从另外一个DMO上使用一个输出缓冲。调用ProcessInput方法来交付每一个缓冲。当应用程序冲洗DMO的时候,缓冲可以被释放,但千万不要在DMO释放之前重复使用缓冲。 为了决定一个流是否可以接收更多的数据,可以调用IMediaObject::GetInputStatus方法。如果流可以接受更多的数据,那么此方法将会返回DMO_INPUT_STATUSF_ACCEPT_DATA标志。 步骤5 处理输出 鉴于ProcessInput一次交付一个出入缓冲,因此ProcessOutput通常一次输出所有的流数据。应用程序传递一个DMO_OUTPUT_DATA_BUFFER矩阵,这个结构用于每个输出流。这个结构包含了一个指向输出缓冲的指针和被填充的不同信息。 在ProcessOutput方法中,DMO会产生尽可能多的数据(被给定的输出缓冲大小)。如果在处理所有的数据前填充了输出缓冲,它将会在dwStatus结构中设定DMO_OUTPUT_DATA_BUFFERF_INCOMPLETE标志。当方法返回时,将会检查每个结构的这个标志。如果标志是存在,则重新调用ProcessOutput。 在流开始之后,DMO可以一直接收数据,或者产生输出数据,或者两者同时产生。因此不是GetInputStatus返回DMO_INPUT_STATUSF_ACCEPT_DATA标志,就是ProcessOutput返回DMO_OUTPUT_DATA_BUFFERF_INCOMPLETE标志。应用程序保持数据流就是通过测试这些标志和调用ProcessInput或者ProcessOutput。 步骤 6 发出中断信号 当交付所有的有效输入数据后,调用IMediaObject::Discontinuity方法进行结束。 可丢弃和可选择的(非强制性的)流 一个DMO可以指定一些输出流作为可丢弃的或者是可选择的: · 一个可丢弃的流包括应用程序可以丢弃的数据,完整的或者间断的采样。 · 一个可选择的流是一个不是所有应用程序都需要的次要的流,或者是包括主流附加信息的流。 要了查询一个流是否为可丢弃或者是可选的,可以调用IMediaObject::GetOutputStreamInfo方法和检测pdwFlags参数。DMO_OUTPUT_STREAMF_DISCARDABLE标志表明了流是具有可丢弃的特点。DMO_OUTPUT_STREAMF_OPTIONAL标志则表示流具有可选择的特点。通常至少有一个流是不可选择的。当调用IMediaObject::ProcessOutput方法时,可以从一个或者多个流中通过在dwFlags参数中设定DMO_PROCESS_OUTPUT_DISCARD_WHEN_NO_BUFFER标志来丢弃数据。对于每个想丢弃的流来说,都要设置DMO_OUTPUT_DATA_BUFFER结构的pBuffer为空。 如果pBuffer是NUL,但又没有设置DMO_PROCESS_OUTPUT_DISCARD_WHEN_NO_BUFFER标志,那么DMO将不会丢弃数据,就算流是可丢弃的或者是可选择的都无济于事。万一pBuffer是NULL但没有数据被丢弃,那么DMO将会发一个DMO_OUTPUT_DATA_BUFFERF_INCOMPLETE标志来表明这个流仍然有数据的。如果有输出流没有处理,但又不丢弃它,DMO将不能在别的输出流中产生数据。 如果从不使用可选择的流,那么就没有必要设置它的媒体类型了。同样的情况不适合可丢弃的流。必须在一个可丢弃的流中设置媒体类型。 in-place 媒体对象 某些数据转换可直接由修改数据来acCOMplished,这既是所谓的in-place 处理。许多音频和视频效果可在适当位置进行处理。In-place 处理比直接把数据复制到另一缓冲有效。为了处理in-place数据, 可单独调用IMediaObjectInPlace::Process 方法, 而不是分开调用ProcessInput 和ProcessOutput。传递一个包含输入数据的字节数组。当方法返回时,字节数组包含输出数据。 支持IMediaObjectInPlace 的必须支持所有MediaObject 方法。可以选择使用in-place 处理或创建独立的输入、输出缓冲。注意不要混淆两种类型的处理。如果调用 Process, 就不要调用 ProcessInput 或 ProcessOutput,反之亦然。 在输入停止后,in-place DMO 可创建一些附加输出,即所谓尾效果(effect tail)。例如,混响效果在输入“安静”后仍持续工作。DMO 产生尾效果,程序必须用零输入缓冲调用Process 方法直到尾 被COMpletely 处理。

你可能感兴趣的:(对象)