QueryAccept (上游)
[與此頁面 相關的功能 DirectShow是舊版功能。 它已被 MediaPlayer、 IMFMediaEngine和 Media Foundation 中的音訊/視訊擷取取代。 這些功能已針對Windows 10和Windows 11進行優化。 Microsoft 強烈建議新程式碼盡可能使用 MediaPlayer、 IMFMediaEngine 和 音訊/視訊擷取 ,而不是 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);
}
}