DirectShow - Video in a Window
Make sure you have read the notes on simple playback before starting on these.
With the simple playback, when a video file is played, DirectShow opens a new pop-up window with the video playing in it. Obviously for our games we would prefer to play the video in our main window, perhaps as an introduction or cut scene.
To play the video in our Window requires a few extra steps than the simple playback example. We need to:
- Set-up DirectShow as normal.
- Get an interface to the DirectShow window
- Tell DirectShow to use our Window
- Run the video as normal
Getting the DirectShow interface for the video window
Assuming you have carried out all the initial steps described in the simple playback notes (e.g. created the graph and control interfaces and called RenderFile) we now need to get an interface for the DirectShow playback window.
// Get the video window
IVideoWindow *m_videoWindow = NULL;
hr=pGraph->QueryInterface(IID_IVideoWindow, (void **)&m_videoWindow);
The above call will return a IVideoWindow set of interfaces. Make sure (as always) that you check the return result for an error. We can use this interface to tell DirectShow to render in our main window and not in a new window
Telling DirectShow about our application Window
// Setup the video window to use our window handle
// Set the style of the video window
hr=m_videoWindow->put_WindowStyle(WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
// Get the size of the window
// Set the video size:
hr=m_videoWindow->SetWindowPosition(rect.left, rect.top, rect.right, rect.bottom);
The first call is to put_Owner, here we are telling DirectShow to use our main Window which we have the handle for (hWnd is a handle to a window and is returned when we call CreateWindow. For further info see: WinMain).
Next we need to tell DirectShow what style of window our window was created with, simply copy the style you used when you created your window and pass it using put_WindowStyle. DirectShow needs to know this information so it can correctly calculate where to position the video e.g. avoid drawing over the menu bar.
Finally we need to tell DirectShow how big the client area of our Window is. The client area is the area of the window that excludes menus, bars at the top, the borders etc. There is a Windows call we can use to obtain this information called GetClientRect. This takes the handle to our window and fills in a RECT structure with the correct values.
Run the video
Now we can simply run the video as normal calling
hr = pControl->Run();
Once the video has finished playing you must release the video window interface (IVideoWindow) or otherwise you may have trouble drawing again - the last frame overwriting everything else.
I originally created these notes because a student wanted to play back a cut scene .avi using DirectShow and OpenGL. He had used OpenGL for all the graphics and wanted to use DirectShow for video. It is perfectly OK to mix DirectX APIs with OpenGL. The only problem was he did not have a handle to the window (hWnd) as OpenGL controlled all of the Window creation. If you have this situation one solution is to use the following code to obtain the window handle:
hWnd = FindWindow("GLUT", "myWindow");
Where GLUT is the Window class name and myWindow is the title you used when creating the main Window.
This works but feels a bit clumsy to me (looking for a Window based on its title!) so if you know a better way of obtaining the window handle used by OpenGL I would appreciate it if you could let me know.
You can also use the Windowless Mode of DirectShow by configuring Video Mixing Renderer filters (VMR-9). This is currently beyond the scope of these notes but look in the Platform SDK help for more information if you interested.