转自 http://blog.csdn.net/bwmwm/article/details/4430684

The Video Mixing Renderer filters (VMR-7 and VMR-9) both support windowless mode, which represents a major improvement over the IVideoWindow interface. This article describes the differences between windowless mode and windowed mode, and how to use windowless mode.

Video Mixing Renderer filter(VMR-7 和 VMR-9)都支持windowless模式,这是在IVideoWindwo接口上的主要提高。这篇文章描述windowless模式和windowed模式的不同,以及如何使用windowless模式。

To remain backward-compatible with existing applications, the VMR defaults to windowed mode. In windowed mode, the renderer creates its own window to display the video. Typically the application sets the video window to be a child of the application window. The existence of a separate video window causes some problems, however:

为了兼容现有的程序,VMR默认windowed模式。在windowed模式中,renderer创建属于它自己的窗口显示视频。应用程序设置视频窗口为应用程序窗口的子窗口。分离视频窗口会产生一些问题:

  • Most importantly, there is a potential for deadlocks if window messages are sent between threads.
  • 如果窗口消息在两个线程之间发送会产生潜在的死锁。
  • The Filter Graph Manager must forward certain window messages, such as WM_PAINT, to the Video Renderer. The application must use the Filter Graph Manager's implementation of IVideoWindow(and not the Video Renderer's), so that the Filter Graph Manager maintains the correct internal state.
  • Filter Graph Manager 必须发送类似WM_PAINT的windows消息到Video Renderer。应用程序必须使用Filter Graph Manager 的IVideoWindow执行(不是Video Renderer的IVideoWindow),以至于Filter Graph Mnager保持正确的内部状态。
  • To receive mouse or keyboard events from the video window, the application must set a "message drain," causing the video window to forward these messages to the application.
  • 为了从视频窗口接收鼠标和键盘事件,应用程序必须设置一个”message drain”,使视频窗口向应用程序发送消息。
  • To prevent clipping problems, the video window must have the right window styles.
  • 为了避免出现遮挡问题,视频窗口必须设置正确的样式。

Windowless mode avoids these problems by having the VMR draw directly on the application window's client area, using DirectDraw to clip the video rectangle. Windowless mode significantly reduces the chance of deadlocks. Also, the application does not have to set the owner window or the window styles. In fact, when the VMR is in windowless mode, it does not even expose the IVideoWindowinterface, which is no longer needed.

windowless模式利用DirectDraw剪切视频区域,直接画在应用程序窗口的客户区域来避免这些问题。windowless模式减少了死锁的几率。应用程序也不需要设置窗口的归属和风格。事实上,当VMR使用windowless模式的时候,并不暴露IVideoWindow接口,这个接口不在需要。

To use windowless mode, you must explicitly configure the VMR. However, you will find that is more flexible and easier to use than windowed mode.

为了使用windowless模式,必须明确的配置VMR。不过,你将发现使用windowless模式比windowed模式方便和灵活。

Configure the VMR for Windowless Mode

To override the VMR's default behavior, configure the VMR before building the filter graph:

要忽略VMR的默认行为,生成filter graph之前先配置VMR:

6.Create the Filter Graph Manager.

7.创建Filter Graph Manager。

8.Create the VMR and add it to the filter graph.

9.创建VMR并添加到filter graph中。

10.Call IVMRFilterConfig::SetRenderingMode on the VMR with the VMRMode_Windowless flag.

11.在VMR上调用IVMRFilterConfig::SetRenderingMode,参数是VMRMode_Windowless。

12.Call IVMRWindowlessControl::SetVideoClippingWindow on the VMR. Specify a handle to the window where the video should appear.

13.在VMR上调用IVMRWindowlessControl::SetVideoClippingWindow。指定一个显示视频的窗口句柄。

Now build the rest of the filter graph by calling IGraphBuilder::RenderFile or other graph-building methods. The Filter Graph Manager automatically uses the instance of the VMR that you added to the graph. (For details on why this happens, see Intelligent Connect.)

然后调用IGraphBuilder::RenderFile或者其他的方法生成filter graph的其他部分。Filter Graph Manager自动使用你添加到graph中的VMR实例。

The following code shows a helper function that creates the VMR, adds it to the graph, and sets up windowless mode.

下列的代码展示如何创建VMR并添加到graph中,设置成windowless模式。

HRESULT InitWindowlessVMR(

    HWND hwndApp,                  // Window to hold the video.

    IGraphBuilder* pGraph,         // Pointer to the Filter Graph Manager.

    IVMRWindowlessControl** ppWc   // Receives a pointer to the VMR.

    )

{

    if (!pGraph || !ppWc)

    {

        return E_POINTER;

    }

    IBaseFilter* pVmr = NULL;

    IVMRWindowlessControl* pWc = NULL;

    // Create the VMR.

    HRESULT hr = CoCreateInstance(CLSID_VideoMixingRenderer, NULL,

        CLSCTX_INPROC, IID_IBaseFilter, (void**)&pVmr);

    if (FAILED(hr))

    {

        return hr;

    }

   

    // Add the VMR to the filter graph.

    hr = pGraph->AddFilter(pVmr, L"Video Mixing Renderer");

    if (FAILED(hr))

    {

        pVmr->Release();

        return hr;

    }

    // Set the rendering mode. 

    IVMRFilterConfig* pConfig;

    hr = pVmr->QueryInterface(IID_IVMRFilterConfig, (void**)&pConfig);

    if (SUCCEEDED(hr))

    {

        hr = pConfig->SetRenderingMode(VMRMode_Windowless);

        pConfig->Release();

    }

    if (SUCCEEDED(hr))

    {

        // Set the window.

        hr = pVmr->QueryInterface(IID_IVMRWindowlessControl, (void**)&pWc);

        if( SUCCEEDED(hr))

        {

            hr = pWc->SetVideoClippingWindow(hwndApp);

            if (SUCCEEDED(hr))

            {

                *ppWc = pWc; // Return this as an AddRef'd pointer.

            }

            else

            {

                // An error occurred, so release the interface.

                pWc->Release();

            }

        }

    }

    pVmr->Release();

    return hr;

}

This function assumes that are displaying only one video stream and are not mixing a static bitmap over the video. For details, see VMR Windowless Mode. You would call this function as follows:

这个函数假设只有一个视频流,且没有混合静态图片覆盖视频:

IVMRWindowlessControl *pWc = NULL;

hr = InitWindowlessVMR(hwnd, pGraph, &g_pWc);

if (SUCCEEDED(hr))

{

    // Build the graph. For example:

    pGraph->RenderFile(wszMyFileName, 0);

    // Release the VMR interface when you are done.

    pWc->Release();

}

Position the Video

After configuring the VMR, the next step is to set the position of the video. There are two rectangles to consider, the source rectangle and the destination rectangle. The source rectangle defines which portion of the video to display. The destination rectangle specifies the region in the window's client area that will contain the video. The VMR crops the video image to the source rectangle and stretches the cropped image to fit the destination rectangle.

配置完VMR之后,下一步就是设置视频的位置。这里有两个矩形需要考虑,源矩形和目标矩形。源矩形定义视频显示的部分。目标矩形指定窗口中包含视频的矩形。VMR裁减图像到源矩形并拉伸裁减的图片以适应目标矩形。

Call the IVMRWindowlessControl::SetVideoPosition method to specify both rectangles. The source rectangle must be equal to or smaller than the native video size; you can use the IVMRWindowlessControl::GetNativeVideoSize method to get the native video size.

调用IVMRWindowlessControl::SetVideoPosition方法 指定这两个矩形。源矩形必须等于后者小于原始视频尺寸。可以调用IVMRWindowlessControl::GetNativeVideoSize或者原始视频尺寸。

For example, the following code sets the source rectangle equal to the entire video image and the destination rectangle equal to the entire window client area:

例如,接下来的代码设置源矩形等于整个视频图像,设置目标矩形等于整个窗口客户区域。

//Find the native video size.

long lWidth, lHeight;

HRESULT hr = g_pWc->GetNativeVideoSize(&lWidth, &lHeight, NULL, NULL);

if (SUCCEEDED(hr))

{

    RECT rcSrc, rcDest;

    // Set the source rectangle.

    SetRect(&rcSrc, 0, 0, lWidth, lHeight);

   

    // Get the window client area.

    GetClientRect(hwnd, &rcDest);

    // Set the destination rectangle.

    SetRect(&rcDest, 0, 0, rcDest.right, rcDest.bottom);

   

   // Set the video position.

    hr = g_pWc->SetVideoPosition(&rcSrc,& rcDest);

}

If you want to video to occupy a smaller portion of the client area, modify the rcDest parameter. If you want to crop the video image, modify the rcSrc parameter.

如果想让视频占据客户区域中的一小块,修改rcDest参数,如果想裁减视频图像,修改rcSrc参数。

Handle Window Messages

Because the VMR does not have its own window, you must inform it when the video needs to be repainted or modified.

因为 VMR没有自己的窗口,当视频需要重绘或者修改的时候,你必须通知他。

  • When you receive a WM_PAINT message, call IVMRWindowlessControl::RepaintVideo to repaint the image.
  • 当接收到WM_PAINT消息时,调用IVMRWindowlessControl::RepaintVideo重绘图像。
  • When you receive a WM_DISPLAYCHANGE message, call IVMRWindowlessControl::DisplayModeChanged. The VMR takes any actions that are needed to display the video at the new resolution or color depth.
  • 当接收到WM_DISPLAYCHANGE消息,调用IVMRWindowlessControl::DisplayModeChanged。在新的分辨率或颜色深度上VMR需要花费一些动作显示视频。
  • When you receive a WM_SIZE message, recalculate the position of the video and call SetVideoPosition again if necessary.
  • 当接收到WM_SIZE消息,如果需要的话,重新计算视频的位置并调用SetVideoPosition。

The following example shows a WM_PAINT message handler. It paints a region defined by the client rectangle minus the video rectangle. Do not draw onto the video rectangle, because the VMR will paint over it, causing flickering. For the same reason, do not set a background brush in your window class.

下面的例子显示了一个WM_PAINT消息的处理。它重画客户区域减去视频区域剩下的部分。不要在视频矩形上绘制,因为VMR将覆盖它,产生闪烁。同样的道理,在窗口类中不要设置背景刷。

void OnPaint(HWND hwnd)

{

    PAINTSTRUCT ps;

    HDC        hdc;

    RECT       rcClient;

    GetClientRect(hwnd, &rcClient);

    hdc = BeginPaint(hwnd, &ps);

    if (g_pWc != NULL)

    {

        // Find the region where the application can paint by subtracting

        // the video destination rectangle from the client area.

        // (Assume that g_rcDest was calculated previously.)

        HRGN rgnClient = CreateRectRgnIndirect(&rcClient);

        HRGN rgnVideo  = CreateRectRgnIndirect(&g_rcDest); 

        CombineRgn(rgnClient, rgnClient, rgnVideo, RGN_DIFF); 

       

        // Paint on window.

        HBRUSH hbr = GetSysColorBrush(COLOR_BTNFACE);

        FillRgn(hdc, rgnClient, hbr);

 

        // Clean up.

        DeleteObject(hbr);

        DeleteObject(rgnClient);

        DeleteObject(rgnVideo);

 

        // Request the VMR to paint the video.

        HRESULT hr = g_pWc->RepaintVideo(hwnd, hdc); 

    }

    else // There is no video, so paint the whole client area.

    {

        FillRect(hdc, &rc2, (HBRUSH)(COLOR_BTNFACE + 1));

    }

    EndPaint(hwnd, &ps);

}

Although you must respond to WM_PAINT messages, there is nothing you need to do between WM_PAINT messages to update the video. As this example shows, windowless mode lets you treat the video image simply as a self-drawing region on the window.

尽管你必须响应WM_PAINT消息,但是在WM_PAINT消息与更新视频之间你不需要做任何事情。就像例子展示的那样,windowless模式让你可以把视频图像简单的当成在窗口上自绘区域一样。

posted on 2013-07-24 12:47  竟飞工作室  阅读(612)  评论(0编辑  收藏  举报