您的位置:首页 > 编程语言 > PHP开发

D3D下使用VMR9播放视频文件

2011-02-22 16:36 288 查看
 

作者:骡子宝

2005.12.30

       随着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();   //播放

 

本文来自CSDN博客,转载请标明出处:http://b
4000
log.csdn.net/senophen/archive/2010/12/02/6049965.aspx
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息