Microsoft DirectX 8.1 (C++)

Setting the Video Window

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:

  1. Attach the video playback window to the desired parent window. To do this, call the IVideoWindow::put_Owner method and pass it a handle to the owner window. This method takes a variable of type OAHWND, so cast the handle to this type, if necessary:
    IVideoWindow    *pVidWin = NULL;
    pGraph->QueryInterface(IID_IVideoWindow, (void **)&pVidWin);
    pVidWin->put_Owner((OAHWND)g_hwnd);
    
  2. Change the style of the video window to a child window. To do this, call the IVideoWindow::put_WindowStyle method and pass it a combination of style flags. The WS_CHILD flag indicates that the window is a child window; the WS_CLIPSIBLINGS flag prevents the window from drawing inside the client area of another child window.
    pVidWin->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS);
    
  3. Set the position of the video window by calling the IVideoWindow::SetWindowPosition method. This method takes device coordinates specifying the left edge (x-axis), top edge (y-axis), width, and height of the window. The sample program stretches the video window to fill the entire parent window:
    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;
}