Microsoft DirectX 8.0 |
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.
This article contains the following sections:
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.
The video renderer filter supports the IVideoWindow interface, which contains methods for setting and retrieving properties on the video window. However, if you constructed your filter graph using the filter graph manager, you will not necessarily have a pointer to the video renderer filter. Therefore, the filter graph manager also supports IVideoWindow. It keeps a list of which filters in the graph expose IVideoWindow. When you call an IVideoWindow method on the filter graph manager, the filter graph manager distributes the call to those filters. In this way, the filter graph manager can support operations on individual filters, without the application needing to locate the right filter.
The filter graph manager uses the same mechanism to expose the IBasicVideo2 and IBasicAudio interfaces. These interfaces contain methods for setting audio and video properties. Call these methods on the filter graph manager, rather than calling them on individual filters.
This section describes how to use the IVideoWindow interface to set properties on the video window, including the owner and style of the window.
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.
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);
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; }