使用 DMO 类模板

[与此页面关联的功能 DirectShow 是一项旧功能。 它已被 MediaPlayerIMFMediaEngine媒体基金会中的音频/视频捕获取代。 这些功能已针对Windows 10和Windows 11进行了优化。 Microsoft 强烈建议新代码尽可能使用 MediaPlayerIMFMediaEngineMedia Foundation 中的音频/视频捕获 ,而不是 DirectShow。 如果可能,Microsoft 建议重写使用旧 API 的现有代码以使用新 API。]

DirectShow 包括用于实现 DMO 的类模板 IMediaObjectImpl。 该模板处理许多“簿记”任务,例如验证输入参数。 通过使用模板,可以专注于特定于 DMO 的功能。 此外,该模板还有助于确保创建可靠的实现。 模板在位于 SDK 的 Include 目录中的头文件 Dmoimpl.h 中定义。

IMediaObjectImpl 模板继承 IMediaObject 接口。 若要使用模板创建 DMO,请定义派生自 IMediaObjectImpl 的新类。 该模板实现所有 IMediaObject 方法。 在大多数情况下,模板对派生类调用相应的私有方法。 该模板提供以下功能:

  • 基本参数检查。 模板方法验证所需的参数是否不为 NULL、流索引是否在范围内以及标志是否有效。
  • 锁定。 模板方法调用两个内部方法 LockUnlock,以序列化 DMO 上的操作。 此功能可确保 DMO 是线程安全的。
  • 媒体类型。 该模板存储客户端设置的媒体类型,并为媒体类型提供访问器方法。
  • 流。 在客户端为所有非可选流设置媒体类型之前,模板会阻止流式处理。 它还可确保在流式处理开始之前调用 IMediaObject::AllocateStreamingResources 方法,这可以保证分配资源。

派生类必须实现 IUnknown 接口;模板不提供此接口。 可以使用活动模板库 (ATL) 来实现 IUnknown,也可以提供一些其他实现。 该模板也不实现锁定机制。 派生类必须实现 LockUnlock 方法。 如果使用 ATL 创建类,则可以使用默认 ATL 实现。

声明派生类

IMediaObjectImpl 类模板的声明如下:

template <class _DERIVED_, int NUMBEROFINPUTS, int NUMBEROFOUTPUTS>
class IMediaObjectImpl : public ImediaObject

三个模板参数是 _DERIVED_、NUMBEROFINPUTS 和 NUMBEROFOUTPUTS。 将 _DERIVED_ 设置为类的名称。 其他两个参数定义 DMO 上的输入流和输出流的数量。 例如,若要创建支持一个输入流和两个输出流的名为 CMyDmo 的 DMO 类,请使用以下声明:

class CMyDmo : public IMediaObjectImpl<CMyDmo, 1, 2>

本部分的其余部分介绍模板如何在 IMediaObject 中实现各种方法。

设置媒体类型的方法

以下方法在 DMO 上设置或检索媒体类型:

  • GetInputTypeGetOutputType。 这些方法按流号和类型索引返回首选媒体类型。 该模板对派生类调用 InternalGetInputTypeInternalGetOutputType
  • SetInputTypeSetOutputType。 这些方法设置流上的媒体类型、测试媒体类型或清除媒体类型。 为了验证媒体类型,模板对派生类调用 InternalCheckInputTypeInternalCheckOutputType 。 派生类返回接受类型的S_OK或DMO_E_INVALIDTYPE拒绝该类型。 模板处理媒体类型的设置或清除。
  • GetInputCurrentTypeGetOutputCurrentType。 这些方法返回流的当前媒体类型,如果未设置任何类型,则返回DMO_E_TYPE_NOT_SET。 模板完全实现了这些方法。

信息方法

以下方法提供有关 DMO 的信息。

  • GetInputMaxLatencySetInputMaxLatency。 这些方法检索或设置最大延迟。 该模板对派生类调用 InternalGetInputMaxLatencyInternalSetInputMaxLatency
  • GetInputSizeInfoGetOutputSizeInfo。 这些方法返回指定流的 DMO 缓冲区要求。 如果未在该流上设置媒体类型,则模板将返回DMO_E_TYPE_NOT_SET。 否则,它会对派生类调用 InternalGetInputSizeInfoInternalGetOutputSizeInfo
  • GetInputStreamInfoGetOutputStreamInfo。 这些方法返回指示客户端应如何设置数据格式的各种标志。 该模板对派生类调用 InternalGetInputStreamInfoInternalGetOutputStreamInfo
  • GetStreamCount。 此方法返回输入和输出流的数目。 模板使用模板参数实现此方法。

资源分配的方法

  • AllocateStreamingResources 方法在流式处理开始之前分配 DMO 所需的任何资源。 FreeStreamingResources 方法释放相同的资源。 该模板分别调用 InternalAllocateStreamingResourcesInternalFreeStreamingResources

DMO 的客户端不需要调用这些方法,但模板在流式处理开始之前会自动调用 AllocateStreamingResources 。 因此,DMO 可以假定在调用 ProcessInput 时已正确分配资源。 DMO 应在其析构函数中调用 FreeStreamingResources

此外,当模板调用 InternalAllocateStreamingResources 时,它会设置内部标志,以便在调用 InternalFreeStreamingResources 之前不会再次调用该方法。 这可确保不会意外地重新分配资源,这可能会导致内存泄漏。

流式处理方法

以下方法用于流式传输数据:

  • GetInputStatus。 此方法指示 DMO 此时是否可以接受输入。 该模板对派生类调用 InternalAcceptingInput 。 如果 DMO 可以接受输入,则派生类返回S_OK并且模板在 dwFlags 参数中设置DMO_INPUT_STATUSF_ACCEPT_DATA位。 否则,派生类将返回S_FALSE并且模板将 dwFlags 设置为零。
  • ProcessInput。 此方法处理输入缓冲区。 该模板调用前面所述的 AllocateStreamingResources。 然后,它对派生类调用 InternalAcceptingInput 。 如果 DMO 可以接受新输入,则模板将调用 InternalProcessInput
  • ProcessOutput。 此方法处理一组输出缓冲区,每个输出流对应一个缓冲区。 该模板依次调用 AllocateStreamingResourcesInternalProcessOutput
  • 中断。 此方法指示输入流中的不连续。 该模板对派生类调用 InternalAcceptingInput 。 如果该方法返回S_OK,则模板对派生类调用 InternalDiscontinuity
  • 刷新。 此方法刷新 DMO。 模板对派生类调用 InternalFlush 。 DMO 应放弃仍保留待处理的任何输入缓冲区。

该模板不提供对 IMediaObjectInPlace 接口的任何直接支持。

锁定方法

锁定用于在多线程环境中保护 DMO 的状态。 在 ATL 项目中, IMediaObject::Lock 方法会导致名称与 ATL Lock 方法冲突。 为了解决冲突,模板将 IMediaObject 方法重命名为 DMOLock。 编译派生类时,请在包含头文件 Dmo.h 之前定义FIX_LOCK_NAME:

#define FIX_LOCK_NAME
#include <dmo.h>

此指令导致预处理器在 IMediaObject 接口的声明中将 DMOLock 替换为 Lock。 应用程序仍然可以使用名称 Lock 调用方法,因为 vtable 顺序不会更改。 DMOLock 方法对派生类调用 LockUnlock。 如果使用 ATL 实现派生类,则这些方法已由 ATL 定义,因此无需其他代码。 如果不使用 ATL,则必须在派生类中提供 LockUnlock 方法。

模板会自动锁定每个 IMediaObject 方法中的 DMO。 例如,如果派生类支持 IMediaObjectInPlace) ,则派生类可能需要将 DMO 锁定在 (实现的其他公共方法中。 类模板还提供内部帮助程序类 IMediaObjectImpl::LockIt,这对于锁定和解锁 DMO 非常有用。

摘要

对于以下 IMediaObject 方法,该模板在派生类上调用具有相同签名的相应方法。 派生类必须实现第二列中显示的每个方法。

IMediaObject 方法 派生类方法
AllocateStreamingResources InternalAllocateStreamingResources
间断 InternalDiscontinuity
刷新 InternalFlush
FreeStreamingResources InternalFreeStreamingResources
GetInputMaxLatency InternalGetInputMaxLatency
GetInputSizeInfo InternalGetInputSizeInfo
GetInputStreamInfo InternalGetInputStreamInfo
GetInputType InternalGetInputType
GetOutputSizeInfo InternalGetOutputSizeInfo
GetOutputStreamInfo InternalGetOutputStreamInfo
GetOutputType InternalGetOutputType
ProcessInput InternalProcessInput
ProcessOutput InternalProcessOutput
SetInputMaxLatency InternalSetInputMaxLatency

 

对于剩余的 IMediaObject 方法,模板方法与派生类方法之间没有一对一的对应关系。 下表汇总了模板完全实现的方法,以及哪些方法调用派生类上的其他方法。

IMediaObject 方法 派生类方法
GetInputCurrentType 完全实现
GetOutputCurrentType 完全实现
GetStreamCount 完全实现
GetInputStatus InternalAcceptingInput
锁定 (实现为 DMOLock) 锁定解锁
SetInputType InternalCheckInputType
SetOutputType InternalCheckOutputType

 

IMediaObjectImpl 类模板

编写 DMO