Directshow 学习入门

来源:互联网 发布:ubuntu查看qt安装目录 编辑:程序博客网 时间:2024/06/05 09:24
处理窗口消息

  因为VMR没有自己的窗口,所以当视频需要重画或者改变的时候你要通知它。

  1、当你接到一个WM_PAINT消息,你就要调用IVMRWindowlessControl::RepaintVideo来重画视频

  2、当你接到一个WM_DISPLAYCHANGE消息,你就要调用IVMRWindowlessControl::DisplayModeChanged.

  3、当你接到一个WM_SIZE消息时,重新计算视频的位置,然后调用SetVideoPostion。

  下面的代码演示了WM_PAINT消息的处理:

void OnPaint(HWND hwnd) 

 PAINTSTRUCT ps; 
 HDC hdc; 
 RECT rcClient; 
 GetClientRect(hwnd, &rcClient); 
 hdc = BeginPaint(hwnd, &ps); 
 if (g_pWc != NULL) 
 { 
  // Find the region where the application can paint by subtracting 
  // the video destination rectangle from the client area.
  // (Assume that g_rcDest was calculated previously.)
  HRGN rgnClient = CreateRectRgnIndirect(&rcClient); 
  HRGN rgnVideo = CreateRectRgnIndirect(&g_rcDest); 
  CombineRgn(rgnClient, rgnClient, rgnVideo, RGN_DIFF); 

  // Paint on window.
  HBRUSH hbr = GetSysColorBrush(COLOR_BTNFACE); 
  FillRgn(hdc, rgnClient, hbr); 
  // Clean up.
  DeleteObject(hbr); 
  DeleteObject(rgnClient); 
  DeleteObject(rgnVideo); 
  // Request the VMR to paint the video.
  HRESULT hr = g_pWc->RepaintVideo(hwnd, hdc); 
 } 
 else // There is no video, so paint the whole client area. 
 { 
  FillRect(hdc, &rc2, (HBRUSH)(COLOR_BTNFACE + 1)); 
 } 
 EndPaint(hwnd, &ps); 
}
  尽管我们要自己处理onpaint消息,但是已经非常简单了。

  如何处理事件通知(Event Notification)

  当一个Directshow的应用程序运行的时候,在 filter Graph内部就会发生各种各样的事件,例如,一个filter也许发生数据流错误。Filter通过给graph mangaer发送事件通知来和graph通信,这个事件通知包括一个事件码和两个事件参数。事件码表示发生事件的类型,两个参数用来传递信息。

  Filter发送的这些事件,其中的一部分可以被Manager直接处理,不通知应用程序,但有一部分事件,Manager将事件放入到一个队列中,等待应用程序处理。这里我们主要讨论在应用程序中经常遇到的三种事件 

  EC_COMPLETE表明回放已经结束

  EC_USERABORT表明用户中断了回放。用户关闭视频播放窗口时,视频Render会发生这个事件

  EC_ERRORABORT表明出现了一个错误。

  应用程序可以通知filter graph manager,在某个指定的事件发生时,向指定的窗口发生一个指定的消息。这样应用程序就可以在消息循环中对发生的事件产生反应。

  首先定义消息:

#define WM_GRAPHNOTIFY WM_APP + 1
  然后向filter graph manager请求IMediaEventEx接口,然后调用IMediaEventEx::SetNotifyWindow方法来设置消息通知窗口:

IMediaEventEx *g_pEvent = NULL;
g_pGraph->QueryInterface(IID_IMediaEventEx, (void **)&g_pEvent);
g_pEvent->SetNotifyWindow((OAHWND)g_hwnd, WM_GRAPHNOTIFY, 0);
  然后在WindowProc函数增加一个处理WM_GRAPHNOTIFY消息的函数:

case WM_GRAPHNOTIFY:
HandleGraphEvent();
break;
  HandleGraphEvent()函数具体定义如下

void HandleGraphEvent()
{
 // Disregard if we don't have an IMediaEventEx pointer.
 if (g_pEvent == NULL)
 {
  return;
 }
 // Get all the events
 long evCode;
 LONG_PTR param1, param2;
 HRESULT hr;
 while (SUCCEEDED(g_pEvent->GetEvent(&evCode, &param1, &param2,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;
  }
 } 
}
  在释放IMediaEventEx指针前,要取消事件通知消息,代码如下:

// Disable event notification before releasing the graph.
g_pEvent->SetNotifyWindow(NULL, 0, 0);
g_pEvent->Release();
g_pEvent = NULL;
0 0
原创粉丝点击