




| Multimedia Player with DirectShow Part 1 |
|
|
|
| Written by Zamrony P. Juhara | ||||||
| Friday, 15 September 2006 23:28 | ||||||
Page 1 of 4 First part of tutorial that explains how to use DirectShow, one of DirectX component, to create multimedia player with Delphi
IntroductionDirectShow 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:
COM InitializationTo 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; 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; 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 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 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; 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 eventCreate 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); 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 |