This article walks through a simple C++ program designed to demonstrate one way to play movies. It is based on the PlayFile function code, taken from the Playfile.cpp file, which you can find in the Playfile sample in the Samples\ds\player directory.
The PlayFile function has no control over the filters selected by the filter graph manager to play the input media file or over the playback window created. This article contains the following sections.
See these related sections to add a particular feature to your playback code:
Playing a Media File
This section explains the code needed to play a media file from within C/C++. The Playfile sample contains Playfile.cpp and demonstrates how to create an application window, display a menu to open a media file, and call the PlayFile function to play the media file. You can examine the Playfile application in the Samples\ds\player\Playfile directory to see how to use the PlayFile function. To learn how to build the Playfile sample from Visual C++ 5.x, see Setting the Visual Studio Include and Lib Directories.
The PlayFile function plays a specified file in a playback window. This function uses the filter graph manager to automatically render the media clip. The filter graph manager selects the appropriate filters and constructs the filter graph.
PlayFile function code demonstrates:
After any function call that retrieves an interface pointer (CoCreateInstance, RenderFile, and QueryInterface), you should insert error-checking code to make sure the interface pointer was successfully obtained; if it wasn't, release any interfaces pointers already obtained. An example of error-checking code is:
if (FAILED(hr)) { goto ObjectRelease; // go to the clean-up section }
You can call the PlayFile function from an application with code such as the following:
TCHAR *szFilename = "c:\\dxmedia\\movie\\movie.avi"; PlayFile(szFilename);
Perform the following steps to play a media file from within C/C++. You don't necessarily have to perform the steps in the order presented.
#include <windows.h> #include <mmsystem.h> #include <streams.h> #include "playfile.h"
#define WM_GRAPHNOTIFY WM_USER+13 #define HELPER_RELEASE(x) { if (x) x->Release(); x = NULL; }
HWND ghApp; HINSTANCE ghInst; HRESULT hr; LONG evCode; LONG evParam1; LONG evParam2;
The ghApp variable is the handle of window to notify when the graph signals an event. The ghInst variable is the HINSTANCE of the window. The evCode variable will hold the event code, and the evParam1 and evParam2 variables will hold the event parameters.
IGraphBuilder *pigb = NULL; IMediaControl *pimc = NULL; IMediaEventEx *pimex = NULL; IVideoWindow *pivw = NULL;
void PlayFile (LPSTR szFile) { HRESULT hr;
WCHAR wFile[MAX_PATH]; MultiByteToWideChar( CP_ACP, 0, szFile, -1, wFile, MAX_PATH );
hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&pigb);
pigb->QueryInterface(IID_IMediaControl, (void **)&pimc); pigb->QueryInterface(IID_IMediaEventEx, (void **)&pimex); pigb->QueryInterface(IID_IVideoWindow, (void **)&pivw);
hr = pigb->RenderFile(wFile, NULL);
pimex->SetNotifyWindow((OAHWND)ghApp, WM_GRAPHNOTIFY, 0);
The window specified by ghApp will handle messages in response to all events from the graph. If an event occurs, DirectShow posts a WM_GRAPHNOTIFY message to the window.
hr = pimc->Run();
Alternatively, if your playback had a pause or stop button (see, for example, the CPlay sample or Controlling Filter Graphs Using C), you can pause or stop the playback on the button event with the IMediaControl::Pause or IMediaControl::Stop method, as shown in the following code.
hr = pimc->Pause(); hr = pimc->Stop();
The WndMainProc callback function in Playfile handles the filter graph messages and releases the interfaces when necessary, using the HELPER_RELEASE macro. The GetClipFileName function gets the movie to be played, while the WinMain function creates the window. These are all generic windows functions.
This section showed how to play a media file from the beginning. The next section shows how to control where within a media file to start and stop playing.
Adding Media Seeking
You can use the IMediaPosition or IMediaSeeking interface to seek to a particular place in your media file. The IMediaPosition::put_CurrentPosition method enables you to specify a start time within the media file. For example, you can use the following code to rewind to the media file's beginning.
IMediaPosition *pimp; hr = pigb->QueryInterface(&IID_IMediaPosition, (void **)&pimp); hr = pimp->put_CurrentPosition(0);
Time is specified in 100-nanosecond units. The following code seeks into the media file 1 second:
hr = pimp->put_CurrentPosition(10000000);
You can use the IMediaPosition::put_StopTime method to set the time within the media file to stop playback.
However, with IMediaPosition you can seek only to times within a media file. With the IMediaSeeking interface, you can set your seeking time format to 100-nanosecond time units, frames, bytes of data, media samples, or interlaced video fields. You set the format you want to use with the IMediaSeeking::SetTimeFormat method. Make sure your media file is not playing when you the set the format.
The term media time refers to positions within a seekable medium. Media time can be expressed in a variety of units, and indicates a position within the data in the file. The following table shows the possible media time formats.
Value | Description |
TIME_FORMAT_MEDIA_TIME | Seeks to the specified time in the media file, in 100-nanosecond units. This is the default. |
TIME_FORMAT_BYTE | Seeks to the specified byte in the stream. |
TIME_FORMAT_FIELD | Seeks to the specified interlaced video field. |
TIME_FORMAT_FRAME | Seeks to the specified video frame. |
TIME_FORMAT_SAMPLE | Seeks to the specified sample in the stream. |
For example, the following code sets the format so that the application seeks for sample numbers.
IMediaSeeking *pims; hr = pigb->QueryInterface(IID_IMediaSeeking, (void **)&pims); hr = pims->SetTimeFormat(&TIME_FORMAT_SAMPLE);
An application can use the various seeking modes to seek in a stream to a particular video frame or audio sample without doing time/rate conversions itself. This is useful for editing, which requires sample-accurate playback. The frame or sample number that the application specifies is passed through to the AVI or MPEG parser without the risk of rounding errors.
The following steps show how to set which frame in a media file to start playing at and which frame to stop playing at; for example, to start playing a movie at the fifth frame after its beginning. You can insert this code into the PlayFile function anywhere after the RenderFile function has built the filter graph.
IMediaSeeking *pims; hr = pigb->QueryInterface(IID_IMediaSeeking, (void **)&pims);
hr = pims->SetTimeFormat(&TIME_FORMAT_FRAME);
LONGLONG start = 5L; LONGLONG stop = 15L;
pims->SetPositions(&start, AM_SEEKING_AbsolutePositioning, &stop, AM_SEEKING_AbsolutePositioning);
pims->Release();
By removing the SetTimeFormat call and setting the values of start and stop as follows, you can set the media file to start playing 5 seconds into the file and stop 7 seconds into the file, for a duration of 2 seconds.
LONGLONG start = 50000000L; LONGLONG stop = 70000000L;
By setting other formats in the SetTimeFormat call, you can seek to frames, sample numbers, byte, and so on.
© 1997 Microsoft Corporation. All rights reserved. Terms of Use.