DirectShow入門之動(dòng)態(tài)構(gòu)建FilterGraph

字號(hào):

摘要:本文檔主要講述了Filter graph的動(dòng)態(tài)構(gòu)建技術(shù)
    動(dòng)態(tài)的重新連接
    在進(jìn)行pin連接的時(shí)候,應(yīng)用程序一般都要講graph停掉。但是,一些filter支持pin的動(dòng)態(tài)連接。
    圖1
    如上圖,我們想將Filter 2動(dòng)態(tài)移走。有兩個(gè)必要條件:
    (1)Filter 3 (pin D)必須支持IPinConnection接口(這個(gè)接口能夠保證Filter在非Stopped狀態(tài)下也能進(jìn)行Pin的重連);
    (2)Filter1上的輸出pin,也就是pin A,在重新連接的過程中必須要將發(fā)送數(shù)據(jù)的線程阻塞,在重連的時(shí)候,pin A和pin D中不允許數(shù)據(jù)的傳輸, 如果“重連”是由Filter 1發(fā)起的(在Filter內(nèi)部完成),那么Filter 1要有內(nèi)部機(jī)制來(lái)阻塞數(shù)據(jù)發(fā)送線程;如果“重連”由應(yīng)用程序來(lái)完成,則要求Filter 1 (pin A)實(shí)現(xiàn)IPinFlowControl接口。
    動(dòng)態(tài)重連的一般步驟如下:
    (1)在Filter 1(pin A)上阻塞數(shù)據(jù)流線程。
    (2)重連Pin A和Pin D,必要時(shí)插入新的Filter。
    (3)再次啟動(dòng)Filter 1(pin A)上的數(shù)據(jù)發(fā)送線程。
    下面先來(lái)看看第一步;
    (1)在Filter 1(pin A)上阻塞數(shù)據(jù)流線程。
    IPinFlowControl::Block可以工作在同步和異步兩種模式下。
    如果在異步方式下使用Block函數(shù),要首先創(chuàng)建一個(gè)win32事件,然后將這個(gè)事件句柄作為參數(shù)傳遞給block函數(shù),這個(gè)函數(shù)會(huì)立即返回,然后調(diào)用WaitForSingleObject方法等待事件被觸發(fā)。如下:
    // 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)用Block函數(shù),只需給它傳遞一個(gè)NULL的參數(shù)即可。這樣這個(gè)函數(shù)就會(huì)一直阻塞下去,直到pin完全做好準(zhǔn)備可以傳遞sample,阻塞停止。如果filter處于paused狀態(tài),阻塞時(shí)間也許會(huì)無(wú)限延長(zhǎng),因此,不要在你的主線程中采用同步的方式調(diào)用這個(gè)函數(shù),可以新開一個(gè)線程或者采用異步的方式。
    (2)重連Pin A和Pin D,必要時(shí)插入新的Filter。
    這里Pin的重連可以使用IGraphConfig::Reconnect或IGraphConfig::Reconfigure(IGraphConfig接口可以從Filter Graph Manager上獲得)。Reconnect比Reconfigure使用起來(lái)要簡(jiǎn)單,它主要作如下幾件事:
    1、將Filter 2置于Stopped狀態(tài),然后將其移走;
    2、如果需要,可以在filter graph中增加新的Filter;
    3、重新連接相關(guān)的各個(gè)Pin;
    4、將新加入的Filter置于Paused或Running狀態(tài),以使其與Filter Graph同步。示例如下:
    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);
    實(shí)際應(yīng)用中,如果你覺得Reconnect不夠靈活,還可以改用Reconfigure方法。這個(gè)方法可以通過應(yīng)用程序中的回調(diào)函數(shù)來(lái)重新連接pin。使用Reconfigure方法,你必須在你的應(yīng)用程序里實(shí)現(xiàn)IGraphConfigCallback接口;
    在Reconfigure調(diào)用之前,還要如前所述,阻塞數(shù)據(jù)發(fā)送線程,然后通過以下步驟將海沒有處理得數(shù)據(jù)發(fā)送下去:
    1、調(diào)用filter最末端的輸入pin上的IPinConnection::NotifyEndOfStream。在這個(gè)例子里就是pin D。給這個(gè)pin傳遞一個(gè)win32事件
    2、然后在和上游需要阻塞發(fā)送數(shù)據(jù)的filter的輸出pin相連的輸入pin上調(diào)用IPin::EndOfStream方法,這個(gè)例子,上游最遠(yuǎn)端得數(shù)據(jù)輸出pin是pin A,那么和它相連的輸入pin就是pin B了,就調(diào)用pin B上的IPin::EndOfStream方法。
    3、等待觸發(fā)事件。當(dāng)Pin D接收到一個(gè)end of stream通知的時(shí)候,表明graph中已經(jīng)沒有數(shù)據(jù)流在傳遞了,可以安全的進(jìn)行pin的重新連接了。
    這些處理IGraphConfig::Reconnect會(huì)自動(dòng)給我們完成 。
    (3)再次啟動(dòng)Filter 1(pin A)上的數(shù)據(jù)發(fā)送線程。
    只需調(diào)用IPinFlowControl::Block,如下:pFlowControl->Block(0, NULL);
    過濾器鏈(Filter Chains)
    首先要弄明白什么是Filter Chain。見下圖:
    圖2
    1、Filter Chain是相互連接著的一條Filter鏈路,并且鏈路中的每個(gè)Filter至多有一個(gè)Input pin,至多有一個(gè)Output pin;
    2、這條Filter鏈路中的數(shù)據(jù)流不依賴于鏈路外的其他Filter。
    如上圖中,A–B,C–D,F(xiàn)–G–H,F(xiàn)–G,G–H都是Filter Chain,同時(shí)Filter鏈也可以只包括一個(gè)filter,因此A,B,C,D,E,F,G也都是獨(dú)立的鏈,因?yàn)镋含有兩個(gè)輸入pin,因此任何含有E的都不是Filter Chain。
    Filter Chain通過IFilterChain接口來(lái)操作的,該接口可以從Filter Graph Manager上獲得。
    IFilterChain提供了下面的方法用來(lái)操作filter鏈:
    ·IFilterChain::StartChain 開始一個(gè)鏈條
    ·IFilterChain::StopChain 停止一個(gè)鏈條
    ·IFilterChain::PauseChain 暫停一個(gè)鏈條
    ·IFilterChain::RemoveChain 將一個(gè)鏈條從graph中刪除
    并沒有一個(gè)特殊的方法用來(lái)添加一個(gè)chain,它和正常的添加filter的方法一樣,首先用IFilterGraph::AddFilter 在graph中添加一個(gè)filter,然后就是IGraphBuilder::Connect, IGraphBuilder::Render等諸如此類的方法。
    當(dāng)Graph在運(yùn)行的時(shí)候,F(xiàn)ilter Chain可以在Running和Stopped狀態(tài)之間切換;當(dāng)Graph在暫停狀態(tài)下,F(xiàn)ilter Chain可以在Paused和Stopper狀態(tài)之間切換。以上是Filter Chain僅有的兩種狀態(tài)轉(zhuǎn)換