修改現(xiàn)有filter
如果需要修改現(xiàn)有filter,可以停止該圖,進(jìn)行更改,然后重新啟動(dòng)該圖。 這通常是最佳方法。 但是,在某些情況下,你可能希望在圖形仍在運(yùn)行時(shí)對(duì)其進(jìn)行更改。 例如:
- 應(yīng)用程序在播放期間插入視頻效果
filter。 - 源
filter將媒體類型切換為中流,可能需要新的解壓縮filter。 - 應(yīng)用程序?qū)⑿碌囊曨l流添加到圖形。
這些都是 動(dòng)態(tài)圖形生成的示例,該術(shù)語(yǔ)涵蓋在圖形繼續(xù)運(yùn)行時(shí)對(duì)filter Graph所做的任何類型的更改。 動(dòng)態(tài)圖形生成可以由應(yīng)用程序或圖形中的filter啟動(dòng)。 可以采用三種不同的方案: - 動(dòng)態(tài)格式更改:
filter可以在中游更改格式,而無(wú)需刪除或替換任何filter。 - 動(dòng)態(tài)重新連接:通過(guò)添加或刪除
filter來(lái)更改圖形。 -
filter鏈:添加、刪除和控制filter鏈。
動(dòng)態(tài)重新連接
在大多數(shù) DirectShow filter中,當(dāng)圖形主動(dòng)流式傳輸數(shù)據(jù)時(shí),無(wú)法重新連接pin。 應(yīng)用程序必須在重新連接pin之前停止圖形。 但是,某些filter在圖形運(yùn)行時(shí)支持pin重新連接,此過(guò)程稱為動(dòng)態(tài)重新連接。 這可以通過(guò)應(yīng)用程序或圖形中的filter來(lái)完成。
例如,請(qǐng)考慮下圖中的圖。

動(dòng)態(tài)重新連接的一種方案可能是在圖形正在運(yùn)行時(shí)從圖形中刪除filter 2,并將其替換為另一個(gè)filter。 若要使此方案正常工作,必須滿足以下條件:
-
filter3 (pinD) 上的輸入pin必須支持 IPinConnection 接口。 此接口允許在不停止filter的情況下重新連接pin。 -
filter1 上的輸出pin(pinA) 必須能夠在重新連接發(fā)生時(shí)阻止媒體數(shù)據(jù)流。 在重新連接期間,任何數(shù)據(jù)都不能在pinA 和pinD 之間傳輸。 通常,這意味著輸出pin必須支持 IPinFlowControl 接口。 但是,如果filter1 是啟動(dòng)重新連接的filter,則它可能有一些內(nèi)部機(jī)制來(lái)阻止其自己的數(shù)據(jù)流。
動(dòng)態(tài)重新連接將涉及以下步驟:
- 阻止來(lái)自
pinA 的數(shù)據(jù)流。 - 重新連接
pinA 到pinD,可能通過(guò)新的中間filter。 - 取消阻止固定 A,以便數(shù)據(jù)再次開始流動(dòng)。
阻止數(shù)據(jù)流
若要阻止數(shù)據(jù)流,請(qǐng)?jiān)?code>pin A 上調(diào)用 IPinFlowControl::Block ??梢援惒交蛲秸{(diào)用此方法。 若要 異步調(diào)用 方法,請(qǐng)創(chuàng)建 Win32 事件對(duì)象并將事件句柄傳遞給 Block 方法。 方法將立即返回。 使用 WaitForSingleObject 等函數(shù)等待事件發(fā)出信號(hào)。 pin在事件阻止數(shù)據(jù)流時(shí)發(fā)出信號(hào)。 例如:
// Create an event
HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (hEvent != NULL)
{
// Block the data flow.
hr = pFlowControl->Block(AM_PIN_FLOW_CONTROL_BLOCK, hEvent);
if (SUCCEEDED(hr))
{
// Wait for the pin to finish.
DWORD dwRes = WaitForSingleObject(hEvent, dwMilliseconds);
}
}
若要 同步調(diào)用 方法,只需傳遞值 NULL 而不是事件句柄。 現(xiàn)在, 方法將阻止,直到操作完成。 在pin準(zhǔn)備好提供新示例之前,可能不會(huì)發(fā)生這種情況。 如果filter已暫停,則可能需要任意時(shí)間長(zhǎng)度。 因此,不要從main應(yīng)用程序線程進(jìn)行同步調(diào)用。 使用工作線程,或者異步調(diào)用 方法。
重新連接pin
若要重新連接pin,請(qǐng)查詢 IGraphConfig 接口的 Filter Graph 管理器,并調(diào)用 IGraphConfig::Reconnect 或 IGraphConfig::Reconfigure。 重新連接方法更易于使用;它執(zhí)行以下操作:
停止示例) 中 (filter 2 的中間filter,并將其從圖中刪除。
根據(jù)需要添加新的中間filter。
連接所有pin。
暫?;蜻\(yùn)行任何新filter,以匹配圖形的狀態(tài)。
重新連接方法有多個(gè)可選參數(shù),可用于指定pin連接的媒體類型和要使用的中間filter。 例如:
pGraph->AddFilter(pNewFilter, L"New Filter for the Graph");
pConfig->Reconnect(
pPinA, // Reconnect this output pin...
pPinD, // ... to this input pin.
pMediaType, // Use this media type.
pNewFilter, // Connect them through this filter.
NULL,
0);
有關(guān)詳細(xì)信息,請(qǐng)參閱參考頁(yè)。 如果 重新連接 方法不夠靈活,可以使用 Reconfigure 方法,該方法調(diào)用應(yīng)用程序定義的回調(diào)方法來(lái)重新連接pin。 若要使用此方法,請(qǐng)?jiān)趹?yīng)用程序中實(shí)現(xiàn) IGraphConfigCallback 接口。
在調(diào)用 重新配置之前,請(qǐng)阻止來(lái)自輸出pin的數(shù)據(jù)流,如前所述。 然后推送正在重新連接的關(guān)系圖部分仍處于掛起狀態(tài)的任何數(shù)據(jù),如下所示:
在示例) 中,在重新連接鏈中最遠(yuǎn)下游的輸入pin上調(diào)用 IPinConnection::NotifyEndOfStream (pin D。 將句柄傳遞到 Win32 事件。
在從阻止數(shù)據(jù)流的輸出pin直接下游的輸入pin上調(diào)用 IPin::EndOfStream 。 (在此示例中,數(shù)據(jù)流在pin A 處被阻止,因此可以在pin B.)
等待事件發(fā)出信號(hào)。 輸入pin (pin D) 接收流結(jié)束通知時(shí)向事件發(fā)出信號(hào)。 這表示沒有數(shù)據(jù)在pin之間傳輸,并且調(diào)用方可以安全地重新連接pin。
請(qǐng)注意, IGraphConfig::重新連接 方法會(huì)自動(dòng)處理前面的步驟。 僅當(dāng)使用 Reconfigure 方法時(shí),才需要執(zhí)行這些步驟。
通過(guò)圖形推送數(shù)據(jù)后,調(diào)用 重新配置 并將指針傳遞到 IGraphConfigCallback 回調(diào)接口。 Filter Graph 管理器將調(diào)用你提供的 IGraphConfigCallback::Reconfigure 方法。
取消阻止數(shù)據(jù)流
重新連接pin后,請(qǐng)為第一個(gè)參數(shù)調(diào)用值為零的 IPinFlowControl::Block 來(lái)取消阻止數(shù)據(jù)流。
備注
如果動(dòng)態(tài)重新連接由filter執(zhí)行,則必須注意一些線程問(wèn)題。 如果 Filter Graph 管理器嘗試停止filter,它可能會(huì)死鎖,因?yàn)閳D形等待filter停止,同時(shí)filter可能正在等待數(shù)據(jù)通過(guò)圖形推送。 為了防止可能出現(xiàn)的死鎖,本部分所述的某些方法會(huì)處理 Win32 事件。 如果 Filter Graph 管理器嘗試停止filter,filter應(yīng)發(fā)出事件信號(hào)。 有關(guān)詳細(xì)信息,請(qǐng)參閱 IGraphConfig 和 IPinConnection。
filter鏈
filter鏈?zhǔn)菨M足以下條件的filter序列:
- 鏈中的每個(gè)
filter最多有一個(gè)連接的輸入pin和一個(gè)連接的輸出pin。 - 無(wú)需遍歷鏈外部的
filter即可遍歷鏈中的每個(gè)filter。
例如,在下圖中,filter A–B、C-D 和 F–G-H 是filter鏈。 F-G-H (F-G 和 G-H) 中的每個(gè)子鏈也是一個(gè)filter鏈。 filter鏈可以包含單個(gè)filter,因此filter A、B、C、D、F、G 和 H 也是不同的filter鏈。 filter E 具有兩個(gè)輸入連接,因此包含filter E 的任何filter序列都不是filter鏈。

filter鏈 (示例 1)
IFilterChain 接口提供用于控制filter鏈的以下方法:
Label 值
IFilterChain::StartChain 啟動(dòng)鏈。
IFilterChain::StopChain 停止鏈。
IFilterChain::P auseChain 暫停鏈。
IFilterChain::RemoveChain 從圖中刪除鏈。
沒有用于添加鏈的特定方法。 若要添加鏈,請(qǐng)使用 IFilterGraph::AddFilter 方法插入新filter。 然后,通過(guò)調(diào)用 IGraphBuilder::Connect、 IGraphBuilder::Render 或類似方法連接filter。
當(dāng)圖形運(yùn)行時(shí),filter鏈可以在運(yùn)行和停止之間切換。 當(dāng)圖形暫停時(shí),它可以在暫停和停止之間切換。 這些是filter鏈唯一可能的狀態(tài)轉(zhuǎn)換。
filter鏈準(zhǔn)則
使用 IFilterChain 方法時(shí),請(qǐng)務(wù)必確保圖中的filter可以支持filter鏈接操作。 否則,可能會(huì)導(dǎo)致死鎖或圖形錯(cuò)誤。 在鏈更改狀態(tài)后,連接到鏈的filter必須正常運(yùn)行。
使用 IFilterChain 的最佳方式是使用一組專為鏈接設(shè)計(jì)的filter。 使用以下準(zhǔn)則來(lái)確保filter對(duì)filter鏈操作是安全的。 這些要點(diǎn)參考下圖。

filter鏈 (示例 2)
在filter鏈的狀態(tài)更改之前,必須完成filter鏈邊界上的所有數(shù)據(jù)處理調(diào)用。 此規(guī)則適用于 IMemInputPin::Receive、 IPin::NewSegment 和 IPin::EndOfStream 的方法。 鏈中的filter必須從對(duì)鏈外filter進(jìn)行的這些方法的調(diào)用返回;和 鏈外部的filter必須從鏈中的filter進(jìn)行的調(diào)用返回。
例如,在上圖中,filter B 必須完成來(lái)自filter A 的任何數(shù)據(jù)處理調(diào)用,而filter E 必須完成來(lái)自filter D 的任何調(diào)用。如果pin公開 IPinFlowControl 和 IPinConnection 接口,可以通過(guò)調(diào)用 IPinFlowControl::Block 和 IGraphConfig::P ushThroughData 方法通過(guò)圖形推送數(shù)據(jù),如 動(dòng)態(tài)重新連接中所述。 filter可能還支持用于推送數(shù)據(jù)的專用方法。
上游filter必須預(yù)期鏈的狀態(tài)會(huì)發(fā)生更改。 例如,在上圖中,假設(shè)鏈已停止,但filter A 調(diào)用 IMemInputPin::Receive。 調(diào)用失敗,filter A 的響應(yīng)是停止流式處理。 當(dāng)應(yīng)用程序重啟鏈時(shí),它不起作用,因?yàn)?code>filter A 不再流式處理數(shù)據(jù)。
下游filter還必須預(yù)期鏈的狀態(tài)會(huì)發(fā)生更改。 否則,下游filter可能會(huì)在等待從未到達(dá)的樣本時(shí)阻止。 例如,多路復(fù)用器 (MUX) filter通常需要來(lái)自其所有輸入pin的數(shù)據(jù)。 從一個(gè)輸入pin停止數(shù)據(jù)流可能會(huì)阻止其他流進(jìn)行處理。 這可能會(huì)導(dǎo)致圖形死鎖。
從鏈外filter到鏈內(nèi)filter的每個(gè)pin連接都應(yīng)具有其自己的分配器,而其他連接不共享該分配器。 當(dāng)鏈更改狀態(tài)或從圖中刪除時(shí),分配器可能已取消提交。 如果其他連接使用相同的分配器,則它們無(wú)法再處理示例。
除非連接到鏈的filter支持動(dòng)態(tài)斷開連接,否則請(qǐng)勿刪除鏈。 通常,連接的filter將支持 IPinConnection 或 IPinFlowControl 接口,但可能改為支持專用接口。