Event notification in DirectShow
This section will describe how the event is implemented in the Microsoft® DirectShow® filter table; an application can accept event notification and respond to them.
Event notification overview
Filters communicate an event to the Filter Table Manager by delivering event notifications. The event can be any information, such as the end, or an error, such as the failure of the original stream. The filter table manager itself handles some filter events, and other events remain to the application for processing. If the Filter Table Manager encounters an incomplete event, it puts the event into a queue. Similarly, the filter table manager also puts its own event notification into the queue and processes in order to apply.
Applications can receive events from the queue and respond to them. Therefore, DirectShow's event notification is very similar to the Microsoft® Windows® message queue mode. The application can cancel the filter table manager itself can handle this behavior of the event, filter table management, putting these events into the queue and processed by the application. This mechanism allows:
Filter Table Manager communicates with the application.
Filters can communicate with applications and filter table management.
Determine which events are handled by the application.
Receive event
The Filter Table Manager exposes three interfaces to the outside to support event notifications.
IMediaEventSink contains methods for filter delivery events
IMediaEvent contains methods for application reception events
IMediaeventex inherits from and extends the iMediaEvent interface.
IMediaEventex inherits and expands the ImdeiAevent interface
The filter delivers event notifications by calling the IMEDIAEventsink :: Notify method of the Filter Table Manager. An event notification consists of an event code and two DWORD type parameters. According to different event code, the parameter value may be a pointer, return code, reference time, or other information.
In order to receive events from the queue, the application should call the iMediaEvent :: getEvent method to receive data. This method is blocked until an event or exceeds the time limit from a queue. When the getEvent is called, the application should always call the iMediaEvent :: FreeEventParams method to release resources in the event parameter. For example, parameters may be the BSTR string provided by the filter table.
The following code provides a framework for accepting events from the queue.
Long Evcode, Param1, Param2;
HRESULT HR;
While (hr = pevent-> getEvent (& Evcode, & param1, & param2, 0), succeededed (hr))
{
Switch (EVCode)
{
// Call Application-Defined Functions for Each
// Type of Event this You Want to Handle.
}
HR = pevent-> freeeeventparams (Evcode, Param1, Param2);
}
In order to stop the default processing of a filter table manager for an event, you can call the iMediaEvent :: CanceldefaultHandling method. You can restore the default processing of the event by calling the iMediaEvent :: RestorefaultHandling method. For events that do not have the default processing of the Filter Table Manager, call these methods will not have any impact.
When did the event occur?
For the DirectShow event, the application needs a method that can be known when there is an event in the queue. Filter Table Manager provides two ways to achieve:
Window Notification: When a Filter Table Manager generates a new event, send a custom message to the application window.
Event signal: If there is a DirectShow event in the queue, the Filter Table Manager sends a window event. And reset the event in the queue. An Application CAN Use Either Technique. Window Notification IS Usually Simpler.
Applications can be implemented using other techniques. But window messages are usually more simple.
Window notification
You can call the iMediaEventEx :: SetNotifyWindow method to specify a private message to create a window notification. This private message can use the number from WM_APP to WM_APP 0xBFFF. As long as the filter table management is placed in a new event to the queue, it sends information to the specified application window. The application responds to messages from a Windows message loop.
The following code illustrates how to set the notification window.
#define WM_GraphNotify WM_APP 1 // Private Message.
PEVENT-> SetNotifyWindow (OAHWND) G_hwnd, WM_GraphNotify, 0);
The following code shows how to respond to the window message
LResult Callback WindowProc (HWND HWND, UINT MSG, UINT WPARAM, long lparam)
{
Switch (msg)
{
Case WM_GRAPHNOTIFY:
HandleEvent (); // application definition function.
Break;
// You can also write message processing here.
}
Return (DEFWIndowProc (HWND, MSG, WPARAM, LPARAM);
}
Because event notifications and message loops are asynchronous, there may be multiple event messages when your application responds to messages. It may sometimes become invalid, then it will be cleared. Therefore, in your event handling code, you should call the getEvent method until the failure code is returned, that is, the message queue is empty.
Note that when you release the iMediaEventEx pointer, you will first cancel event notifications by passing an empty pointer to SetNotifyWindow. In your event handling code, a must check the validity of the IMEIAEventEx pointer before calling the getEvent method. This can prevent the application that may have an error that may occur again after the iMediaEventEx pointer is released.
Signal
Filter Table Manager maintains an event of manual-reset to react the status of the event queue. If the event queue contains unresolved event notifications, filter table management will send a manual reset event. If the event is empty, call the iMediaEvent :: getEvent method to reset the event. Applications can use this event to determine the status of the queue.
Note: This language may be misunderstood. Manual reset event is an event type established by the Windows CreateEvent function, which does not do anything in DirectShow.
Call the iMediaEvent :: getEventHandle method to get the handle of the manual reset event. You can wait for this event through the WaitFormultiPleObject function. Once this event occurs, you can get the DirectShood event when you call the iMediaEvent :: getEvent method.
The following code example shows such a function. It acquires the handle of the event, waiting for the event of the event every 100 milliseconds. When the event occurs, the event is called by calling the getEvent method and the event code and event parameters are displayed. The cycle ends when the EC_COMPLETE event (which represents playback has been completed).
Handle HEVENT;
Long Evcode, Param1, Param2;
Boolean bdone = false;
HRESULT HR = S_OK; HR = pevent-> getEventHandle ((OAEvent *) & hev);
While (! bdone)
{
IF (wait_Object_0 == WaitforsingleObject (HEVENT, 100))
{
While (hr = pevent-> getEvent (& Evcode, & param1, & param2, 0), succeededed (hr))
{
Printf ("Event Code:% # 04x / N Params:% D,% D / N", EVCODE, PARAM1, PARAM2;
HR = pevent-> freeeeventparams (Evcode, Param1, Param2);
BDONE = (EC_COMPLETE == EVCODE);
}
}
}
Because the filter table will automatically set or reset the event appropriately, your application can freely processes these things. Similarly, after you release the filter table, the filter table will release the event handle. Therefore, after you release the filter table, don't use the event handle.
(to be continued...)