使用擷取圖形產生器建置圖形
[與此頁面相關的功能 DirectShow是舊版功能。 它已被 MediaPlayer、 IMFMediaEngine和 Media Foundation 中的音訊/視訊擷取取代。 這些功能已針對Windows 10和Windows 11進行優化。 Microsoft 強烈建議新程式碼盡可能使用 MediaPlayer、 IMFMediaEngine 和 音訊/視訊擷取 ,而不是 DirectShow。 Microsoft 建議使用舊版 API 的現有程式碼盡可能重寫為使用新的 API。
雖然擷取圖形產生器的名稱很適合用來建置許多類型的自訂篩選圖形,而不只是擷取圖表。 本文提供如何使用這個物件的簡短概觀。
擷取圖形產生器會公開 ICaptureGraphBuilder2 介面。 首先,呼叫 CoCreateInstance 以建立擷取圖形產生器和篩選圖形管理員。 然後使用篩選圖形管理員的指標呼叫 ICaptureGraphBuilder2::SetFiltergraph ,以初始化擷取圖形產生器,如下所示:
IGraphBuilder *pGraph = NULL;
ICaptureGraphBuilder2 *pBuilder = NULL;
// Create the Filter Graph Manager.
HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL,
CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&pGraph);
if (SUCCEEDED(hr))
{
// Create the Capture Graph Builder.
hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL,
CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2,
(void **)&pBuilder);
if (SUCCEEDED(hr))
{
pBuilder->SetFiltergraph(pGraph);
}
};
連接篩選
ICaptureGraphBuilder2::RenderStream方法會將鏈結中的兩個或三個篩選連接在一起。 一般而言,當每個篩選準則沒有一個以上的輸入針腳或相同類型的輸出針腳時,此方法最適合使用。 此討論從忽略 RenderStream 的前兩個參數開始,並將焦點放在最後三個參數。 第三個參數是 IUnknown 指標,可將篩選 (指定為 IBaseFilter 介面指標) 或輸出針腳 (做為 IPin 介面指標) 。 第四個和第五個參數會指定 IBaseFilter 指標。 RenderStream方法會連接鏈結中的所有三個篩選。 例如,假設 A、 B和 C 是篩選準則。 假設每個篩選準則都只有一個輸入針腳和一個輸出針腳。 下列呼叫會將 A 連接到 B,然後將 B 連接到 C:
- 'RenderStream (Null、Null、A、B、C) '
所有連線都是「智慧型」,這表示會視需要將其他篩選新增至圖表。 如需詳細資訊,請參閱 Intelligent Connect。 若要只連接兩個篩選準則,請將中間值設定為 Null。 例如,此呼叫會將 A 連接到 C:
- 'RenderStream (Null、Null、A、Null、C) '
您可以呼叫 方法兩次來建立較長的鏈結:
- 'RenderStream (Null、Null、A、B、C) ' 'RenderStream (Null、Null、C、D、E) '
如果最後一個參數是 Null,此方法會自動找出預設轉譯器。 它會針對視訊使用 影片轉譯器 ,而 DirectSound 轉譯器 則用於音訊。 因此:
- 'RenderStream (Null、Null、A、Null、Null) '
相當於
- 'RenderStream (Null、Null、A、Null、R) '
其中 R 是適當的轉譯器。 不過,若要連接影片混合轉譯器篩選,而不是影片轉譯器,您必須明確指定它。
如果您在第三個參數中指定篩選,而不是釘選,您可能需要指出應該用於連線的輸出針腳。 這是方法的前兩個參數的目的。 第一個參數僅適用于擷取篩選。 它會指定 GUID,指出針腳類別。 如需類別的完整清單,請參閱 Pin 屬性集。 其中兩個類別適用于所有擷取篩選:
- PIN_CATEGORY_CAPTURE
- PIN_CATEGORY_PREVIEW
如果擷取篩選未提供擷取和預覽的個別針腳, RenderStream 方法會插入 Smart Tee 篩選,將資料流程分割成擷取資料流程和預覽資料流程。 從應用程式的觀點來看,您可以直接將所有擷取篩選視為具有個別的針腳,並忽略圖形的基礎拓撲。
針對檔案擷取,將擷取釘選連接到多工篩選器。 針對即時預覽,將預覽釘選連接到轉譯器。 如果您切換兩個類別,圖形可能會在檔案擷取期間卸載過多的畫面格;但是如果圖表已正確連線,它會視需要卸載預覽畫面,以維護擷取資料流程上的輸送量。
下列範例示範如何連接這兩個數據流:
// Capture to file:
pBuilder->RenderStream(&PIN_CATEGORY_CAPTURE, NULL, pCapFilter, NULL, pMux);
// Preview:
pBuilder->RenderStream(&PIN_CATEGORY_PREVIEW, NULL, pCapFilter, NULL, NULL);
某些擷取篩選也支援隱藏式輔助字幕,以 PIN_CATEGORY_VBI表示。 若要擷取檔案的隱藏式輔助字幕,請將此類別轉譯為多工篩選器。 若要在預覽視窗中檢視隱藏式輔助字幕,請連線到轉譯器:
// Capture to file:
pBuilder->RenderStream(&PIN_CATEGORY_VBI, NULL, pCapFilter, NULL, pMux);
// Preview on screen:
pBuilder->RenderStream(&PIN_CATEGORY_VBI, NULL, pCapFilter, NULL, NULL);
RenderStream的第二個參數會識別媒體類型,而且通常是下列其中一項:
- MEDIATYPE_Audio
- MEDIATYPE_Video
- MEDIATYPE_Interleaved (DV)
每當篩選的輸出針腳支援慣用媒體類型的列舉時,就可以使用此參數。 針對檔案來源,擷取圖形產生器會視需要自動新增剖析器篩選,然後查詢剖析器上的媒體類型。 (如需範例,請參閱 重新壓縮 AVI File.) 此外,如果鏈結中的最後一個篩選有數個輸入針腳,此方法會嘗試列舉其媒體類型。 不過,並非所有篩選都支援這項功能。
尋找篩選和釘選上的介面
建置圖形之後,您通常需要找出圖形中篩選和釘選所公開的各種介面。 例如,擷取篩選可能會公開 IAMDroppedFrames 介面,而篩選的輸出針腳可能會公開 IAMStreamConfig 介面。
尋找介面最簡單的方式是使用 ICaptureGraphBuilder2::FindInterface 方法。 這個方法會逐步引導圖形 (篩選和釘選) 直到找到所需的介面為止。 您可以指定搜尋的起點,並限制搜尋從起點篩選上游或下游。
下列範例會在影片預覽釘選上搜尋 IAMStreamConfig 介面:
IAMStreamConfig *pConfig = NULL;
HRESULT hr = pBuild->FindInterface(
&PIN_CATEGORY_PREVIEW,
&MEDIATYPE_Video,
pVCap,
IID_IAMStreamConfig,
(void**)&pConfig
);
if (SUCCESSFUL(hr))
{
/* ... */
pConfig->Release();
}
注意
[ 尋找篩選或釘選上的介面 ] 主題會顯示使用 IGraphBuilder 介面而非 ICaptureGraphBuilder2的替代方法。 使用的方法取決於您的應用程式。 如果您的應用程式已經使用 ICaptureGraphBuilder2 來建置圖形, 則 ICaptureGraphBuilder2::FindInterface 是很好的方法。 否則,請考慮使用 IGraphBuilder 方法。
尋找針腳
較不常見,您可能需要在篩選上找出個別的針腳,不過在大部分情況下, RenderStream 和 FindInterface 方法會節省您的問題。 如果您需要在篩選上尋找特定的針腳, ICaptureGraphBuilder2::FindPin 協助程式方法很有用。 指定類別、媒體類型 (視訊或音訊) 、方向,以及針腳是否必須未連線。
例如,下列程式碼會在擷取篩選上搜尋未連線的影片預覽釘選:
IPin *pPin = NULL;
hr = pBuild->FindPin(
pCap, // Pointer to the filter to search.
PINDIR_OUTPUT, // Search for an output pin.
&PIN_CATEGORY_PREVIEW, // Search for a preview pin.
&MEDIATYPE_Video, // Search for a video pin.
TRUE, // The pin must be unconnected.
0, // Return the first matching pin (index 0).
&pPin); // This variable receives the IPin pointer.
if (SUCCESSFUL(hr))
{
/* ... */
pPin->Release();
}
相關主題