天天看點

[DirectShow] 002 - How To Play a File

As the article Introduction to DirectShow Application Programming describes, a DirectShow application always performs the same basic steps:

1.     Create an instance of the Filter Graph Manager .

2.     Use the Filter Graph Manager to build a filter graph.

3.     Run the graph, causing data to move through the filters.

就像 Introduction to DirectShow Application Programming 文章描述的,一個 DirectShow 應用程式總是執行以下相同的基本步驟:

1.       建立一個 Filter Graph Manage 執行個體。

2.       使用 Filter Graph Manager 生成 Filter Graph.

3.       運作 Graph ,讓資料在 Filters 中移動。

Start by calling CoInitialize to initialize the COM library

從調用 CoInitialize 初始化 COM 庫開始:

HRESULT hr = CoInitialize(NULL);

if (FAILED(hr))

{

    // Add error-handling code here. (Omitted for clarity.)

}

To keep things simple, this example ignores the return value, but you should always check the HRESULT value from any method call.

為使事情簡單,上面代碼忽略了傳回值。但是你需要檢查其他函數傳回的 HRESULT 值。

Next, call CoCreateInstance to create the Filter Graph Manager:

接下來,調用 CoCreateInstance 建立 Filter Graph Manager.

IGraphBuilder *pGraph;

HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL,

CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&pGraph);

As shown, the class identifier (CLSID) is CLSID_FilterGraph. The Filter Graph Manager is provided by an in-process DLL, so the execution context is CLSCTX_INPROC_SERVER. DirectShow supports the free-threading model, so you can also call CoInitializeEx with the COINIT_MULTITHREADED flag.

Class Identifier(CLSID) 是 CLSID_FilterGraph , Filter Graph Manager 由一個程序内 dll 提供,是以執行環境是 CLSCTX_INPROC_SERVER 。 DirectShow 支援自由線程類型,是以可以在調用 CoInitializeEx 的時候設定 COINIT_MULTITHREADED 标記。

The call to CoCreateInstance returns the IGraphBuilder interface, which mostly contains methods for building the filter graph. Two other interfaces are needed for this example:

·         IMediaControl controls streaming. It contains methods for stopping and starting the graph.

·         IMediaEvent has methods for getting events from the Filter Graph Manager. In this example, the interface is used to wait for playback to complete.

調用 CoCreateInstance 獲得 IGraphBuilder 接口,這個接口包含了大部分生成 filter graph 的方法。在這個例子中還使用到了兩個接口:

IMediaControl 控制媒體流,這個接口包含開始和停止 Graph 方法。

IMediaEvent 這個接口有從 Filter Graph Manager 獲得事件的函數,在這個例子中,這個接口被用來等待回放結束。

Both of these interfaces are exposed by the Filter Graph Manager. Use the returned IGraphBuilder pointer to query for them:

IMediaControl *pControl;

IMediaEvent   *pEvent;

hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl);

hr = pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);

這兩個接口都由 Filter Graph Manager 暴露。使用 IGraphBuilder 的指針詢問這兩個接口指針。

Now you can build the filter graph. For file playback, this is done by a single method call:

現在可以生成 Filter Graph 了,調用一個簡單的方法就可以回放檔案:

hr = pGraph->RenderFile(L"C://Example.avi", NULL);

The IGraphBuilder::RenderFile method builds a filter graph that can play the specified file. The first parameter is the file name, represented as a wide character (2-byte) string. The second parameter is reserved and must equal NULL.

IGraphBuilder::RenderFile 方法生成的 Filter Graph 可以播放指定的檔案。第一個參數是以寬字元串呈現的檔案名,第二個參數是保留參數必須為 NULL 。

This method can fail if the specified file does not exist, or the file format is not recognized. Assuming that the method succeeds, however, the filter graph is now ready for playback. To run the graph, call the IMediaControl::Run method:

當指定的檔案不存在或者格式不正确,這個函數會傳回失敗。如果傳回成功,那麼 filter graph 就準備好回放了。調用 IMediaControl::Run 方法運作這個 graph :

hr = pControl->Run();

When the filter graph runs, data moves through the filters and is rendered as video and audio. Playback occurs on a separate thread. You can wait for playback to complete by calling the IMediaEvent::WaitForCompletion method:

當 filter graph 運作的時候,資料在 filters 之間穿行,并且以視訊和音頻的形式呈現。回放發生在分離線程。可以調用 IMediaEvent::WaitForCompletion 方法等待回放結束:

long evCode = 0;

pEvent->WaitForCompletion(INFINITE, &evCode);

This method blocks until the file is done playing, or until the specified time-out interval elapses. The value INFINITE means the application blocks indefinitely until the file is done playing. For a more realistic example of event handling, see Responding to Events .

這個函數阻塞,直到檔案播放完成,或者指定的逾時時間到達。 INFINITE 值意味着應用程式無限期的阻塞,知道檔案播放完成。更多事件句柄的例子,參考 Responding to Events 。

When the application is finished, release the interface pointers and close the COM library:

當應用程式結束的時候,釋放接口指針,關閉 COM 庫:

pControl->Release();

pEvent->Release();

pGraph->Release();

CoUninitialize();

Here is the complete code for the example described in this article:

下面是這個例子的完整代碼:

#include <dshow.h>

void main(void)

{

    IGraphBuilder *pGraph = NULL;

    IMediaControl *pControl = NULL;

    IMediaEvent   *pEvent = NULL;

    // Initialize the COM library.

    HRESULT hr = CoInitialize(NULL);

    if (FAILED(hr))

    {

        printf("ERROR - Could not initialize COM library");

        return;

    }

    // Create the filter graph manager and query for interfaces.

    hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,

                         IID_IGraphBuilder, (void **)&pGraph);

    if (FAILED(hr))

    {

        printf("ERROR - Could not create the Filter Graph Manager.");

        return;

    }

    hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl);

    hr = pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);

    // Build the graph. IMPORTANT: Change this string to a file on your system.

    hr = pGraph->RenderFile(L"C://Example.avi", NULL);

    if (SUCCEEDED(hr))

    {

        // Run the graph.

        hr = pControl->Run();

        if (SUCCEEDED(hr))

        {

            // Wait for completion.

            long evCode;

            pEvent->WaitForCompletion(INFINITE, &evCode);

            // Note: Do not use INFINITE in a real application, because it

            // can block indefinitely.

        }

    }

    pControl->Release();

    pEvent->Release();

    pGraph->Release();

    CoUninitialize();

}

繼續閱讀