我是靠谱客的博主 健壮水杯,最近开发中收集的这篇文章主要介绍DirectShow之视频渲染,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

概述

    DirectShow提供了几种渲染视频的滤镜:

   ·Video Renderer filter:此过滤器适用于支持DirectX的所有平台,并且没有特定的系统要求。 Video Renderer尽可能使用DirectDraw来呈现视频; 否则,它使用GDI。 此筛选器是比Windows XP早的平台上的默认视频渲染器。

   ·Video Mixing Renderer Filter 7 (VMR-7):VMR-7在Windows XP上可用,它是默认的视频渲染器。 VMR-7总是使用DirectDraw 7进行渲染。 它提供了旧版Video Renderer过滤器中没有的许多强大功能,包括应用程序控制用于渲染的DirectDraw表面的插件模型。

    ·Video Mixing Render Filter 9 (VMR-9):VMR-9是使用Direct3D 9进行渲染的视频混合渲染器的更新版本。 它适用于支持DirectX的所有平台。 但它不是默认的渲染器,因为它比Video Renderer过滤器具有更高的系统要求。

    ·Overlay Mixer滤镜专为DVD播放和广播视频而设计。 它还支持视频端口扩展(VPE),使其能够与硬件MPEG-2解码器或将视频直接发送到图形卡的模拟电视调谐器。

    ·增强视频渲染器(EVR)过滤器在Windows Vista中可用。 与早期的视频渲染器相比,它提供了改进的视频性能,尤其是在启用Windows Vista桌面组合时

 

   DirectShow视频渲染器可以在窗口模式或无窗口模式下运行:

  ·在窗口模式下,渲染器创建自己的窗口来显示视频。 通常,您将使此窗口成为应用程序窗口的子项。

  ·在无窗口模式下,渲染器将视频直接拖到应用程序窗口上。 它不创建它自己的窗口

   Video Renderer过滤器仅支持窗口模式。 VMR-7和VMR-9过滤器支持这两种模式。 它们默认为窗口模式以实现向后兼容,但无窗口模式是首选。 EVR仅支持无窗口模式。

 

Choosing the Right Video Renderer

   主要使用哪个渲染器取决于您需要支持哪些版本的Windows

   ·在Windows Vista及更高版本中,如果硬件支持,则应用程序应使用EVR。 否则,回到VMR-9或VMR-7。 EVR提供比以前的渲染器更好的性能和更好的视频质量。 此外,它旨在与桌面窗口管理器(DWM)一起使用。

   ·在Windows Vista之前,如果硬件支持它并且不需要视频端口功能,请使用VMR-9。 否则,请使用VMR-7。

   ·在较旧的系统上,您可能需要使用Overlay Mixer(用于视频端口或硬件叠加支持)或旧式Video Renderer过滤器。

   IGraphBuilder :: Render和RenderFile方法默认使用VMR-7。 如果硬件不支持VMR-7,这些方法将回退到传统的Video Renderer过滤器。 EVR和VMR-9绝不是默认的渲染器。

 

窗口模式

    在窗口模式下,视频渲染器创建自己的窗口,在该窗口绘制视频帧。 除非另有说明,否则此窗口是具有自己的边框和标题栏的顶层窗口。 但是,大多数情况下,您会将视频窗口附加到应用程序窗口,以便将视频集成到应用程序UI中。 这需要以下步骤:

   1.查询IVideoWindow。

   2.设置父窗口。

   3.设置新的窗口样式。

   4.将视频窗口放置在所有者窗口内。

   5.通知WM_MOVE消息的视频窗口。

 

Query for IVideoWindow

    在开始播放之前,请在Filter Graph Manager中查询IVideoWindow接口

IVideoWindow *pVidWin = NULL;
pGraph->QueryInterface(IID_IVideoWindow, (void **)&pVidWin);

 

Set the Parent Window

 

    要设置父窗口,请调用带有应用程序窗口句柄的IVideoWindow :: put_Owner方法。 这个方法接受一个OAHWND类型的变量,所以把句柄转换为这种类型:

pVidWin->put_Owner((OAHWND)hwnd);

 

Set New Window Styles

 

    通过调用IVideoWindow :: put_WindowStyle方法来更改视频窗口的样式:

pVidWin->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS);

   WS_CHILD标志将窗口设置为子窗口,并且WS_CLIPSIBLINGS标志防止窗口在另一个子窗口的客户区域内绘制。

 

Position the Video Window

    要设置视频相对于应用程序窗口客户区的位置,请调用IVideoWindow :: SetWindowPosition方法。 此方法采用指定视频窗口的左边缘,顶边缘,宽度和高度的矩形。 例如,以下代码将视频窗口拉伸到适合父窗口的整个客户区:

RECT rc;
GetClientRect(hwnd, &rc);
pVidWin->SetWindowPosition(0, 0, rc.right, rc.bottom);

    要获得视频的原始大小,请在Filter Graph Manager上调用IBasicVideo :: GetVideoSize方法。 您可以使用该信息来缩放视频并保持正确的宽高比。

 

Respond to WM_MOVE Messages

   为了获得最佳性能,每当窗口在图形暂停时移动时,都应通知视频渲染器。 调用IVideoWindow :: NotifyOwnerMessage方法来转发WM_MOVE消息:

// (Inside your WindowProc)
case WM_MOVE:
    pVidWin->NotifyOwnerMessage((OAHWND)hWnd, msg, wParam, lParam);
    break;

    如果渲染器正在使用硬件叠加层,则此通知将导致渲染器更新叠加层位置。 (VMR-9不使用叠加层,因此如果您使用VMR-9,则无需调用此方法。)

 

Cleap Up

   在应用程序退出之前,停止图形并将视频窗口的所有者重置为NULL。 否则,窗口消息可能被发送到错误的窗口,这可能会导致错误。 此外,隐藏视频窗口,否则您可能会在屏幕上瞬间看到视频图像闪烁:

pControl->Stop(); 
pVidWin->put_Visible(OAFALSE);
pVidWin->put_Owner(NULL);  

 

 

 

无窗口模式

Configure the VMR for Windowless Mode

·VMR-7

   1.创建过滤器图形管理器。

   2.创建VMR-7并将其添加到过滤器图形中。

   3.使用VMRMode_Windowless标志在VMR-7上调用IVMRFilterConfig :: SetRenderingMode。

   4.查询IVMRWindowlessControl接口的VMR-7。

   5.在VMR-7上调用IVMRWindowlessControl :: SetVideoClippingWindow。指定视频应该出现的窗口的句柄。

·VMR-9   

   1.创建过滤器图形管理器。

   2.创建VMR-9并将其添加到过滤器图形中。

   3.使用VMR9Mode_Windowless标志调用VMR-9上的IVMRFilterConfig9 :: SetRenderingMode。

   4.查询IVMRWindowlessControl9界面的VMR-9。

   5.在VMR-9上调用IVMRWindowlessControl9 :: SetVideoClippingWindow。 指定视频应该出现的窗口的句柄。

 

   以下代码显示了一个辅助函数,它可以创建VMR-7,将其添加到图形中,并设置无窗口模式。

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; 
} 

    此功能假定仅显示一个视频流,而不是在视频上混合静态位图。你可以这样调用这个函数:

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();
}

 

 

 

Positon the Video

·VMR-7

   1.调用IVMRWindowlessControl :: SetVideoPosition方法来指定两个矩形。

   2.源矩形必须等于或小于原始视频大小; 您可以使用IVMRWindowlessControl :: GetNativeVideoSize方法获取原生视频大小。

·VMR-9

   1.调用IVMRWindowlessControl9 :: SetVideoPosition方法来指定两个矩形。

   2.源矩形必须等于或小于原始视频大小; 您可以使用IVMRWindowlessControl9 :: GetNativeVideoSize方法来获取原生视频大小。

   例如,以下代码设置VMR-7的源矩形和目标矩形。 它将源矩形设置为等于整个视频图像,目标矩形等于整个窗口客户区:

// 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); 
}

 

 

 

Handle Window Messages

·VMR-7

    1.WM_PAINT。 调用IVMRWindowlessControl :: RepaintVideo。 此方法会导致VMR-7重新绘制最近的视频帧。                 2.WM_DISPLAYCHANGE:调用IVMRWindowlessControl :: DisplayModeChanged。 此方法通知VMR-7必须以新的分辨率或颜色深度显示视频。

    3.WM_SIZE或WM_WINDOWPOSCHANGED:重新计算视频的位置并在需要时调用IVMRWindowlessControl :: SetVideoPosition更新位置。

·VMR-9

   1.WM_PAINT。 调用IVMRWindowlessControl9 :: RepaintVideo。 此方法会导致VMR-9重新绘制最近的视频帧。                2.WM_DISPLAYCHANGE:调用IVMRWindowlessControl9 :: DisplayModeChanged。 此方法通知VMR-9必须以新的分辨率或颜色深度显示视频。

   3.WM_SIZE或WM_WINDOWPOSCHANGED:重新计算视频的位置并在需要时调用IVMRWindowlessControl9 :: SetVideoPosition更新位置。

 

    以下示例显示了一个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); 
} 

参考:

https://www.yuque.com/docs/share/6c6329ba-62e6-4b66-8d01-0c57d47828de

最后

以上就是健壮水杯为你收集整理的DirectShow之视频渲染的全部内容,希望文章能够帮你解决DirectShow之视频渲染所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(40)

评论列表共有 0 条评论

立即
投稿
返回
顶部