Click here to Skip to main content
Email Password   helpLost your password?

Introduction

This article demonstrates a simple wrapper class for playing video files with the new DirectShow Video Mixing Renderer 9.

In DirectX9, multimedia applications can use a new video renderer to display decoded frames, but this renderer is not the default renderer for compatibility issue. On Windows XP, the default renderer is the VMR7, but on older Windows version it's the Video Renderer. The main difference is performance and overlay mixing capabilities: as older renderer use different versions of DirectDraw API (even older API for the Video Renderer), the VMR9 is based on DirectX Graphics, so it uses the Direct3D capability of your 3D video card. The result is an improved performance on recent 3D cards, better support of overlay mixing, compatibility with all Windows versions that support DirectX9, and some new capability such as de-interlacing and ProcAmp support (contrast, saturation, etc.).

So the new VMR9 looks great but it's not the default renderer, regardless of Windows version... We've to build it manually, and this is why I wrote this class.

What you need...

To run the demo, DirectX9 runtime has to be installed on your system, which must have a Direct3D compatible display adapter. To build, DirectX9 SDK must be installed on your system. The source code was created under Visual C++ 6 SP5.

All the tests I've made is on my WinXP box, running an ATI Radeon M7 (kind of Radeon 7500). As I can't check real compatibility with many other Windows releases and video cards, please try with your system and put a word in the forum.

Using the code

A first look

All of the DirectShow graph management and VMR routines are included in one class : CVMR9Graph.

class CVMR9Graph  
{
    // Constructor / destructor

public:
    CVMR9Graph();
    CVMR9Graph(HWND MediaWindow, 
             int NumberOfStream = 4);
    virtual ~CVMR9Graph();

    // Methods

public:
    // Graph configuration

    void SetNumberOfLayer(int nNumberOfLayer);
    BOOL SetMediaWindow(HWND MediaWindow);
    BOOL SetMediaFile(const char* pszFileName, 
                             int nLayer = 0);
    BOOL PreserveAspectRatio(BOOL bPreserve = TRUE);
    IBaseFilter* AddFilter(const char* pszName, 
                             const GUID& clsid);

    // Graph control

    BOOL PlayGraph();
    BOOL StopGraph();
    BOOL ResetGraph();
    IMediaEvent* GetPtrMediaEvent();
    IMediaControl* GetPtrMediaControl();
    IMediaSeeking* GetPtrMediaSeeking();
    IBasicAudio* GetPtrBasicAudio();


    // Layer control

    BOOL GetVideoRect(LPRECT pRect);
    int GetAlphaLayer(int nLayer);
    BOOL SetAlphaLayer(int nLayer, int nAlpha);
    DWORD GetLayerZOrder(int nLayer);
    BOOL SetLayerZOrder(int nLayer, DWORD dwZOrder);
    BOOL SetLayerRect(int nLayer, RECT layerRect);

    // Bitmap control

    BOOL SetBitmap(const char* pszBitmapFileName, 
      int nAlpha, COLORREF cTransColor, RECT bitmapRect);
    BOOL SetBitmapParams(int nAlpha, 
      COLORREF cTransColor, RECT bitmapRect);

    // Reflected from window

    BOOL Repaint();
    BOOL Resize();

    // helper

    LPCTSTR GetLastError();

protected:
    // [...]

};

For convenience, header and implementation files contains the DirectShow includes, Direct3D includes, and pragma directives for lib.

Step 1 : Building a simple player

Building a very simple video player is quite easy:

  1. Include VMR9Graph.h and VMR9Graph.cpp in your project,
  2. Add an instance of CVMR9Graph in your application,
  3. Provide a window for video playback,
  4. Call CVMR9Graph::SetMediaWindow(hMyVideoPlaybackHandle) to set the video playback window,
  5. Call CVMR9Graph::SetMediaFile(0, pszPathToMyFile) to set the video file to render,
  6. Call CVMR9Graph::RunGraph() to play video.

At this point video playback works but the video wasn't resized with your window...

Step 2 : Forwarding events

Your application have to tell to the graph when the video has to repaint or size:

You can notice that video playback preserves aspect ratio by default. You can change this by a call to CVMR9Graph::PreserveAspectRatio(FALSE).

Ok, that looks much better... time to play with video mixing.

Step 3: Mixing video

Multiple file playback was handled by layers. Each layer plays a video and supports several properties such as ordering, alpha blending, size and position. The video produced by multiple layers is called a composition, and takes the size of the biggest media.

Each layer you insert is identified by it's layer index; CVMR9Graph lets you play with 10 layers, with it's default value to 4 layers (VMR9 default).

The following example loads 2 video files and sets an alpha value of 50% to the first:

// load media files

myGraph.SetMediaFile(0, "C:\\Video1.avi");
myGraph.SetMediaFile(1, "C:\\Video2.mpg");

// set alpha value to video1

myGraph.SetAlphaLayer(0, 50);

Alpha value can be set in real time, as show in the demo app.

Note 1: I have not been able to mix two DivX files, but only one DivX and other codecs such as MPEG... Don't know why... perhaps a hardware lack, since DirectShow samples seems to have the same troubles.

Note 2: The CVMR9Graph adds only one sound renderer in the graph, so only the first video stream has sound. You can add another sound renderer with a call to CVMR9Graph::AddFilter(_T"Another Sound Renderer", CLSID_DSoundRender).

Looks cool on a recent computers... Can we add more?

Step 4 : Setting an overlay bitmap

Overlay bitmap in CVMR9Graph is loaded in a Direct3D surface. The bitmap can be in GIF, JPEG, PNG, BMP, DIB, TGA, or DDS format.

To set an overlay bitmap, call CVMR9Graph::SetBitmap(), with the following parameters :

Overlay bitmap is a cool feature that can be used to:

Last step: Go further away

To keep the class simple, playback control is minimal, but you can do more by getting some DirectShow COM interfaces:

Note: After the use of an interface, you have to release it by a call to TheInterface::Release().

Known issue

When the graph is running, a call to CVMR9Graph::Stop() or CVMR9Graph::SetMediaFile() can be done, but it seems that in some cases composition can't run correctly after, particularly with bitmap media files...

A call to CVMR9Graph::ResetGraph() cleans up the graph and constructs a new fresh instance.

When resizing video window in demo app, there is some flickering... That's because it's a MFC window with the standard OnEraseBackgnd() implementation. Microsoft guidelines clearly indicate to bypass standard background paint.

// TODO : some improvements

The IVMRMonitorConfig9 interface is retrieved but not used. Multi monitor can be great.

There's no support for de-interlacing or ProcAmp control (ProcAmp don't work on my current ATI display drivers... Grrr)

There's no support for dynamic overlay bitmap... As a Direct3D surface can be locked and modified by a device context handle or even directly, this can be quite simple...don't know why I din't code it... probably a small lack of sleep.

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
AnswerReset problem
Member 1481854
4:01 20 Jun '08  
I think i found the solution to the problem in which case you need to call ResetGraph() after each video play
It seems that when you ask for a IMediaSeeking pointer and when the video is done reset the position to 0 and then play another file all goes well
But if you don't it gives the problem which needs the call to ResetGraph

IMediaSeeking * seeking = 0;
LONGLONG stopPos = 0, curPos = 0;
while (1) {
//get current position
if (seeking)
seeking->GetCurrentPosition(&curPos);

if (stopPos == curPos) {
//release previous seeking
if (seeking) {
//FIX!!!
LONGLONG zero = 0;
seeking->SetPositions(&zero, AM_SEEKING_AbsolutePositioning, 0, AM_SEEKING_NoPositioning);
// seeking->Release();
seeking = 0;
}

//play video
vmr->StopGraph();
vmr->SetMediaFile("file");
vmr->PlayGraph();

//get new seeking and stop position
seeking = vmr->GetPtrMediaSeeking();
seeking->GetStopPosition(&stopPos);
}
Sleep(50);
}

//cleanup
if (seeking)
seeking->Release();

QuestionReset function does not close the file
Yuna79
0:08 3 May '08  
First of all I would like to congratulate the author for the great job. The class is fantastic!!!
Forgive my English...
I have only one problem and i could use some help

1)I use SetMediaFile to set a specific file.
2)I use ResetGraph to release all interfaces.
3) I try to open the file with _open function but i can't. I can't delete it with the
DeleteFile function. It seems that the file is still open.

Here is some code:

m_pDirectShow->SetMediaFile("C\\test.avi");
m_pDirectShow->ResetGraph();
int myfile= _open("C\\test.avi",_O_RDWR|_O_CREAT|_O_BINARY);

myfile is equal to -1.
Any Ideas ?
Is there any way to force close the file?
GeneralHow can we implement this in c#
programmer
18:53 3 Dec '07  
Please guide me for impementing this in c#

from
Pgr
Generalreal time video?
captainc/c++
21:50 27 Nov '07  
Can I use it for real time video? how about dynamic resizing?

Right now, I am able to capture video from a video capture device, however, I'm not using DirectShow but instead DirectDraw. My problem is trying to put the video data into encoder and also resizing the video resolution whenever bitrate is going lower than pre-defined value. Or just resizing video into smaller resolutions (QCIF, SQCIF from CIF) will be OK for now.

Can you help me? DirectShow or DirectDraw will do just fine, as long as it works.

~God Bless The Internet~

GeneralVB6
Xristos2000
11:12 3 Sep '07  
I can make this work in VB6:
1 Master video with alpha% (V1)
1 Transparent video and with alpha% (V2)
1 Transparent BITMAP and with alpha% (B1)

all works fine but i have some quetions.
A. How i can hide or show one video or the bitmap (only solution i have is the rezise to witdh=0 and height=0)
B. How i can stop one video (V2) and others works with no problem.
C. How i can stop the video (V1) and play other (V1')
D. How i can pause one video (V2) and others videos (V1) continues to play

If any help me in C++ and i try converted at VB6.
(I try for all there 1 month)

thanks
GeneralRunning with WMP11
Trollslayer
0:01 25 Aug '07  
I have XP SP2, WMP11 and a nVidia 7600GS graphics card, the demo executable ran out the box!

Visit http://www.readytogiveup.com/[^] and do something special today.

GeneralVB6 or VB.NET?
Xristos2000
0:10 22 Aug '07  
IT IS IMPOSSIBLE WITH VB6 OR VB.NET (STUDIO 2005)?
Generalplay video on 2 surfaces
froid24
3:38 26 Apr '07  
I have a dialog-based app. Imodified the code to display the video on a dialog object, instead of a view. All nice so far.

But while the movie is playing on one dialog, i want it to play (show the same images) on another dialog, too, at different scale.

Is it possible to create another surface and attach/detach it to/from the graph at runtime ?

If i have 4 such graphs for 4 video files, all playing (like thumbnails), and i want to display one of the 4 videos in a bigger area, is it possible to capture a frame and blit it on a DC, while the original movie keeps playing ?

Thanks for the help !


Cheers,
Emil
Generaldraw over video
froid24
3:34 26 Apr '07  
Hi,

Is it possible to draw over the video (a line, a text etc.) like on a DC ? I see the bitmap overlay example, is it something similar ?

Could someone point me in the right direction ?

Many thanks !

Cheers,
Emil
GeneralRe: draw over video
KarstenK
4:25 26 Apr '07  
I would recommend that you try to draw directly on the DesktopDC. ::GetDC(0)

Greetings from Germany

GeneralRe: draw over video
froid24
11:02 26 Apr '07  
That is an idea, indeed. Many thanks.

But first i will try to seek the answer to my other (above) question. I have 4 video files playing in small regions, like thumbs. At any point in time, 1 of the 4 will have to be simultaneously displayed (played) bigger on another dialog. I think this could be done with another d3d surface, attached to the same graph, but i'm not sure since it is the first time i use this.

On the other hand, sometimes the video being displayed in the big regions must be frozen to a certain frame (the 4 thumb videos keep playing), and i have to draw some lines over this frozen frame. In this case, either i detach the d3d surface from the graph (if possible) and draw (as you suggest) directly on the desktop, so over it, hoping that it keeps the frozen frame. Or, I deactivate/delete that surface, and simply blit from the frozen frame onto the dialog, and draw over it in OnPaint.

I'm still waiting for suggestions from people who master this DirectX stuff better than me.

Thanks for the help !



Cheers from Romania,
Emil
GeneralRe: draw over video
KarstenK
21:20 26 Apr '07  
If you want to draw to 2 regions, it makes sence to draw first in a MemoryDC and than do the output. This MemoryDC would give you the option for further processing.

One of my live experiences is: "If your first solution dont work, dont worry TRY another"Cool

Greetings from Germany

Questionusing IMediaSeeking
superjoe3
11:56 13 Apr '07  
This wrapper works fine !
But I see no methods to control the position in the file I'm reading.
Has somebody an example of media playing using the IMediaSeeking with the VMR9?

Thanks in advance


AnswerRe: using IMediaSeeking
froid24
23:32 1 May '07  
Hi there,

This graph class HAS this functionality !!! It's just not exemplified.

Use the GetPtrMediaSeeking method of CVMR9Graph to obtain a pointer to an IMediaSeeking. Then, just use that pointer to:

- GetDuration(...)
- SetPositions(...)

These are both methods of IMediaSeeking.

Don't forget to Release() the IMediaSeeking when you're done.



Cheers from Romania !

-Emil
GeneralRe: using IMediaSeeking [modified]
exp2lnt
0:38 5 Nov '07  
You can using IMediaSeeking to seeking media as folows:
--------------------------------------------------------------------------
class CVMR9Graph
{
// Constructor / destructor
public:
...............................
IMediaSeeking* m_pMediaSeeking;
/** Goto the end of the video
Auguments
None
Return
Current position after seeking
*/
LONGLONG SeekToEnd(void);

/** Goto the begin of the video
Auguments
None
Return
Current position after seeking
*/
LONGLONG SeekToStart(void);

/** Seek w.r.t current position
Auguments
offset The offset to current position
Return
Current position after seeking
*/
LONGLONG Seek(int offset);
...............................
}

Next, you must implememt above methods

LONGLONG CVMR9Graph::SeekToStart(void)
{
// Goto the start of the video file
LONGLONG currentPosition = 0;
OAFilterState fs;
m_pMediaSeeking = GetPtrMediaSeeking();
if (m_pMediaSeeking) {
// Wait for the other seeking operation finish.
m_pMediaControl->GetState(INFINITE, &fs);
// Seek to start
m_pMediaSeeking->SetPositions(¤tPosition,
AM_SEEKING_AbsolutePositioning,
NULL, AM_SEEKING_NoPositioning);
// This function will wait until the seeking is finished
m_pMediaControl->GetState(INFINITE, &fs);
// Display the new frame
m_pMediaControl->StopWhenReady();
}
return LONGLONG(currentPosition);
}

LONGLONG CVMR9Graph::SeekToEnd(void)
{
// Goto the end of the video file
LONGLONG currentPosition = 0;
OAFilterState fs;
m_pMediaSeeking = GetPtrMediaSeeking();
if (m_pMediaSeeking) {
// Wait for the other seeking operation finish.
m_pMediaControl->GetState(INFINITE, &fs);
// Seek to the last frame
m_pMediaSeeking->GetDuration(¤tPosition);
m_pMediaSeeking->SetPositions(¤tPosition,
AM_SEEKING_AbsolutePositioning,
NULL, AM_SEEKING_NoPositioning);
// This function will wait until the seeking is finished
m_pMediaControl->GetState(INFINITE, &fs);
// Display the new frame
m_pMediaControl->StopWhenReady();
}
return LONGLONG(currentPosition);
}

LONGLONG CVMR9Graph::Seek(int offset)
{
LONGLONG currentPosition = -1;
OAFilterState fs;
m_pMediaSeeking = GetPtrMediaSeeking();
if (m_pMediaSeeking) {
// Wait for the other seeking operation to finish.
m_pMediaControl->GetState(INFINITE, &fs);
// Seek with respect to current position.
m_pMediaSeeking->GetCurrentPosition(¤tPosition);
currentPosition += offset;
m_pMediaSeeking->SetPositions(¤tPosition,
AM_SEEKING_AbsolutePositioning,
NULL, AM_SEEKING_NoPositioning);
// Wait until the seeking is finished
m_pMediaControl->GetState(INFINITE, &fs);
// Display the new frame
m_pMediaControl->StopWhenReady();
}
return LONGLONG(currentPosition);
}
--------------------------------------------------------------------------
Note that you don't forget Release() method. For example :

SafeRelease(m_pMediaSeeking);

Good luck !Smile


-- modified at 5:44 Monday 5th November, 2007
GeneralStreamed videos mms protocol
Scope
14:45 25 Feb '07  
First I have to say great work with the article and the project! Excellent wrapper! Works flawless with regular video-files on harddrive but doesnt seem to work with streamed files over the mms protocol. I guess you need some extra handling to be able to stream videos, handle cache-pauses and stuff? Perhaps you could enlighten me what it would take to get it to play streamed videos?

Thanks alot and keep up the good work!

-----------------------------
I am out of scope

GeneralRendering to texture
sodan
8:33 22 Feb '07  
Hi there

Nice code! Could you prove functions to render a movie, onto a supplied texture ?

thanx,
Søren

GeneralUsing the VMR project
slinks555
13:57 24 Jan '07  
The latter versions of DirectX 9 / DirectX 10 don't come with VMR
code, so using the last available .dsw samples version of DirectX is best.

I use Visual Studio 6.0 with sp5

Install DirectX 9 sdk (The version with VMR9 code in .dsw format) Retail or Debug

extract watermark.zip - http://www.quikstream.com.au/Lennox%20CCTV%20Engineering_files/watermark.zip

to a directory in:

c:\DXSDK\Samples\C++\DirectShow\VMR9\

load up the dsw workspace

compile and build

A CLSID_VideoMixingRenderer9 error can be caused when trying to compile
this project after installing DirectX8 SDK. For Directx8 CLSID_VideoMixingRenderer
instead is the predominant item, which is hard coded, that is the main cause of this error,
the vs builder likes all the library and header directories in place as well.


Generalnoob...compile error..
danomano100xtc
8:33 23 Jan '07  
I've openned/converted the project into visual studio 2003..

when I compile I get the following error:

c:\tmp\VMR9Demo\VMR9Graph.cpp(632) : error C2065: 'CLSID_VideoMixingRenderer9' : undeclared identifier
VMR9Demo.cpp
c:\tmp\VMR9Demo\VMR9Demo.cpp(53) : warning C4996: 'CWinApp::Enable3dControls' was declared deprecated
c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\atlmfc\include\afxwin.h(4369) : see declaration of 'CWinApp::Enable3dControls'
OverlayDialog.cpp

Any pointers on whats missing from my project/system?

GeneralRe: noob...compile error..
bigbadmarcus
9:47 5 Jul '07  


I fixed on my computer. Problem is that MS moves stuff around in different DirectX SDKs.

So I had to go to Visual Studio settings, move c:\dxsdk\include (and lib) to the top in directory locations.

You will have to change to fit your install also.

now it compiles/links/runs just fine.


GeneralQuikstream VMR media player for XP
slinks555
6:56 30 Dec '06  
Quikstream media player for XP

- alpha blended GUI
- plays all video files
- dx9 SDK compatible
- open source
- adaptable interface

Download:

http://www.quikstream.com.au/Lennox%20CCTV%20Engineering_files/watermark.zip

Build with Visual Studio 6.0 / 2005 Smile


QuestionCant add VMR9 in DirectX ??? [modified]
~Jabeen~
1:00 21 Dec '06  
Hi all

This is a very strange problem I have seen ever

I am developing my application based on Direct X

I am rendering video through “Video Mixing Renderer 9” (VMR9) on my PC the application is fine. On another PC my application is giving error that it can’t get the renderer filter.

Using Graph Edit I created Video Capture Sources and then rendered the Capture Pin. As observed a Video Renderer is added, finally video is previewed. As my application demanded windowless mode, I have replaced Video Renderer with VMR9.

On my PC this Graph Edit procedure is working fine. On another PC when I am trying to replace the Video Renderer with VMR it is giving following error. So my application gives error too that it cant add the VMR9 filter

The filter could not be created. Resources used by this filter may be already in use

Although I have checked the resources. No camera or such resources usage is observed. Also there is no connection between the pins when I am adding the filter.

How is this???? I don’t know how to resolve this.

In coding I would have used Video Renderer but I need Windowless mode which is provided by VMR only I want to display video in client area). Any alternate is also appreciated.

But can any body solve this issue that why I can’t add the filter. Or is there any other substitute of VMR?

i have searched out that problem i am facing has Error code 0x0273 in "DirectX Error Lookup"
(return code:0x80040273)

but how can i resolve this ? Some one told me reinstalling windows probably solve the problem

but my application is a dll and is developed statically linked with MFC so it has all prerequisites for it.

I wonder if any client of this dll faces same scenrio and not know the reason how will my application work Sniff

does anyone knows the alternate solution in DirectX (i want to display video in Client area that is Windowless mode).

I need DirectX because i want to capture video through Capture Resources

but i cant resolve this problem


Regards,



Jabeen

GeneralFound issue in SetMediaFile
MacGuy86
10:14 10 Mar '06  
I'm still playing with this, and I'm not sure exactly how it's supposed to work, but I was having serious problems with your class... basically, the vast majority of videos wouldn't play, and only under very specific circumstances would it play at all.

I got it to work, though I'm not certain what the correct solution is.

When adding a source filter, I added an IGraphBuilder::RenderFile line, and this fixed my issues. I suspect this is what you were looking for when you mentioned issues with SetMediaFile after it had been started.
GeneralMultiple Bitmaps?
DP3
11:54 29 Sep '05  
Is it possible to overlay more than one bitmap onto the video? I want to put multiple status statements on the video display.

Thanks,
Don

GeneralMemory leak
Anonymous
0:56 23 Sep '05  
I have played with this wrapper and it seems it has a memory leak. I am not shure if it is just my setup or inappropriate use, so please give your comments if you can reproduce this bug.

The procedure is as follows:
Open a video and play it
while (true) // Smile
When it stops (or when you stop it) load another video and play it

You can use the demo and load the files manually or program it.

From each video played there remains one thread (!) and several handles that are not released.


Last Updated 11 Feb 2003 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010