解码器如何使用 IAMVideoAccelerator
[与此页面关联的功能 DirectShow 是旧版功能。 它已被 MediaPlayer、 IMFMediaEngine 和 Media Foundation 中的音频/视频捕获所取代。 这些功能已针对Windows 10和Windows 11进行了优化。 Microsoft 强烈建议新代码尽可能在 Media Foundation 中使用 MediaPlayer、 IMFMediaEngine 和 音频/视频捕获 ,而不是 DirectShow。 如果可能,Microsoft 建议重写使用旧 API 的现有代码以使用新 API。]
IAMVideoAccelerator 接口支持常规视频加速操作,包括 DirectX 视频加速 (VA) 。 对于非 DirectX VA 加速,解码器和视频驱动程序必须都遵循通用协议。
本部分介绍使用此接口时,任何解码器应遵循的一般操作顺序。 有关基于 DirectX VA 的解码器的详细信息,请参阅 将 DirectX 视频加速映射到 IAMVideoAccelerator。
注意
此接口在 Windows 2000 及更高版本中可用。
IAMVideoAccelerator 接口在覆盖混音器或视频混合呈现器 (VMR) 的输入引脚上公开。 IAMVideoAcceleratorNotify 接口在解码器的输出引脚上公开。 连接筛选器引脚的事件序列如下所示:
Filter Graph 管理器在解码器筛选器的输出引脚上调用 IPin::Connect 。 AM_MEDIA_TYPE是可选参数。
- AM_MEDIA_TYPE 是描述一种媒体类型的数据结构。 它包含主要类型 GUID (在本例中应MEDIATYPE_Video) 、子类型 GUID (在本例中应是视频加速器 GUID) 以及其他各种内容。 其中之一是包含媒体相关信息的格式类型 GUID,包括未压缩视频图片的宽度和高度,最有可能在 MPEG1VIDEOINFO、 VIDEOINFOHEADER、 MPEG2VIDEOINFO 或 VIDEOINFOHEADER2 结构中 。
- AM_MEDIA_TYPE结构(如果存在)指示解码器使用指定的媒体类型(可以是“完全指定”或“部分指定”)进行操作。 如果“完全指定”,解码器通常只是尝试使用该媒体类型进行操作。 如果“部分指定”,它将尝试查找“完全指定”兼容的操作模式,可以使用该模式以与“部分指定”媒体类型一致的方式进行连接。
- 尝试查找用于连接的“完全指定”媒体类型的常规方式是,只需运行输出引脚支持的与“部分指定”媒体类型兼容的每个“完全指定”媒体类型的列表,并尝试与每个媒体类型连接,直到成功。 如果 IPin::Connect 调用中不包含任何AM_MEDIA_TYPE,但输出引脚需要检查其所有媒体类型,则此过程通常类似。
如果解码器想要检查下游输入引脚是否支持特定AM_MEDIA_TYPE (包括视频加速器 GUID) ,则可以调用该引脚的 IPin::QueryAccept (,并将视频加速器 GUID 用作AM_MEDIA_TYPE) 的子类型,也可以直接尝试连接到该引脚,如以下第 5 项所述。
如果解码器不知道下游输入引脚支持哪些视频加速器 GUID,并且不希望通过调用下游输入引脚的 IPin::QueryAccept 来仅建议某个特定的候选视频加速器 GUID,则解码器可以调用 IAMVideoAccelerator::GetVideoAcceleratorGUID 以获取该引脚支持的视频加速器 GUID 的列表。
对于某些特定的视频加速器 GUID,解码器可以调用下游输入引脚的 IAMVideoAccelerator::GetUncompFormatsSupported 以获取可用于呈现特定视频加速器 GUID 的 DDPIXELFORMAT 像素格式的列表。 应将返回的列表视为按优先顺序递减 (,即首先列出首选格式) 。
解码器调用下游输入引脚的 IPin::ReceiveConnection,向其传递 一个AM_MEDIA_TYPE ,其中正确的视频加速器 GUID 作为媒体类型的子类型。 这会为操作设置连接,包括创建未压缩的输出图面 (使用 在 AM_MEDIA_TYPE 中找到的宽度和高度进行分配,以及通过下述调用找到的要分配的图面数,以及视频加速器具有和希望用于该目的的任何其他信息,例如视频加速器 GUID 本身) 。 如果下游输入引脚拒绝视频加速器 GUID 或连接的其他某个方面,这可能会导致 IPin::ReceiveConnection 失败。 如果 IPin::ReceiveConnection 失败,则会在返回的 HRESULT 中指示这一点,解码器可以尝试再次进行调用,例如,在 AM_MEDIA_TYPE 结构中使用新的视频加速器 GUID。
[!注意]
这是解码器确定下游输入引脚支持内容的另一种 (方式,也是) 的最明确方法,只需调用 IPin::ReceiveConnection 并尝试连接,然后检查连接尝试是否成功。
在 IPin::ReceiveConnection 期间,呈现器调用解码器的 IAMVideoAcceleratorNotify::GetUncompSurfacesInfo,向其传递视频加速器 GUID 和 AMVAUncompBufferInfo 结构,以确定要分配的未压缩图面数。 解码器填充并返回结构,该结构包含要分配的特定类型的最小和最大图面数,以及描述要分配的图面的像素格式的 DDPIXELFORMAT 结构。
[!注意]
在调用 IAMVideoAcceleratorNotify::GetUncompSurfacesInfo 时,除了视频加速器 GUID 之外,实际上不会向解码器传递任何内容。
呈现器调用解码器的 IAMVideoAcceleratorNotify::SetUncompSurfacesInfo,将分配的实际未压缩表面数传递给解码器。
呈现器调用解码器的 IAMVideoAcceleratorNotify::GetCreateVideoAcceleratorData ,以获取初始化视频加速器所需的任何数据。
解码器调用 IAMVideoAccelerator::GetCompBufferInfo,向其传递视频加速器 GUID、 AMVAUncompDataInfo 结构和压缩缓冲区类型的数量,以获取返回一组 AMVACompBufferInfo 数据结构,其中一个结构对应于视频加速器 GUID 所使用的每种类型的压缩数据缓冲区。
- AMVAUncompDataInfo 结构包含解码的未压缩数据 (的宽度和高度(以像素) )和未压缩图片的 DDPIXELFORMAT。
- 每个返回的 AMVACompBufferInfo 数据结构都包含:
特定类型所需的压缩缓冲区数。
要创建的图面的宽度和高度 (字段,这些字段可能具有或可能没有任何实际含义) 。
注意
压缩缓冲区的 DirectDraw surface 分配操作当前未规定这些图面的宽度或高度大于或等于 2^15,但如果违反此限制,表面分配调用可能不会明显失败。 因此,驱动程序可以构造对压缩缓冲区内存的请求,以避免这种极端大小。 例如,驱动程序应请求 width=“1”和 height=“65536”的缓冲区,而不是请求 width=“1024”和 height=“64”的缓冲区。
图面要使用的字节总数。
类型为 DDSCAPS2 的结构,用于定义 DirectDrawSurface 对象,描述创建用于存储压缩数据的图面的功能。
DDPIXELFORMAT,描述用于创建表面以将压缩数据存储 (字段的像素格式) 。
注意
呈现器对某些解码器的 IAMVideoAcceleratorNotify 接口方法的调用可能会 (,通常) 在解码器对呈现器的 IPin::ReceiveConnection 的调用内发生。 具体而言,这适用于以下情况:
注意
为了支持动态格式更改,解码器还可以在筛选器连接并运行时调用 IPin::ReceiveConnection 和上述其他方法。 提供此功能是为了支持动态格式更改, (尽管不在 H.263 附件 P 中, 意义 - 因为所有数据集都是从头开始重新启动的,因此任何参考图片信息) 丢失。
下面是初始化后操作期间 IAMVideoAccelerator 使用的说明:
对于每个未压缩的图面,解码器调用 IAMVideoAccelerator::BeginFrame 以开始处理以创建输出图片。 执行此操作时,解码器会发送 AMVABeginFrameInfo 结构。
AMVABeginFrameInfo 结构包含目标缓冲区的索引、指向要向下游发送的某些数据的指针,以及一个指向加速器可以放置一些数据供解码器读取的位置的指针。
注意 1:加速器实际上不会接收目标缓冲区索引,因为它在进入下游之前由呈现器转换。
注意 2: IAMVideoAccelerator::BeginFrame 可以在调用 IAMVideoAccelerator::EndFrame 之间多次调用。
注意 3:接口操作中没有假设需要调用 IAMVideoAccelerator::BeginFrame 和 IAMVideoAccelerator::EndFrame 来处理位流中每个单独的图片。
就接口而言, IAMVideoAccelerator::BeginFrame 的作用是在索引和未压缩图面之间的呈现器中创建关联。 它还提供了一种在设备驱动程序 (中调用特定函数的方法,支持在解码器和设备驱动程序) 之间来回传递任意数据。
(但是,在 DirectX VA 操作中,需要调用 IAMVideoAccelerator::BeginFrame 和 IAMVideoAccelerator::EndFrame 来处理 bitstream 中每张图片的要求。)
若要将未压缩的数据发送到加速器,解码器会调用:
- IAMVideoAccelerator::QueryRenderStatus ,用于确定缓冲区是否适合从中读取或写入。
- IAMVideoAccelerator::GetBuffer 可锁定并获取对指定缓冲区 (的访问权限(如果之前未调用它来获取该访问) )。 GetBuffer 还可用于获取调用 IAMVideoAccelerator::BeginFrame 的最后一张未压缩输出图片的内容的副本,前提是尚未为该目标缓冲区索引调用 IAMVideoAccelerator::EndFrame 。 如果 DDI 返回所请求缓冲区的呈现状态DDERR_WASSTILLDRAWING,则会在 GetBuffer 中运行睡眠循环,直到清除此条件。 为了调用 GetBuffer,解码器需要从 AMVACompBufferInfo 数据结构获取一些信息,该结构是通过调用 IAMVideoAccelerator::GetCompBufferInfo 获取的。
- IAMVideoAccelerator::Execute 指示应处理 AMVABUFFERINFO 数据结构数组中一组压缩缓冲区中的数据。 在此调用中,将函数代码 dwFunction 传递给驱动程序。 lpPrivateInputData 指针也会传递到某些数据以向下游发送,lpPrivateOutputData 指针将传递到下游进程可以放置一些数据供解码器读取的位置。
- IAMVideoAccelerator::ReleaseBuffer 指示解码器目前已完成指定缓冲区的使用,不再需要锁定访问缓冲区。 (如果解码器希望继续使用缓冲区, 它暂时不能调用 IAMVideoAccelerator::ReleaseBuffer,因此无需调用 IAMVideoAccelerator::GetBuffer,直到它真正打算不再使用缓冲区。) 在 QueryRenderStatus 指示缓冲区可以安全写入之前,在调用 Execute 之后,解码器不应写入缓冲区。
若要完成目标缓冲区的输出处理,解码器调用 IAMVideoAccelerator::EndFrame。 它可以通过此调用向下游传递一些任意数据,这基本上就是此调用所导致的一切。 它不会在此调用中发送目标缓冲区索引,因此它无法向加速器准确指示已完成的目标缓冲区,除非此指示包含在传递的任意数据中。
为了显示帧,解码器调用 IAMVideoAccelerator::D isplayFrame,其中包含要显示的帧的索引,以及包含开始和停止时间戳和相关标志(如 AM_SAMPLE2_PROPERTIES 结构中的 dwTypeSpecificFlags)和 VIDEOINFOHEADER2 结构中的 dwInterlaceFlags 的 IMediaSample 结构。 解码器必须在调用 DisplayFrame 之前验证影响帧内容的所有解压缩操作是否已完成。
最后,解码器应在完成所有处理后,通过调用 IAMVideoAccelerator::EndFrame 来指示完成所有剩余的开始输出帧,并通过为每个未发布的缓冲区调用 IAMVideoAccelerator::ReleaseBuffer 释放其所有锁定的缓冲区。
相关主题