juhara.com

  • Narrow screen resolution
  • Wide screen resolution
  • Decrease font size
  • Default font size
  • Increase font size
Home Articles Multimedia Programming Multimedia Player with DirectShow Part 1
Multimedia Player with DirectShow Part 1 PDF Print E-mail
Written by Zamrony P. Juhara   
Friday, 15 September 2006 23:28
Article Index
Multimedia Player with DirectShow Part 1
Controlling Data Streaming
Source code example
Demo application
All Pages
First part of tutorial that explains how to use DirectShow, one of DirectX component, to create multimedia player with Delphi

Introduction

DirectShow is one of DirectX component useful for multimedia streaming. This tutorial is first part of creating TV tuner application tutorial (inspired by question posted by mikroplus in Delphindo mailing list). Because creating TV Tuner with DirectShow needs knowledge about Directshow, so for first part, this tutorial discusses basic steps to create DirectShow application. To create simple application with DirectShow is not so hard.

What do you need?

You need following softwares:

  • Brain.
  • DirectX version 8 or newer.
  • Delphi compiler. I use Delphi 7.
  • DirectX header conversion. You can download DirectX 9 header conversion or DirectX 8.1 header conversion. I use DirectX 8.1 header conversion.

COM Initialization

To initialize COM, we callCoInitialize(). For example:

CoInitialize(nil);

CoInitialize() is declared in Activex.pas unit.

Creating Filter Graph Manager.

DirectShow uses filter graph (or simply filter) to refer to software components that operate on multimedia data. Filter graph manager is manager of filters.

To create Filter Graph Manager, we can use CoCreateInstance() function, declared in activex.pas

For example:

var FFilterGraph:IGraphBuilder;

CoCreateInstance(CLSID_FilterGraph,nil,
CLSCTX_INPROC_SERVER,
IID_IGraphBuilder,
FFilterGraph);

CLSID_FilterGraph is classID for filter graph manager (declared in Directshow.pas unit), CLSCTX_INPROC_SERVER indicates that we use in-process COM server (DirectX is in-process COM server). IID_IGraphBuilder is interface ID for IGraphBuilder. IGraphiBuilder interface is interface of filter graph manager. If succeed, FFilterGraph will be filled with address of interface IGraphBuilder instance, otherwise it will be filled with nil.

Creating filter graph and add it to Filter graph manager.

DirectShow has many built-in filters, on of it is filter reader to read multimedia file. To read multimedia file and play it, IGraphBuilder has RenderFile() method useful for constructing filter graph and add filter graph to filter graph manager automatically.

var FFilename:string;
wFilename:widestring;
begin

wFilename:=WideString(FFilename);
FFilterGraph.RenderFile(PWideChar(wFilename),nil);
end;

RenderFile() expects filename to be rendered. It should be type of PWideChar (2 byte per 1 character), therefore, if we use string, it must be typecasted to widestring. Second parameter is PlayList. This parameter is reserved and must be set to nil.

RenderFile doesn't clear existing filter graph. If we call RenderFile twice then all filter will be played simultaneous. This behaviour may not what we expected.

Removing filter graph from filter graph manager.

IGraphBuilder has RemoveFilter method to remove a filter from filter graph manager. For example:

FFilterGraph.RemoveFilter(aFilter);

Where aFilter is filter graph type of IBaseFilter that we want to delete. To get list of filters in filter graph manager, we use enumFilters().

FFilterGraph.EnumFilters(enum);

enum is type of IEnumFilters. This interface has method called Next to access next filter. For example

while (enum.Next(1,afilter,@totRead)=S_OK) do

begin
//do something with filter
end;

First parameter is number of filter we want to retrieve. In example above, we take filter one by one. afilter is filter type of IBaseFilter, totRead is address of variable that will filled with actual filter retrieved. According to Microsoft, afilter is array of IBaseFilter and its total element is equal to number of filter requested, but ub its declaration in DirectShow.pas, its type is IBaseFilter.

To remove all filter:

while (enum.Next(1,afilter,@totRead)=S_OK) do
begin
FFilterGraph.RemoveFilter(aFilter);
enum.Reset;
end;

After a filter is deleted, enum is no longer consistent with content of filter graph (out of sync). To make it consistent, we need to reset it.

Get other interfaces from filter graph manager.

Other interfaces we need is IMediaControl useful for controlling multimedia streaming process. IMediaSeeking is useful for seeking position in multimedia stream. IMediaEvent and IMediaEventEx.is used for event notification. To get those interfaces (except IMediaEventEx), we query from IGraphBuilder interface. For example:

var FMediaControl:IMediaControl;
aEvent:IMediaEvent;
FMediaEvent:IMediaEventEx;
FMediaSeek:IMediaSeek;

FFilterGraph.QueryInterface(IID_IMediaControl,FMediaControl);
FFilterGraph.QueryInterface(IID_IMediaEvent,aEvent);
aEvent.QueryInterface(IID_IMediaEventEx,FMediaEvent);
FFilterGraph.QueryInterface(IID_IMediaSeeking,FMediaSeek);

For IMediaEventEx, we don't quiery it from IGraphBuilder. IMediaEventEx is an extension of IMediaEvent and must be queried from IMediaEvent.

Sending DirectShow Event Notification Request.

To let us know what is currently going on, we need to tell DirectShow that we want to get notified. We use SetNotifyWindow() method of IMediaEventEx. For example:

FMediaEvent.SetNotifyWindow(aHandle,WM_MMNOTIFY,integer(self));

aHandle is window window that will receive WM_MMNOTIFY message. WM_MMNOTIFY is our own custom message we define. Custom message should be between WM_APP-WM_APP+$BFFF.

const WM_MMNOTIFY=WM_APP+$1234;

Don't forget to add messages.pas unit. Third parameter is our own data. This parameter will get passed to message handler via lParam of WM_MMNOTIFY. In above example, we send address of class instance.

Processing event

Create and event handler for WM_MMNOTIFY, for example:

procedure WM_MMNotify(var msg:TMessage);message WM_MMNOTIFY;

and in its implementation

procedure TfrmMediaPlayer.WM_MMNotify(var msg: TMessage);
var aplayer:TBasicPlayer;
evCode,param1,param2:integer;
begin
aplayer:=TBasicPlayer(msg.LParam);
aplayer.EventObj.GetEvent(evCode,param1,param2,0);
case evCode of

EC_COMPLETE:begin
//lakukan sesuatu
end;
end;
aplayer.EventObj.FreeEventParams(evCode,param1,param2);
end;

msg.lParam will hold address of class instance (see "Sending DirectShow Event Notification Request" above).

IMediaEventEx has GetEvent() useful to get code of event occured and its parameters. Because this function allocates memory for parameters of event, we must call FreeEventParams() to avoid memory leak. For complete event code, you can look at DirectX documentation. I use EC_COMPLETE very often. It tells us when data streaming is complete.



Last Updated on Friday, 06 November 2009 15:32
 

Language

IndonesianEnglish (United Kingdom)

Game Institute
DAZ3D

Is this article helpful? Help this site improve by donating. Any amount is appreciated.