D3D下使用VMR9播放視頻文件

隨着DX開發包的不斷升級,其提供給媒體程序開發人員的接口功能也空前強大起來。本文就D3D下使用VMR9播放視頻向初學者談談心得。高手請止步(不想讓你看了吐血^_^)。
       早在DX8時代,SDK中就提供了VMR的功能,但是不幸的是,有不少功能只限於WINXP下使用。現在好了,DX9中VMR升級了,提供了VMR9。VMR全稱爲Video Mixing Renderer,顧名思義就是可以使用它來進行視頻渲染。那麼它到底有多強大呢?我可以告訴你,他十分強大,從SDK的SAMPLE中大家就能看到,VMR9可以進行多部視頻文件的混合播放,畫中畫播放,更酷的是只要是能支持DirectX9的系統都能使用它在3維物體的表面上進行視頻渲染。那麼這到底是什麼樣的效果呢?我可以設想這樣一個效果來告訴你。(注意:這目前只是一個設想,本人還沒有完全掌握這項技術)大家都知道“水晶球”有預知未來的能力吧,當法師操縱水晶球時,球體表面就會出現未來世界的一些情景。如果要把這個效果反映的程序裏去,我們就可以使用VMR9了。我們可以首先建立一個球體,並進行水晶化效果處理,然後再使用VMR9將一個關於未來的視頻片斷渲染到球體表面,這樣就形成了剛纔所設想的效果了。
VMR9可以使用3種工作模式,分別爲windowed, windowless, renderless模式。後兩種模式多用於遊戲中。本文將只談及windowless模式。下面我們進入正題。
使用過DSHOW的朋友應該會對下面的流程有似曾相識的感覺。
 
使用VMR9前我們必須先初始化COM庫!因爲它是一個COM對象。
 
//關於D3D的設備初始化我就不在此講述了
 
CoInitialize(NULL);       //初始化COM庫
 
程序中需要如下變量:
IGraphBuilder*                           g_graph;        //FILTER管理器
IBaseFilter*                                g_filter;         //用於創建VMR9
IBaseFilter*                                g_source;        //用於流媒體數據處理
IEnumPins*                                g_enumpins;     //用於獲取PIN
IFilterGraph2*                            g_Graph2;             //用於視頻流渲染操作
IMediaControl*                           g_mediaControl;   //媒體控制
IVMRFilterConfig9*                    g_filterConfig;     //VMR9配置
IVMRWindowlessControl9*         g_VMR;         //VMR9的WINDOWED模式控制
HWND                                      hWnd;           //程序主窗口句柄
 
首先我們要創建FilterGraphManager來管理處理視頻音頻信息的Filter(過濾器)
//創建FilterGraphManager
 
if(FAILED(CoCreateInstance(CLSID_FilterGraph,NULL,CLSCTX_INPROC_SERVER,IID_IGraphBuilder,(void **)&g_graph)))
{
       //錯誤處理
}
 
然後我們就要創建VMR9對象並將其功能接口返回給g_filter
 
//創建FilterGraph(VMR9)
if(FAILED(CoCreateInstance(CLSID_VideoMixingRenderer9,NULL,CLSCTX_INPROC_SERVER,IID_IBaseFilter,(void **)&g_filter)))
{
              //ERROR
}
 
創建完畢後將其加入到FILTER管理器以便使用VMR9的功能處理視頻流.
 
//add the VMR-9 to the filter graph
if(FAILED(g_graph->AddFilter(g_filter, L"VMR9")))
{
              //ERROR
}
 
現在第一步完成。我們接下來該對VMR9進行屬性配置,以便我們按照自己的目的使用它。
 
//創建VMRFilterConfig9
if(FAILED(g_filter->QueryInterface(IID_IVMRFilterConfig9, reinterpret_cast<void**>(&g_filterConfig))))
{
              //ERROR;
}
 
g_filterConfig->SetRenderingMode(VMR9Mode_Windowless);  //將其配置爲WINDOWLESS模式
 
現在我們需要VMRWindowlessControl9來對渲染區進行描述
 
//創建VMRWindowlessControl9
if(FAILED(g_filter->QueryInterface(IID_IVMRWindowlessControl9, reinterpret_cast<void**>(&g_VMR))))
{
              //error
}
 
g_VMR->SetVideoClippingWindow(hWnd);    //指定要渲染的窗口爲我們的應用程序
                                                                      //主窗口
//下面的三行描述我們的渲染窗口爲整個應用程序客戶區(整個配置過程適用於窗口模//式和全屏模式)
RECT *clientRect = new RECT;
::GetClientRect(hWnd, clientRect );
g_VMR->SetVideoPosition( NULL, clientRect );
 
最後,我們需要加載資源並控制播放
 
g_graph->AddSourceFilter(“你的資源路徑”, L"source", &g_source);  //將資源載入
 
//創建IFilterGrahp2處理媒體流
if(FAILED(g_graph->QueryInterface(IID_IFilterGraph2,reinterpret_cast<void**>(&g_Graph2))))
{
              //error
}
 
//指定RENDER渲染設備對上流設備的數據進行處理
g_Graph2->RenderEx(GetPin(g_source,PINDIR_OUTPUT),AM_RENDEREX_RENDERTOEXISTINGRENDERERS,NULL);
 
這裏對GetPin()方法進行一下說明:
IPin* PowerVideo::GetPin(IBaseFilter *pFilter, PIN_DIRECTION PinDir)
{
       BOOL       bFound = FALSE;
    IEnumPins  *pEnum;
    IPin       *pPin;
    HRESULT hr = pFilter->EnumPins(&pEnum);  //搜索上流設備的PIN
    if (FAILED(hr))
    {
        return NULL;
    }
    while(pEnum->Next(1, &pPin, 0) == S_OK)
    {
        PIN_DIRECTION PinDirThis;
        pPin->QueryDirection(&PinDirThis);
        if (bFound = (PinDir == PinDirThis))   //找到上流設備的輸出PIN
            break;
        pPin->Release();
    }
    pEnum->Release();
       if(!bFound)MessageBox(NULL,"Pin連接失敗","PowerVideo",MB_OK);
    return (bFound ? pPin : NULL); 
}//該方法主要就是幫助g_Graph2->RenderEx方法和上流設備的媒體輸出PIN進行對連
//以便將上流設備解碼後的媒體信息流出到RENDER(應用程序創建的渲染器)
 
//創建MediaControl控制播放
if(FAILED(g_graph->QueryInterface(IID_IMediaControl,reinterpret_cast<void**>(&g_mediaControl))))
{
              //error
}
 
g_mediaControl->Run();   //播放
 
至此,所部過程完畢,再次複述一下流程:
1、創建FILTER管理器
2、創建VMR9
3、將VMR9加入管理器
4、設置VMR9
5、加載資源
6、將資源與VMR9連接,讓VMR9對其進行解碼
7、播放
發佈了18 篇原創文章 · 獲贊 1 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章