I was working on a project that involved Reading video frames out of WMV files. First I searched for an article on CodeProject and other sites but could
not find anything. So I started
the Windows MediaSDK help files, and also used Google
Groups to solve the problems that I have encountered.
This article describes the basics of reading from a Windows Media file. I am
adding a class that can be used for reading WMV video frames, out of a file.
my focus is on the reading of video frames, the steps described in this article
are almost the same for reading audio buffers.
Note: Windows Media SDK requires a basic understanding of COM Interfaces.
You should download the Windows Media SDK files from Microsoft's site. I am
using version 9.5.
Very important: Follow the instructions provided for
setting up the environment to run WM SDK.
As in any program that uses COM, you need to remember to call
the basic interface
IUnknown, and allows the use of COM Objects.
I will now describe the steps taken for opening a WMV file.
Opening the file:
Step 1: Create a Reader Interface
There are two Reader Objects,
AsyncronusReader and the
AsyncronusReader uses a callback function that receives the next frame's information. I
prefer to use the
SyncReader, which is easier to understand and implement.
hr = WMCreateSyncReader(NULL,0,&m_ISyncReader);
Step 2: Opening a file
Now that we have a Reader Object we can call the
Open function and open a file
for reading. The file name should be in
w_char so you can use a
CString Object and call the
hr = m_ISyncReader->Open(m_filename.AllocSysString());
Step 3: Receiving the Outputs and Stream Numbers
Every WMV file has a number of streams (a stream is the compressed audio or
video). Output is uncompressed data read from the file. Output numbers start from 0 and stream numbers start from
1. If we have an output number, we can get its stream number. So basically, we
read output (which refer to Compressed Streams stored in the file). Note: output
can also be called an output stream.
This part has more steps, so I will break it down in separate parts.
3.1 Getting the number of Outputs in the file
3.2 Identify the Audio stream and the Video Stream
We use the
IWMOutputMediaProps Interface to receive the output stream
properties. Also we use the
First we get the output
properties by calling the
function which gives us for an output number of
we need to get the details. This is done by two calls to the
m_IVideoOutputProps->GetMediaType() function, first to get the size needed to
allocate for the
WM_MEDIA_TYPE, then for actually getting the information.
m_theMediaType = ( WM_MEDIA_TYPE* ) new BYTE[theSize ];
Now we can check if this is an Audio or Video Stream.
For Audio Stream check:
if( WMMEDIATYPE_Audio == m_theMediaType->majortype)
For Video Stream check:
if( WMMEDIATYPE_Video == m_theMediaType->majortype)
if(m_theMediaType->formattype == WMFORMAT_VideoInfo)
Now we can receive the Stream number of the video or Audio output.
Also, for the video stream we should read the Video Header:
We can receive more information on the movie, such
as: its duration, the movie name, etc. We leave this for later, however.
Step 4: Setting the Reader to receive correct sample durations
Set to receive correct sample durations. To ensure that the synchronous reader
delivers correct sample durations for video streams, you must first configure
the stream output. Call the
IWMSyncReader::SetOutputSetting method to set the
g_wszVideoSampleDurations, setting it to TRUE. If true, the reader will deliver
accurate sample durations.
BYTE* pValue = new BYTE;
hr = m_ISyncReader->SetOutputSetting(m_iVideoOutputNumber,
Step 5: Set To receive Uncompressed Samples
SetReadStreamSamples method specifies whether samples from a stream will be
delivered, compressed, or uncompressed. This is how you get set to receive uncompressed samples:
Reading Samples From the File
Reading the samples with the Synchronous Reader is quite simple.
We call the
IWMSyncReader::GetNextSample() function. This function fills a
INSSBuffer Interface pointer, you choose what stream to read from, and you get
the next sample. You also get its duration and position time in the movie.
When receiving a sample you should check if it's a CLEANPOINT sample. This
sample is a picture you would want to read.
When you get to the end of the movie you will receive
See this next code snippet for details:
QWORD cnsSampleTime = 0;
QWORD cnsSampleDuration = 0;
DWORD dwFlags = 0;
HRESULT hr = m_ISyncReader->GetNextSample(m_iVideoStreamNumber,
m_pINSSBuffer = NULL;
The buffer we receive here is only the DIB, the bitmap data without the header,
which we received in early stages.
Now you can save pictures to the disc, display the frames on your window, or
analyze the frames for other purposes.
Reading Other file properties
As I mentioned earlier, you can get more information from the file, such as its
duration. This is done in a few steps.
For receiving extra information on the file such as the file Duration, Title,
number of frames, we do the following.
Note: this information is there only if when creating the file the information
was included. So even if you try to get some information (such as the
To receive the information you need to create two objects:
IWMMetadataEditor *pEditor; IWMHeaderInfo3* pHdrInfo;
First you create the Editor, then you can receive the HeaderInfo.
Here is the code that receives the Duration of the file:
pHdrInfo = NULL;
hr = pEditor->QueryInterface(IID_IWMHeaderInfo3,(void**)&pHdrInfo);
WORD wStream =0;
WORD wSize =0;
hr = pHdrInfo->GetAttributeByName(
pValue = new BYTE[wSize];
hr = pHdrInfo->GetAttributeByName(&wStream,L"Duration",
m_qwTotalTimeInSeconds = (dwDuration*100)/1000000000;
Investigate Windows Media SDK for further information about what attributes you can
receive, and what names to use in the
Well, this is it. I hope you find this article useful.
May 8 - Initial posting