共用方式為


QueryAccept (上游)

[與此頁面相關聯的功能,DirectShow是舊版功能。 它已被 MediaPlayer、imfMediaEngine 取代,並在媒體基金會 音訊/視訊擷取。 這些功能已針對 Windows 10 和 Windows 11 進行優化。 Microsoft強烈建議新程式代碼盡可能在媒體 基礎中使用 MediaPlayerIMFMediaEngine 音訊/視訊擷取,而不是 DirectShow。 Microsoft建議使用舊版 API 的現有程式代碼,盡可能改寫成使用新的 API。]

此機制可讓輸入針腳向其上游對等專案提出格式變更。 下游篩選條件必須將媒體類型附加至上游篩選會在下一次呼叫 IMemAllocator::GetBuffer時取得的範例。 不過,若要這樣做,下游篩選必須提供連線的自定義配置器。 這個配置器必須實作私用方法,下游篩選條件可用來在下一個範例上設定媒體類型。

下列步驟會發生:

  1. 下游篩選會檢查針腳連接是否使用篩選的自定義配置器。 如果上游篩選擁有配置器,下游篩選就無法變更格式。
  2. 下游篩選會呼叫上游輸出釘選 IPin::QueryAccept (請參閱圖例,步驟 A)。
  3. 如果 QueryAccept 傳回S_OK,下游篩選會在其配置器上呼叫私用方法,以設定媒體類型。 在此私用方法中,配置器會在下一個可用的範例 (B) 上呼叫 IMediaSample::SetMediaType
  4. 上游篩選會呼叫 GetBuffer,以取得新的範例 (C) 和 IMediaSample::GetMediaType 以取得媒體類型 (D)。
  5. 當上游篩選傳遞範例時,它應該讓媒體類型附加至該範例。 如此一來,下游篩選可以確認媒體類型已變更 (E)。

如果上游篩選條件接受格式變更,它也必須能夠切換回原始媒體類型,如下圖所示。

queryaccept (上游)

這種格式變更的主要範例涉及 DirectShow 影片轉譯器。

  • 原始 視訊轉譯器 篩選可以在串流期間切換 RGB 和 YUV 類型。 當篩選連線時,它需要符合目前顯示設定的 RGB 格式。 這可確保如果需要的話,它可以回復 GDI。 串流開始之後,如果有 DirectDraw 可用,影片轉譯器會要求將格式變更為 YUV 類型。 稍後,如果它因為任何原因而失去 DirectDraw 表面,它可能會切換回 RGB。
  • 較新的影片混合轉譯器 (VMR) 篩選器會連線到圖形硬體支援的任何格式,包括 YUV 類型。 不過,圖形硬體可能會變更基礎 DirectDraw 介面的步幅,以將效能優化。 VMR 篩選器會使用 QueryAccept 來報告新的步幅,這會在 BITMAPINFOHEADER 結構的 biWidth 成員中指定。 VIDEOINFOHEADER 中的來源和目標矩形VIDEOINFOHEADER2 結構會識別應譯碼視訊的區域。

實作注意事項

您不太可能撰寫需要要求上游格式變更的篩選,因為這主要是視訊轉譯器的功能。 不過,如果您撰寫視訊轉換篩選或視訊譯碼器,您的篩選必須正確回應來自視訊轉譯器的要求。

位於視訊轉譯器和譯碼器之間的跨位置篩選,應該傳遞上游的所有 QueryAccept 呼叫。 在到達時儲存新的格式資訊。

複製轉換篩選條件(也就是非就地篩選條件)應該實作下列其中一種行為:

  • 傳遞格式會變更上游,並在到達時儲存新的格式資訊。 您的篩選必須使用自定義配置器,才能將格式附加至上游範例。
  • 在篩選內執行格式轉換。 這可能比傳遞上游格式變更更容易。 不過,它可能比讓譯碼器篩選譯碼成正確的格式要低。
  • 作為最後手段,只要拒絕格式變更即可。 (如需詳細資訊,請參閱 DirectShow 基類連結庫中 CTransInPlaceOutputPin::CheckMediaType 方法的原始程式碼。不過,拒絕格式變更可能會降低效能,因為它會防止視訊轉譯器使用最有效率的格式。

下列虛擬程式代碼示範如何實作可在 YUV 和 RGB 輸出類型之間切換的複製轉換篩選器(衍生自 CTransformFilter)。 此範例假設篩選條件本身會執行轉換,而不是傳遞格式變更上游。

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);
    }
}