Microsoft DirectX 8.1 (C++) |
This article describes how to attach video playback to a particular window. It presents a sample program and explains the concepts required to understand the sample. The sample program builds on the one presented in How To Play a File.
Note In the sample program presented in this article, most of the code performs standard windowing operations, and is not discussed in this section. In particular, the functions WindowProc and WinMain contain a typical framework for Microsoft® Windows® applications. The application-defined functions PlayFile and CleanUp are the ones of interest.
When you render a video file, the filter graph will contain a video renderer filter. The video renderer takes uncompressed video data as input and renders it to the screen inside a window. Unless you specify otherwise, the video playback window is a top-level window with its own borders and title bar. It is more likely, however, that you will want the video to appear in a particular window created by your application. The solution is to make the renderer's video window a child of the application window. You can accomplish this by setting properties on the video window to specify the owner, style, and position of the window. To do this, use the Filter Graph Manager's IVideoWindow interface.
First, create an instance of the filter graph manager and construct the filter graph (through a call to the IGraphBuilder::RenderFile method). For more information on how to do this, see How To Play a File.
Then, before starting playback, set the properties on the video window, as follows:
IVideoWindow *pVidWin = NULL;
pGraph->QueryInterface(IID_IVideoWindow, (void **)&pVidWin);
pVidWin->put_Owner((OAHWND)g_hwnd);
pVidWin->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS);
RECT grc;
GetClientRect(g_hwnd, &grc);
pVidWin->SetWindowPosition(0, 0, grc.right, grc.bottom);
The GetClientRect function fills a RECT structure with the coordinates of the window's client area. The coordinates are relative to the upper-left corner of the client area, so the left and top members are both zero and the right and bottom members define the width and height, respectively.
Before the application exits, it is important that you set the visibility of the video window to false. Otherwise, a video image remains on the screen and the user cannot get rid of it. Then, reset the owner to NULL; otherwise, messages are sent to the wrong window, likely causing errors.
HRESULT hr = pVidWin->put_Visible(OAFALSE);
hr = pVidWin->put_Owner(NULL);
Sample Code
The following sample program renders a file named Test.avi inside an application window. For brevity, it omits the following features:
#include <windows.h>
#include <dshow.h>
#define CLASSNAME "VideoWindow"
IGraphBuilder *pGraph = NULL;
IMediaControl *pMediaControl = NULL;
IVideoWindow *pVidWin = NULL;
HWND g_hwnd;
void PlayFile(void)
{
// Create the filter graph manager.
CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC,
IID_IGraphBuilder, (void **)&pGraph);
pGraph->QueryInterface(IID_IMediaControl, (void **)&pMediaControl);
pGraph->QueryInterface(IID_IVideoWindow, (void **)&pVidWin);
// Build the graph.
pGraph->RenderFile(L"Test.avi", NULL);
//Set the video window.
pVidWin->put_Owner((OAHWND)g_hwnd);
pVidWin->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS);
RECT grc;
GetClientRect(g_hwnd, &grc);
pVidWin->SetWindowPosition(0, 0, grc.right, grc.bottom);
// Run the graph.
pMediaControl->Run();
}
void CleanUp(void)
{
pVidWin->put_Visible(OAFALSE);
pVidWin->put_Owner(NULL);
pMediaControl->Release();
pVidWin->Release();
pGraph->Release();
}
// Message handler.
long FAR PASCAL WindowProc( HWND hwnd, UINT msg, UINT wParam, LONG lParam)
{
switch (msg)
{
case WM_DESTROY:
CleanUp();
PostQuitMessage(0);
break;
default:
return (DefWindowProc(hwnd, msg, wParam, lParam));
}
return(NULL);
}
// Main.
int PASCAL WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine,
int nCmdShow )
{
MSG msg;
WNDCLASS wc;
CoInitialize(NULL);
ZeroMemory(&wc, sizeof wc);
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInst;
wc.hIcon = LoadIcon( NULL, IDI_APPLICATION );
wc.hCursor = LoadCursor( NULL, IDC_ARROW );
wc.hbrBackground = (HBRUSH)GetStockObject( BLACK_BRUSH );
wc.lpszMenuName = NULL;
wc.lpszClassName = CLASSNAME;
RegisterClass( &wc );
g_hwnd = CreateWindow(
CLASSNAME,
"DirectShow Sample",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInst,
NULL);
ShowWindow( g_hwnd, nCmdShow );
UpdateWindow( g_hwnd );
PlayFile();
while( GetMessage( &msg, NULL, 0, 0 ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
CoUninitialize();
return msg.wParam;
}