[与此页面关联的功能(DirectShow)是一项旧功能。 它已被 MediaPlayer、IMFMediaEngine取代,并在媒体基金会 音频/视频捕获。 这些功能已针对 Windows 10 和 Windows 11 进行了优化。 Microsoft强烈建议新代码尽可能使用 MediaPlayer、IMFMediaEngine 和 Media Foundation 中的音频/视频捕获,而不是 DirectShow。 Microsoft建议重写使用旧 API 的现有代码,以尽可能使用新 API。]
此机制使输入引脚能够建议对其上游对等方进行格式更改。 下游筛选器必须将媒体类型附加到上游筛选器在下一次调用 IMemAllocator::GetBuffer时获取的示例。 但是,若要执行此作,下游筛选器必须为连接提供自定义分配器。 此分配器必须实现下游筛选器可用于在下一个示例中设置媒体类型的专用方法。
执行以下步骤:
- 下游筛选器检查引脚连接是否使用筛选器的自定义分配器。 如果上游筛选器拥有分配器,则下游筛选器无法更改格式。
- 下游筛选器在上游输出引脚上调用 IPin::QueryAccept(请参阅图示,步骤 A)。
- 如果
QueryAccept
返回S_OK,下游筛选器对其分配器调用专用方法,以便设置媒体类型。 在此专用方法中,分配器会在下一个可用示例(B)上调用 IMediaSample::SetMediaType。 - 上游筛选器调用 GetBuffer 以获取新的示例(C)和 IMediaSample::GetMediaType 以获取媒体类型(D)。
- 当上游筛选器传送样本时,它应保留附加到该样本的媒体类型。 这样,下游筛选器就可以确认媒体类型已更改(E)。
如果上游筛选器接受格式更改,它还必须能够切换回原始媒体类型,如下图所示。
此类格式更改的主要示例涉及 DirectShow 视频呈现器。
- 原始 视频呈现器 筛选器可以在流式处理期间在 RGB 和 YUV 类型之间进行切换。 筛选器连接时,它需要与当前显示设置匹配的 RGB 格式。 这可以保证,如果需要,它可以回退到 GDI 上。 流式处理开始后,如果 DirectDraw 可用,视频呈现器会请求对 YUV 类型进行格式更改。 稍后,如果由于任何原因丢失 DirectDraw 图面,它可能会切换回 RGB。
- 较新的视频混合呈现器(VMR)筛选器将连接到图形硬件支持的任何格式,包括 YUV 类型。 但是,图形硬件可能会更改基础 DirectDraw 图面的步幅,以优化性能。 VMR 筛选器使用
QueryAccept
来报告新步幅,该步幅在 BITMAPINFOHEADER 结构的 biWidth 成员中指定。 VIDEOINFOHEADER 中的源和目标矩形 或 VIDEOINFOHEADER2 结构中标识应解码视频的区域。
实现说明
不太可能编写需要请求上游格式更改的筛选器,因为这主要是视频呈现器的一项功能。 但是,如果编写视频转换筛选器或视频解码器,筛选器必须正确响应来自视频呈现器的请求。
位于视频呈现器和解码器之间的跨位置筛选器应传递上游的所有 QueryAccept
调用。 在到达时存储新格式信息。
复制转换筛选器(即非就地筛选器)应实现以下行为之一:
- 传递格式更改上游,并在到达时存储新的格式信息。 筛选器必须使用自定义分配器,以便它可以将格式附加到上游示例。
- 在筛选器中执行格式转换。 这可能比传递上游格式更改容易。 但是,它可能比让解码器筛选器解码为正确的格式要低。
- 作为最后手段,只需拒绝格式更改。 (有关详细信息,请参阅 DirectShow 基类库中 CTransInPlaceOutputPin::CheckMediaType 方法的源代码。但是,拒绝格式更改可能会降低性能,因为它会阻止视频呈现器使用最有效的格式。
以下伪代码演示如何实现复制转换筛选器(派生自 CTransformFilter),该筛选器可在 YUV 和 RGB 输出类型之间进行切换。 此示例假定筛选器本身执行转换,而不是传递上游格式更改。
HRESULT CMyTransform::CheckInputType(const CMediaType *pmt)
{
if (pmt is a YUV type that you support) {
return S_OK;
}
else {
return VFW_E_TYPE_NOT_ACCEPTED;
}
}
HRESULT CMyTransform::CheckTransform(
const CMediaType *mtIn, const CMediaType *mtOut)
{
if (mtOut is a YUV or RGB type that you support)
{
if ((mtIn has the same video dimensions as mtOut) &&
(you support the mtIn-to-mtOut transform))
{
return S_OK;
}
}
// otherwise
return VFW_E_TYPE_NOT_ACCEPTED;
}
// GetMediaType: Return a preferred output type.
HRESULT CMyTransform::GetMediaType(int iPosition, CMediaType *pMediaType)
{
if (iPosition < 0) {
return E_INVALIDARG;
}
switch (iPosition)
{
case 0:
Copy the input type (YUV) to pMediaType
return S_OK;
case 1:
Construct an RGB type that matches the input type.
return S_OK;
default:
return VFW_S_NO_MORE_ITEMS;
}
}
// SetMediaType: Override from CTransformFilter.
HRESULT CMyTransform::SetMediaType(
PIN_DIRECTION direction, const CMediaType *pmt)
{
// Capture this information...
if (direction == PINDIR_OUTPUT)
{
m_bYuv = (pmt->subtype == MEDIASUBTYPE_UYVY);
}
return S_OK;
}
HRESULT CMyTransform::Transform(
IMediaSample *pSource, IMediaSample *pDest)
{
// Look for format changes from downstream.
CMediaType *pMT = NULL;
HRESULT hr = pDest->GetMediaType((AM_MEDIA_TYPE**)&pMT);
if (hr == S_OK)
{
hr = m_pOutput->CheckMediaType(pMT);
if(FAILED(hr))
{
DeleteMediaType(pMT);
return E_FAIL;
}
// Notify our own output pin about the new type.
m_pOutput->SetMediaType(pMT);
DeleteMediaType(pMT);
}
// Process the buffers
if (m_bYuv) {
return ProcessFrameYUV(pSource, pDest);
}
else {
return ProcessFrameRGB(pSource, pDest);
}
}