Step 2: Declare CVideoRenderer and Derived Classes

[The feature associated with this page, DirectShow, is a legacy feature. It has been superseded by MediaPlayer, IMFMediaEngine, and Audio/Video Capture in Media Foundation. Those features have been optimized for Windows 10 and Windows 11. Microsoft strongly recommends that new code use MediaPlayer, IMFMediaEngine and Audio/Video Capture in Media Foundation instead of DirectShow, when possible. Microsoft suggests that existing code that uses the legacy APIs be rewritten to use the new APIs if possible.]

This topic is step 2 of the tutorial Audio/Video Playback in DirectShow. The complete code is shown in the topic DirectShow Playback Example.

DirectShow provides several different filters that render video:

For more information about the differences between these filters, see Choosing the Right Video Renderer.

In this tutorial, the following abstract class is used to wrap the video renderer filter.

// Abstract class to manage the video renderer filter.
// Specific implementations handle the VMR-7, VMR-9, or EVR filter.

class CVideoRenderer
{
public:
    virtual ~CVideoRenderer() {};
    virtual BOOL    HasVideo() const = 0;
    virtual HRESULT AddToGraph(IGraphBuilder *pGraph, HWND hwnd) = 0;
    virtual HRESULT FinalizeGraph(IGraphBuilder *pGraph) = 0;
    virtual HRESULT UpdateVideoWindow(HWND hwnd, const LPRECT prc) = 0;
    virtual HRESULT Repaint(HWND hwnd, HDC hdc) = 0;
    virtual HRESULT DisplayModeChanged() = 0;
};

Notes:

  • The HasVideo method returns TRUE if the video renderer has been created.
  • The AddToGraph method adds the video renderer to the filter graph.
  • The FinalizeGraph method completes the graph-building step.
  • The UpdateVideoWindow method updates the video destination rectangle.
  • The Repaint method redraws the current video frame.
  • The DisplayModeChanged method handles display-mode changes.

Each of these methods is described in detail later in this tutorial.

Next, declare a derived class to wrap each of the three video renderers: the EVR, the VMR-9, and the VMR-7.

CEVR Class

The CEVR class manages the EVR. It contains a pointer to the IBaseFilter and IMFVideoDisplayControl interfaces of the EVR.

// Manages the EVR video renderer filter.

class CEVR : public CVideoRenderer
{
    IBaseFilter            *m_pEVR;
    IMFVideoDisplayControl *m_pVideoDisplay;

public:
    CEVR();
    ~CEVR();
    BOOL    HasVideo() const;
    HRESULT AddToGraph(IGraphBuilder *pGraph, HWND hwnd);
    HRESULT FinalizeGraph(IGraphBuilder *pGraph);
    HRESULT UpdateVideoWindow(HWND hwnd, const LPRECT prc);
    HRESULT Repaint(HWND hwnd, HDC hdc);
    HRESULT DisplayModeChanged();
};

CVMR9 Class

The CVMR9 class manages the VMR-9. It contains a pointer to the IVMRWindowlessControl9 interface.

// Manages the VMR-9 video renderer filter.

class CVMR9 : public CVideoRenderer
{
    IVMRWindowlessControl9 *m_pWindowless;

public:
    CVMR9();
    ~CVMR9();
    BOOL    HasVideo() const;
    HRESULT AddToGraph(IGraphBuilder *pGraph, HWND hwnd);
    HRESULT FinalizeGraph(IGraphBuilder *pGraph);
    HRESULT UpdateVideoWindow(HWND hwnd, const LPRECT prc);
    HRESULT Repaint(HWND hwnd, HDC hdc);
    HRESULT DisplayModeChanged();
};

CVMR7 Class

The CVMR7 class manages the VMR-7. It contains a pointer to the IVMRWindowlessControl interface.

// Manages the VMR-7 video renderer filter.

class CVMR7 : public CVideoRenderer
{
    IVMRWindowlessControl   *m_pWindowless;

public:
    CVMR7();
    ~CVMR7();
    BOOL    HasVideo() const;
    HRESULT AddToGraph(IGraphBuilder *pGraph, HWND hwnd);
    HRESULT FinalizeGraph(IGraphBuilder *pGraph);
    HRESULT UpdateVideoWindow(HWND hwnd, const LPRECT prc);
    HRESULT Repaint(HWND hwnd, HDC hdc);
    HRESULT DisplayModeChanged();
};

Next: Step 3: Build the Filter Graph.

Audio/Video Playback in DirectShow

Using the Video Mixing Renderer

Video Rendering