Share via


QueryAccept (上游)

[與此頁面 相關的功能 DirectShow是舊版功能。 它已被 MediaPlayerIMFMediaEngineMedia Foundation 中的音訊/視訊擷取取代。 這些功能已針對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 方法的原始程式碼。) 拒絕格式變更可能會降低效能,因為它會防止視訊轉譯器使用最有效率的格式。

下列虛擬程式碼示範如何實作衍生自 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);
    }
}