Directshow 學習入門

處理窗口消息

  因爲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;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章