QueryAccept (上游)

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

此机制使输入引脚能够建议对其上游对等方进行格式更改。 下游筛选器必须将上游筛选器在下一次调用 IMemAllocator::GetBuffer 时获取的媒体类型附加到示例。 但是,若要执行此操作,下游筛选器必须为连接提供自定义分配器。 此分配器必须实现下游筛选器可用于在下一个示例中设置媒体类型的私有方法。

将执行以下步骤:

  1. 下游筛选器检查引脚连接是否使用筛选器的自定义分配器。 如果上游筛选器拥有分配器,则下游筛选器无法更改格式。
  2. 下游筛选器在上游输出引脚上调用 IPin::QueryAccept, (请参阅图示,步骤 A) 。
  3. 如果 QueryAccept 返回S_OK,则下游筛选器对其分配器调用私有方法以设置媒体类型。 在此专用方法中,分配器对下一个可用示例调用 IMediaSample::SetMediaType (B) 。
  4. 上游筛选器调用 GetBuffer 来获取新的示例 (C) 和 IMediaSample::GetMediaType 以获取媒体类型 (D) 。
  5. 当上游筛选器提供样本时,它应保留附加到该样本的媒体类型。 这样,下游筛选器就可以确认媒体类型已 (E) 更改。

如果上游筛选器接受格式更改,则还必须能够切换回原始媒体类型,如下图所示。

queryaccept (上游)

此类格式更改main示例涉及 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);
    }
}