科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件DirectShow入门之Directshow的基本技巧

DirectShow入门之Directshow的基本技巧

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

本文主要讲述了Directshow开发的一些基本概念和技巧。

作者:智慧的鱼 来源:天极开发 2007年10月16日

关键字:

  • 评论
  • 分享微博
  • 分享邮件
处理窗口消息

  因为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;
    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章