[與此頁面相關聯的功能,DirectShow是舊版功能。 它已被 MediaPlayer、imfMediaEngine 取代,並在媒體基金會 音訊/視訊擷取。 這些功能已針對 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 方法的原始程式碼。不過,拒絕格式變更可能會降低效能,因為它會防止視訊轉譯器使用最有效率的格式。
下列虛擬程式代碼示範如何實作可在 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);
}
}