L
LeeChange
Unregistered / Unconfirmed
GUEST, unregistred user!
今天我们要讨论的是怎样响应DS程序中的事件.他也包含一个例子程序,不过是基于Setting the Video Window的.
1.时间通知系统是怎样工作的.
DS程序在工作的时候,filter的状态会发生改变.例如被暂停,出现错误等等.此时,filter都会发送一个事件.一个时间由三部分
构成:
a.事件代码:表明事件的类型.
b.两个参数:表明一些附加信息.(与具体事件类型有关)
Filter graph manager会在内部处理一些事件而不通知应用程序,比如要求重绘视频窗体的事件.而有些事件,会被他送到
事件队列,应用程序可以得到和处理他们.DS处理事件的方法与Windows处理消息的非常类似.实际上,我们可以让filter graph
manager在有新事件发生时送一个消息到特定的窗体.这样一来,应用程序就可以在消息循环中处理DS的事件了.
应用程序可能要处理许许多多的事件,在我们的例子中,只关心EC_Complete事件.(他在数据流结束是被产生)
2.运用事件机制.
例子程序中用了对我们自定义的消息WM_GraphNotity作出了响应.
const
WM_GraphNotify = WM_App+1;
接下来,设置响应该消息的窗体
MediaEvent.SetNotifyWindow(Handle, WM_GraphNotify, 0);
IMediaEventEx.SetNotifyWindow有三个参数:第一个是确定哪个窗体将得到消息,第二个是传递什么消息.第三个无所谓.
该方法要在MediaControl.Run之前调用.
当应用程序收到WM_GraphNotify时,消息的lParam等于SetNotifyWindow中的第三个参数.消息的wParam总等于0.
在程序中,我们可以在Application的OnMessage中响应WM_GraphNotify,但我推荐编写一个消息响应方法:
procedure WMGraphNotify(var Msg: TMessage);
message WM_GraphNotify;
整个事件的发生序列如下:
1.Filter传送事件到filter graph manager
2.如果filter graph manager不处理该事件,则将他放入事件序列
3.Filter graph manager向应用程序发送WM_GraphNotify消息
4.应用程序响应这个消息
5.应用程序从事件队列中得到具体事件.
在WM_GraphNotify的响应处理中,用MediaEvent.GetEvent来从事件队列中的到事件(包括事件代码和两个参数).最后一个参数
是将等待多长时间,由于我们在WM_GraphiNotify之后才调用他,所以设为0(队列中肯定有事件)
由于消息和事件是异步的,所以安排了一个while循环一次将事件队列中的所有事件取出.取出后,用FreeEventParams释放也
是必要的.
例子程序中,只对EC_Complete做出响应(您可以自由发挥).
Source Code:
unit Main;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ExtCtrls, DirectShow, ActiveX;
const
WM_GraphNotify = WM_App+1;
type
TMainForm = class(TForm)
Panel: TPanel;
Button: TButton;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure ButtonClick(Sender: TObject);
private
{ Private declarations }
procedure WMGraphNotify(var Msg: TMessage);
message WM_GraphNotify;
public
{ Public declarations }
Graph: IGraphBuilder;
VideoWindow: IVideoWindow;
MediaControl: IMediaControl;
MediaEvent: IMediaEventEx;
end;
var
MainForm: TMainForm;
implementation
{$R *.DFM}
{ TMainForm }
procedure TMainForm.FormCreate(Sender: TObject);
begin
CoInitialize(nil)
end;
procedure TMainForm.FormDestroy(Sender: TObject);
begin
CoUninitialize
end;
procedure TMainForm.ButtonClick(Sender: TObject);
begin
CoCreateInstance(CLSID_FilterGraph, nil, CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, Graph);
Graph.RenderFile('c:/program files/borland/delphi5/demos/coolstuf/speedis.avi',
nil);
Graph.QueryInterface(IID_IVideoWindow, VideoWindow);
VideoWindow.put_Owner(Panel.Handle);
VideoWindow.put_WindowStyle(WS_Child or WS_Clipsiblings);
VideoWindow.SetWindowPosition(0, 0, Panel.Width, Panel.Height);
Graph.QueryInterface(IID_IMediaEventEx, MediaEvent);
MediaEvent.SetNotifyWindow(Handle, WM_GraphNotify, 0);
Graph.QueryInterface(IID_IMediaControl, MediaControl);
MediaControl.Run
end;
procedure TMainForm.WMGraphNotify(var Msg: TMessage);
var
evCode: Integer;
lParam1, lParam2: Integer;
begin
while MediaEvent.GetEvent(evCode, lParam1, lParam2, 0)=S_OKdo
begin
MediaEvent.FreeEventParams(evCode, lParam1, lParam2);
if evCode=EC_Complete then
begin
VideoWindow.put_Visible(False);
VideoWindow.put_Owner(0);
VideoWindow:=nil;
MediaEvent:=nil;
MediaControl:=nil;
Graph:=nil;
Exit
end
end
end;
end.
1.时间通知系统是怎样工作的.
DS程序在工作的时候,filter的状态会发生改变.例如被暂停,出现错误等等.此时,filter都会发送一个事件.一个时间由三部分
构成:
a.事件代码:表明事件的类型.
b.两个参数:表明一些附加信息.(与具体事件类型有关)
Filter graph manager会在内部处理一些事件而不通知应用程序,比如要求重绘视频窗体的事件.而有些事件,会被他送到
事件队列,应用程序可以得到和处理他们.DS处理事件的方法与Windows处理消息的非常类似.实际上,我们可以让filter graph
manager在有新事件发生时送一个消息到特定的窗体.这样一来,应用程序就可以在消息循环中处理DS的事件了.
应用程序可能要处理许许多多的事件,在我们的例子中,只关心EC_Complete事件.(他在数据流结束是被产生)
2.运用事件机制.
例子程序中用了对我们自定义的消息WM_GraphNotity作出了响应.
const
WM_GraphNotify = WM_App+1;
接下来,设置响应该消息的窗体
MediaEvent.SetNotifyWindow(Handle, WM_GraphNotify, 0);
IMediaEventEx.SetNotifyWindow有三个参数:第一个是确定哪个窗体将得到消息,第二个是传递什么消息.第三个无所谓.
该方法要在MediaControl.Run之前调用.
当应用程序收到WM_GraphNotify时,消息的lParam等于SetNotifyWindow中的第三个参数.消息的wParam总等于0.
在程序中,我们可以在Application的OnMessage中响应WM_GraphNotify,但我推荐编写一个消息响应方法:
procedure WMGraphNotify(var Msg: TMessage);
message WM_GraphNotify;
整个事件的发生序列如下:
1.Filter传送事件到filter graph manager
2.如果filter graph manager不处理该事件,则将他放入事件序列
3.Filter graph manager向应用程序发送WM_GraphNotify消息
4.应用程序响应这个消息
5.应用程序从事件队列中得到具体事件.
在WM_GraphNotify的响应处理中,用MediaEvent.GetEvent来从事件队列中的到事件(包括事件代码和两个参数).最后一个参数
是将等待多长时间,由于我们在WM_GraphiNotify之后才调用他,所以设为0(队列中肯定有事件)
由于消息和事件是异步的,所以安排了一个while循环一次将事件队列中的所有事件取出.取出后,用FreeEventParams释放也
是必要的.
例子程序中,只对EC_Complete做出响应(您可以自由发挥).
Source Code:
unit Main;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ExtCtrls, DirectShow, ActiveX;
const
WM_GraphNotify = WM_App+1;
type
TMainForm = class(TForm)
Panel: TPanel;
Button: TButton;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure ButtonClick(Sender: TObject);
private
{ Private declarations }
procedure WMGraphNotify(var Msg: TMessage);
message WM_GraphNotify;
public
{ Public declarations }
Graph: IGraphBuilder;
VideoWindow: IVideoWindow;
MediaControl: IMediaControl;
MediaEvent: IMediaEventEx;
end;
var
MainForm: TMainForm;
implementation
{$R *.DFM}
{ TMainForm }
procedure TMainForm.FormCreate(Sender: TObject);
begin
CoInitialize(nil)
end;
procedure TMainForm.FormDestroy(Sender: TObject);
begin
CoUninitialize
end;
procedure TMainForm.ButtonClick(Sender: TObject);
begin
CoCreateInstance(CLSID_FilterGraph, nil, CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, Graph);
Graph.RenderFile('c:/program files/borland/delphi5/demos/coolstuf/speedis.avi',
nil);
Graph.QueryInterface(IID_IVideoWindow, VideoWindow);
VideoWindow.put_Owner(Panel.Handle);
VideoWindow.put_WindowStyle(WS_Child or WS_Clipsiblings);
VideoWindow.SetWindowPosition(0, 0, Panel.Width, Panel.Height);
Graph.QueryInterface(IID_IMediaEventEx, MediaEvent);
MediaEvent.SetNotifyWindow(Handle, WM_GraphNotify, 0);
Graph.QueryInterface(IID_IMediaControl, MediaControl);
MediaControl.Run
end;
procedure TMainForm.WMGraphNotify(var Msg: TMessage);
var
evCode: Integer;
lParam1, lParam2: Integer;
begin
while MediaEvent.GetEvent(evCode, lParam1, lParam2, 0)=S_OKdo
begin
MediaEvent.FreeEventParams(evCode, lParam1, lParam2);
if evCode=EC_Complete then
begin
VideoWindow.put_Visible(False);
VideoWindow.put_Owner(0);
VideoWindow:=nil;
MediaEvent:=nil;
MediaControl:=nil;
Graph:=nil;
Exit
end
end
end;
end.