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、播放
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.