DirectShow

Top  Previous  Next

Programming DirectShow in Delphi

 

Introduction to DirectShow

 

Microsoft® DirectShow® is an architecture for streaming media on the Microsoft Windows® platform. DirectShow provides for high-quality capture and playback of multimedia streams. It supports a wide variety of formats, including Advanced Systems Format (ASF), Motion Picture Experts Group (MPEG), Audio-Video Interleaved (AVI), MPEG Audio Layer-3 (MP3), and WAV sound files. It supports capture from digital and analog devices based on the Windows Driver Model (WDM) or Video for Windows. DirectShow is integrated with other DirectX technologies. It automatically detects and uses video and audio acceleration hardware when available, but also supports systems without acceleration hardware.

DirectShow simplifies media playback, format conversion, and capture tasks. At the same time, it provides access to the underlying stream control architecture for applications that require custom solutions. You can also create your own DirectShow components to support new formats or custom effects.

Examples of the types of C++ applications you can write with DirectShow include file players, TV and DVD players, video editing applications, file format converters, audio-video capture applications, encoders and decoders, digital signal processors, and more. In Visual Basic you can create basic playback applications only. This documentation set covers both C++ and Visual Basic topics. Audio-video playback based on managed code is supported through Managed DirectX 9.0 and is not part of DirectShow.

DirectShow is based on the Component Object Model (COM). To write a DirectShow application or component, you must understand COM client programming. For most applications, you do not need to implement your own COM objects. DirectShow provides the components you need. (If you want to extend DirectShow by writing your own components, however, you must implement them as COM objects.)

Supported Formats in DirectShow

 

DirectShow is an open architecture, which means that it can support any format as long as there are filters to parse and decode it. The filters provided by Microsoft, either as redistributables through DirectShow or as Windows operating system components, provide default support for the following file and compression formats.

Note An asterisk (*) indicates that DirectShow applications must use the Windows Media® Format SDK to support this format. For more information, see the Audio and Video section of the MSDN Library.

File types:

Windows Media® Audio (WMA)*

Windows Media® Video (WMV)*

Advanced Systems Format (ASF)*

Motion Picture Experts Group (MPEG)

Audio-Video Interleaved (AVI)

QuickTime (version 2 and lower)

WAV

AIFF

AU

SND

MIDI

Compression formats:

Windows Media Video*

ISO MPEG-4 video version 1.0*

Microsoft MPEG-4 version 3*

Sipro Labs ACELP*

Windows Media Audio*

MPEG Audio Layer-3 (MP3) (decompression only)

Digital Video (DV)

MPEG-1 (decompression only)

MJPEG

Cinepak

Microsoft does not provide an MPEG-2 decoder. Several DirectShow-compatible hardware and software MPEG-2 decoders are available from third parties.

For information on the availability of particular third-party codecs for redistribution with DirectShow applications, contact the codec manufacturer.

Note : in Windows Vista DVD Decoder Codec are avaiable

In delphi, you can find the delphi header of directshow/directx here :

http://sourceforge.net/projects/delphi-dx9sdk/

or (with DSPack & BaseClasses)

http://www.progdigy.com/files/DSPACK234.zip

You don't need to install dspack. Just add path to it : Tools -> Environment Option -> Library -> Library Path

(Note : in this tutorial i use delphi 7, other delphi version will work correctly)

 

How to play a file ?

 

Start a new console project.

 

A DirectShow application always performs the same basic steps:

Create an instance of the Filter Graph Manager.

Use the Filter Graph Manager to build a filter graph.

Run the graph, causing data to move through the filters.

Start by calling CoInitialize to initialize the COM library:

 

var hr : HRESULT;

hr := CoInitialize(nil);

 

if FAILED(hr) then

begin

// Add error-handling code here. (Omitted for clarity.)

Writeln('ERROR - Could not initialize COM library');

Halt;

end;

 

To keep things simple, this example ignores the return value, but you should always check the HRESULT value from any method call.

Next, call CoCreateInstance to create the Filter Graph Manager:

 

var pGraph : IGraphBuilder;

// Create the filter graph manager and query for interfaces.

hr := CoCreateInstance(CLSID_FilterGraph, nil, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, pGraph);

if FAILED(hr) then

begin

Writeln('ERROR - Could not create the Filter Graph Manager.');

Halt;

end;

 

As shown, the class identifier (CLSID) is CLSID_FilterGraph. The Filter Graph Manager is provided by an in-process DLL, so the execution context is CLSCTX_INPROC_SERVER. DirectShow supports the free-threading model, so you can also call CoInitializeEx with the COINIT_MULTITHREADED flag.

The call to CoCreateInstance returns the IGraphBuilder interface, which mostly contains methods for building the filter graph. Two other interfaces are needed for this example:

IMediaControl controls streaming. It contains methods for stopping and starting the graph.

IMediaEvent has methods for getting events from the Filter Graph Manager. In this example, the interface is used to wait for playback to complete.

Both of these interfaces are exposed by the Filter Graph Manager. Use the returned IGraphBuilder pointer to query for them:

 

var pControl : IMediaControl;

pEvent   : IMediaEvent;

hr := pGraph.QueryInterface(IID_IMediaControl, pControl);

hr := pGraph.QueryInterface(IID_IMediaEvent, pEvent);

 

Now you can build the filter graph. For file playback, this is done by a single method call:

 

hr := pGraph.RenderFile('C:\Example.avi', nil);

 

The IGraphBuilder::RenderFile method builds a filter graph that can play the specified file. The first parameter is the file name, represented as a wide character (2-byte) string. The second parameter is reserved and must equal NULL.

This method can fail if the specified file does not exist, or the file format is not recognized. Assuming that the method succeeds, however, the filter graph is now ready for playback. To run the graph, call the IMediaControl::Run method:

 

hr := pControl.Run();

 

When the filter graph runs, data moves through the filters and is rendered as video and audio. Playback occurs on a separate thread. You can wait for playback to complete by calling the IMediaEvent::WaitForCompletion method:

 

var evCode : integer = 0;

pEvent.WaitForCompletion(INFINITE, evCode);

 

This method blocks until the file is done playing, or until the specified time-out interval elapses. The value INFINITE means the application blocks indefinitely until the file is done playing.

When the application is finished, release the interface pointers and close the COM library:

 

pControl._Release();

pEvent._Release();

pGraph._Release();

CoUninitialize();

 

Sample Code

Here is the complete code for the example described in this article:

 

program DirectShow_Sample;

 

{$APPTYPE CONSOLE}

uses

DirectShow9,

Windows,

ActiveX;

 

var pGraph : IGraphBuilder;

pControl : IMediaControl;

pEvent : IMediaEvent;

hr : HRESULT;

evCode : integer = 0;

begin

hr := CoInitialize(nil);

 

if FAILED(hr) then

begin

Writeln('ERROR - Could not initialize COM library');

Halt;

end;

 

// Create the filter graph manager and query for interfaces.

hr := CoCreateInstance(CLSID_FilterGraph, nil, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, pGraph);

if FAILED(hr) then

begin

Writeln('ERROR - Could not create the Filter Graph Manager.');

Halt;

end;

 

hr := pGraph.QueryInterface(IID_IMediaControl, pControl);

hr := pGraph.QueryInterface(IID_IMediaEvent, pEvent);

 

// Build the graph. IMPORTANT: Change this string to a file on your system.

hr := pGraph.RenderFile('C:\Example.avi', nil);

if SUCCEEDED(hr) then

begin

// Run the graph.

hr := pControl.Run();

if SUCCEEDED(hr) then

begin

// Wait for completion.

pEvent.WaitForCompletion(INFINITE, evCode);

// Note: Do not use INFINITE in a real application, because it

// can block indefinitely.

end;

end;

pControl._Release();

pEvent._Release();

pGraph._Release();

CoUninitialize();

end.