使用 DMO 类模板
[与此页面关联的功能 DirectShow 是一项旧功能。 它已被 MediaPlayer、 IMFMediaEngine 和 媒体基金会中的音频/视频捕获取代。 这些功能已针对Windows 10和Windows 11进行了优化。 Microsoft 强烈建议新代码尽可能使用 MediaPlayer、 IMFMediaEngine 和 Media Foundation 中的音频/视频捕获 ,而不是 DirectShow。 如果可能,Microsoft 建议重写使用旧 API 的现有代码以使用新 API。]
DirectShow 包括用于实现 DMO 的类模板 IMediaObjectImpl。 该模板处理许多“簿记”任务,例如验证输入参数。 通过使用模板,可以专注于特定于 DMO 的功能。 此外,该模板还有助于确保创建可靠的实现。 模板在位于 SDK 的 Include 目录中的头文件 Dmoimpl.h 中定义。
IMediaObjectImpl 模板继承 IMediaObject 接口。 若要使用模板创建 DMO,请定义派生自 IMediaObjectImpl 的新类。 该模板实现所有 IMediaObject 方法。 在大多数情况下,模板对派生类调用相应的私有方法。 该模板提供以下功能:
- 基本参数检查。 模板方法验证所需的参数是否不为 NULL、流索引是否在范围内以及标志是否有效。
- 锁定。 模板方法调用两个内部方法 Lock 和 Unlock,以序列化 DMO 上的操作。 此功能可确保 DMO 是线程安全的。
- 媒体类型。 该模板存储客户端设置的媒体类型,并为媒体类型提供访问器方法。
- 流。 在客户端为所有非可选流设置媒体类型之前,模板会阻止流式处理。 它还可确保在流式处理开始之前调用 IMediaObject::AllocateStreamingResources 方法,这可以保证分配资源。
派生类必须实现 IUnknown 接口;模板不提供此接口。 可以使用活动模板库 (ATL) 来实现 IUnknown,也可以提供一些其他实现。 该模板也不实现锁定机制。 派生类必须实现 Lock 和 Unlock 方法。 如果使用 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 上设置或检索媒体类型:
- GetInputType、 GetOutputType。 这些方法按流号和类型索引返回首选媒体类型。 该模板对派生类调用 InternalGetInputType 或 InternalGetOutputType 。
- SetInputType、 SetOutputType。 这些方法设置流上的媒体类型、测试媒体类型或清除媒体类型。 为了验证媒体类型,模板对派生类调用 InternalCheckInputType 或 InternalCheckOutputType 。 派生类返回接受类型的S_OK或DMO_E_INVALIDTYPE拒绝该类型。 模板处理媒体类型的设置或清除。
- GetInputCurrentType、 GetOutputCurrentType。 这些方法返回流的当前媒体类型,如果未设置任何类型,则返回DMO_E_TYPE_NOT_SET。 模板完全实现了这些方法。
信息方法
以下方法提供有关 DMO 的信息。
- GetInputMaxLatency、 SetInputMaxLatency。 这些方法检索或设置最大延迟。 该模板对派生类调用 InternalGetInputMaxLatency 或 InternalSetInputMaxLatency 。
- GetInputSizeInfo、 GetOutputSizeInfo。 这些方法返回指定流的 DMO 缓冲区要求。 如果未在该流上设置媒体类型,则模板将返回DMO_E_TYPE_NOT_SET。 否则,它会对派生类调用 InternalGetInputSizeInfo 或 InternalGetOutputSizeInfo 。
- GetInputStreamInfo、 GetOutputStreamInfo。 这些方法返回指示客户端应如何设置数据格式的各种标志。 该模板对派生类调用 InternalGetInputStreamInfo 或 InternalGetOutputStreamInfo 。
- GetStreamCount。 此方法返回输入和输出流的数目。 模板使用模板参数实现此方法。
资源分配的方法
- AllocateStreamingResources 方法在流式处理开始之前分配 DMO 所需的任何资源。 FreeStreamingResources 方法释放相同的资源。 该模板分别调用 InternalAllocateStreamingResources 和 InternalFreeStreamingResources。
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。 此方法处理一组输出缓冲区,每个输出流对应一个缓冲区。 该模板依次调用 AllocateStreamingResources 和 InternalProcessOutput。
- 中断。 此方法指示输入流中的不连续。 该模板对派生类调用 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 方法对派生类调用 Lock 或 Unlock。 如果使用 ATL 实现派生类,则这些方法已由 ATL 定义,因此无需其他代码。 如果不使用 ATL,则必须在派生类中提供 Lock 和 Unlock 方法。
模板会自动锁定每个 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 |
相关主题