Pasha Glozman – Windows Media Center
September 16, 2008
1. Scope
The intention of this document is to introduce
developers to the new WTV file format. Below you will find a brief
discussion on how to consume WTV files in a DirectShow graph for various
operations on a WTV file such as trans-coding, playback, editing, etc.
The main audience of this document is developers familiar
with C++ and DirectShow concepts.
2. Overview
WTV file format replaces the previously used DVR-MS file
format. Video is encoded using the MPEG-2 standard and audio using MPEG-1 Layer
II or Dolby Digital AC-3 (ATSC A/52). The format extends these standards by
including metadata about the content and digital rights management.
Access to a WTV file content is made using Stream Buffer Engine DirectShow
source filter. Unlike DVR-MS files, produced by previous versions of Media
Center and based on ASF file format, WTV files are based on a new file format.
Below sections describe how to access audio/visual content
inside WTV file.
3. Consuming
WTV file
The below section provide details on how to consume audio
and video from a WTV file using Stream Buffer Engine (SBE) DirectShow filter.
There are several basic steps that need to be followed:
3.1 Source
filter
The preferred way to add a source filter to a DirectShow
graph is to call IGraphBuilder::AddSourceFilter with a name of .WTV file as a
parameter.
Graph builder object will automatically find source filter
(SBE) according to a file extension (.WTV)
Source filter can also be inserted manually into the graph
by creating a SBE COM object with CLSID CLSID_StreamBufferSource and adding
this filter to a graph by calling IFilterGraph::AddFilter.
3.2 Connecting
to a consuming filter
SBE source filter will expose a variable number of pins,
depending on the way the file was authored. Be default there is up to 1 audio
pin (major type is MEDIATYPE_Audio) and up to 1 video pin (major type is
MEDIATYPE_Video) that is exposed. The overall number and order of exposed
audio/video and other pins is not predetermined – the application must
enumerate all exposed pins and find the pins (by major type) it wants to
consume data from.
3.2.1 Transform filter
If the consuming filter is a transform filter, its input
pin(s) should be connected to the appropriate output SBE pin(s) (having the
same major types) by calling IGraphBuilder::Connect. This will use the
“Intelligent Connect” mechanism in order to insert needed intermediate filters
between SBE and consuming transform filter. Please see MSDN for more
information regarding “Intelligent
Connect” mechanism.
3.2.2 Renderer filter
If the consuming filter is a renderer filter that consumes
audio, video or both, it can be inserted into the graph, and then appropriate
SBE audio/video output pin(s) should be automatically rendered using
IGraphBuilder::Render. Above mentioned approach for transform filters will also
work for renderer filters - output SBE pin may be passed along with renderer
filter’s input pin to IGraphBuilder::Connect.
3.3 Consuming the content
New features in WTV file format allow dynamic format
changes, e.g. video compression type, video resolution, audio compression type,
etc. Consuming filter should support dynamic media format changes coming out of
SBE, signaling change in video and/or audio media type change (update on media
subtype, format block, etc.).
3.3.1 Video handling
If a consuming filter was connected downstream from video
decoder, it should support IPin::ReceiveConnection
calls during the time graph is running and not rely on default implementation
in DirectShow base classes. DirectShow base class implementation is to return
and error from IPin::ReceiveConnection
on a connected pin.
The default format block for MPEG-2 video stream will always
indicate NTSC 720x480 resolution. For TV content having resolution other than
NTSC 720x480, SBE will not send dynamic format updates and it is up to
downstream filters to parse video stream and discover actual video resolution.
When the Microsoft MPEG-2 Video Decoder filter is connected downstream from
SBE, its output pin will initially expose the same resolution in its media type
format block as the one exposed from SBE (NTSC 720x480 for MPEG-2 video). When
graph is pre-rolled (on Pause), it will parse the video steam and issue a video
format update on its output pin with the actual video resolution. It will call
IPin::ReceiveConnection on a downstream filter with new media type at that
time. See MSDN page for IPin::ReceiveConnection method for more information
about this method.
4. Sample
The following pseudo-code shows how to build a WTV -> ASF
trans-coding graph.
HRESULT BuildTranscodeGraph()
{
bool fIntellegentConnect = true;
// This example builds a simple transcode graph from WTV file
// to .ASF file using ASF Writer filter.
// We will use "intellegent connect" mechanism in this example
// as well as just rendering pins to existing renderer in the graph
CComPtr <IGraphBuilder> spGraph;
CComPtr <IBaseFilter> spSBE;
CComPtr <IBaseFilter> spASFWriter;
CComPtr <IPin> spSbeVideoOutputPin;
CComPtr <IPin> spSbeAudioOutputPin;
CComPtr <IPin> spRendererInputPin;
// Create Graph Builder object.
CoCreateInstance(
CLSID_FilterGraph,
NULL,
CLSCTX_INPROC_SERVER,
IID_IGraphBuilder,
(void**)&spGraph
);
// ask Graph Builder to find approproate source filter
// for .wtv file and insert it into the graph.
spGraph->AddSourceFilter(sSourceFileName, L"Source Filter", &spSBE);
// Create consuming ASF Writer filter.
// Create ASF Writer renderer filter and add it to the graph
CoCreateInstance(
CLSID_WMAsfWriter,
NULL,
CLSCTX_INPROC_SERVER,
IID_IBaseFilter,
(void**)&spASFWriter
);
spGraph->AddFilter(spASFWriter, L"ASF Writer");
// Find SBE output pin having MEDIATYPE_Video major type
// and MEDIATYPE_Audio major type
spSbeVideoOutputPin = FindOutputPinByType(spSBE, MEDIATYPE_Video);
spSbeAudioOutputPin = FindOutputPinByType(spSBE, MEDIATYPE_Audio);
// as an example we will use both techniques
if (fIntellegentConnect)
{
spRendererInputPin = FindInputPinByType(spASFWriter, MEDIATYPE_Video);
// Connect the pins , using intellegent connect.
spGraph->Connect(spSbeVideoOutputPin, spRendererInputPin);
spRendererInputPin = FindInputPinByType(spASFWriter, MEDIATYPE_Audio);
// Connect the pins , using intellegent connect.
spGraph->Connect(spSbeAudioOutputPin, spRendererInputPin);
}
else
{
spGraph->Render(spSbeVideoOutputPin);
spGraph->Render(spSbeAudioOutputPin);
}
return S_OK;
}
5. Next
steps
Stream Buffer Engine Source filter supports all documented
interfaces with WTV files.
Please go to http://msdn.microsoft.com/en-us/library/ms787604(VS.85).aspx
to learn more about interfaces supported by Stream Buffer Engine Source. These
interfaces include the following:
IAMFilterMiscFlags
IBaseFilter
IFileSourceFilter
ISpecifyPropertyPages
IStreamBufferMediaSeeking
IStreamBufferMediaSeeking2
IStreamBufferInitialize
IStreamBufferSource.