Monday, July 23, 2007

Video Rendering_Event Notification

About Video Rendering in DirectShow :

DirectShow provides several filters that render video:
Video Renderer filter.
This filter is available for all platforms that support DirectX, and has no particular system requirements. The Video Renderer uses DirectDraw whenever possible to render the video; otherwise, it uses GDI. This filter is the default video renderer on platforms earlier than Windows XP.

Video Mixing Renderer Filter 7 (VMR-7).
The VMR-7 is available on Windows XP, where it is the default video renderer. The VMR-7 always uses DirectDraw 7 for rendering. It provides many powerful features not available in the older Video Renderer filter, including a plug-in model where the application controls the DirectDraw surfaces used for rendering.
Video Mixing Renderer Filter 9 (VMR-9). The VMR-9 is a newer version of the Video Mixing Renderer that uses Direct3D 9 for rendering. It is available for all platforms that support DirectX. It is not the default renderer, however, because it has higher system requirements than the Video Renderer filter.

Windowed Mode and Windowless Mode
A DirectShow video renderer can operate in either windowed mode or windowless mode.In windowed mode, the renderer creates its own window to display the video. Typically you will make this window the child of an application window.
In windowless mode, the renderer draws the video directly onto an application window. It does not create its own window. For more information about this mode


Responding to Events :

While a DirectShow application is running, events can occur within the filter graph. For example, a filter might encounter a streaming error. Filters alert the Filter Graph Manager by sending events, which consist of an event code and two event parameters. The event code indicates the type of event, and the event parameters supply additional information. The meaning of the parameters depends on the event code
three events that are very common:
The EC_COMPLETE event indicates that playback has completed normally.
The EC_USERABORT event indicates that the user has interrupted playback. Video renderers send this event if the user closes the video window.
The EC_ERRORABORT event indicates that an error has caused playback to halt.

Using Event Notification :

An application can instruct the Filter Graph Manager to send a Windows message to a designated window whenever a new event occurs.
For Example, if the user closes the window , then the playback must be closed and COM objects must be released.So From Windows application to
Filtergraph manager, we can pass the message.
//Defining new WIndows message
#define WM_GRAPHNOTIFY WM_APP + 1


Next, query the Filter Graph Manager for the IMediaEventEx interface and call the IMediaEventEx::SetNotifyWindow method:
IMediaEventEx *g_pEvent = NULL;
g_pGraph->QueryInterface(IID_IMediaEventEx, (void **)&g_pEvent);
g_pEvent->SetNotifyWindow((OAHWND)g_hwnd, WM_GRAPHNOTIFY, 0);

This method designates the specified window (g_hwnd) as the recipient of the message. Call the method after you create the filter graph, but before running the graph.
WM_GRAPHNOTIFY is an ordinary Windows message. Whenever the Filter Graph Manager puts a new event on the event queue, it posts a WM_GRAPHNOTIFY message to the designated application window. The message's lParam parameter is equal to the third parameter in SetNotifyWindow. This parameter enables you to send instance data with the message. The window message's wParam parameter is always zero.

In your application's WindowProc function, add a case statement for the WM_GRAPHNOTIFY message:
case WM_GRAPHNOTIFY:
HandleGraphEvent();
break;


In the event handler function, call the IMediaEvent::GetEvent method to retrieve events from the queue:

I have to implement this calls in VideoQualityClient GUI application.

void HandleGraphEvent()
{
// Disregard if we don't have an IMediaEventEx pointer.
if (g_pEvent == NULL)
{
return;
}
// Get all the events
long evCode, param1, param2;
HRESULT hr;
while (SUCCEEDED(g_pEvent->GetEvent(&evCode, ¶m1, ¶m2, 0)))
{
g_pEvent->FreeEventParams(evCode, param1, param2);
switch (evCode)
{
case EC_COMPLETE: // Fall through.
case EC_USERABORT: // Fall through.
case EC_ERRORABORT:
CleanUp();
PostQuitMessage(0);
return;
}
}
}

Add the Filter By class ID :

HRESULT AddFilterByCLSID(
IGraphBuilder *pGraph, // Pointer to the Filter Graph Manager.
const GUID& clsid, // CLSID of the filter to create.
LPCWSTR wszName, // A name for the filter.
IBaseFilter **ppF) // Receives a pointer to the filter.
{
if (!pGraph || ! ppF) return E_POINTER;
*ppF = 0;
IBaseFilter *pF = 0;
HRESULT hr = CoCreateInstance(clsid, 0, CLSCTX_INPROC_SERVER,
IID_IBaseFilter, reinterpret_cast(&pF));
if (SUCCEEDED(hr))
{
hr = pGraph->AddFilter(pF, wszName);
if (SUCCEEDED(hr))
*ppF = pF;
else
pF->Release();
}
return hr;

No comments: