2

我正在努力在 C# dll 中实现 directshow 功能。我的工作基于 Microsoft 随 Windows Mobile 6 sdk 提供的基于 C++ 的“CameraCapture”示例。事情进展顺利(多亏了这个网站上的早期帮助),但我在尝试在 C# 领域监听 directshow 事件时遇到了一些障碍:

我有一个循环来监听 dshow 事件的线程。它基于在此处定义的手动重置事件等待(这是在图初始化结束时定义的:构建图,调用渲染流,并且控制流已经阻塞数据流):

DshowRequestMan = new ManualResetEvent(false);
MediaEvent = (IMediaEvent)FilterGraph;                
chk(MediaEvent.GetEventHandle(out DshowEventHandle));
DshowRequestMan.Handle = DshowEventHandle; //note: no "SafeHandle" in cf

我遇到了两个相关的问题:

  1. 当我的 dshow 事件处理程序循环使用超时时间 0 通过IMediaEvent.GetEvent()拉事件时,我在第三次迭代中得到“超时超时”hresult (-2147467260)。在 C++ 示例中不会发生第三个事件触发器(以及后续错误)。
  2. 如果我忽略上面提到的超时情况,它将不断触发 73 事件。这会杀死处理器,因为循环基本上从不暂停。

当 C++ 示例在预览模式下运行它的图形时,它会获得两个 IMediaEvent:第一个是 13,然后是 73。之后,它会停止触发,直到开始实际捕获。我的 C# 版本拉 13,然后是 73,然后又是 73,但出现超时错误。

简而言之,似乎不应该发生 DshowRequestMan 的第三次触发,因为没有实际“获取”的 dshowevent,因此超时。

不知道我做错了什么 - 我在每次迭代时都调用“FreeEventParams()”......我怀疑 ManualResetEvent 对象的使用不正确,因为我只是为其句柄属性分配了一些东西,但同样当我使用 Pinvoked "WaitForSingleObject" 来收听 DshowEventHandle 时,事情就会发生......我现在很困惑。

任何想法将不胜感激。提前致谢!

4

3 回答 3

2

这是我的过滤图事件处理代码:

while (!_stopReceivingEvents) {
    IntPtr eventHandle;
    var hr = _mediaEvent.GetEventHandle(out eventHandle);
    DsError.ThrowExceptionForHR(hr);

    //NOTE: Do not close the event handle, because it is used internally by the filter graph
    using (var safeWaitHandle = new SafeWaitHandle(eventHandle, false)) {
        using (var waitHandle = new AutoResetEvent(false) {SafeWaitHandle = safeWaitHandle}) {
            if (WaitHandle.WaitAll(new[] {waitHandle}, 500)) {
                //receive all available events
                do {
                    EventCode eventCode;
                    IntPtr param1;
                    IntPtr param2;
                    hr = _mediaEvent.GetEvent(out eventCode, out param1, out param2, 500);
                    _mediaEvent.FreeEventParams(eventCode, param1, param2);

                    if (hr == 0) {
                        switch (eventCode) {
                            //add handling code here
                        }
                    }
                } while (hr == 0);
            }
        }
    }
}
于 2011-08-10T11:11:47.637 回答
0

你的实际等待代码是什么样的?问题很可能是你在等待0ms,这基本上意味着“检查事件并立即返回”。如果您希望它在等待时阻塞(例如使用 WAIT_INFINITE 的本机调用),您需要传入 System.Threading.Timeout.Infinite(实际上是 -1)。

如果您希望检查线程定期产生(这比无限等待更安全,并且实际上会允许您的应用程序关闭),那么您需要检查等待的返回,如果它是超时(0x80004004)然后只是返回并再次等待:

while(!shutdown)
{
  if(DshowRequestMan.WaitOne(1000))
  {
    // handle the event
  }
}
于 2009-09-09T12:55:42.233 回答
0

您是否确保在获取并处理事件后重置您的事件?

于 2009-06-30T23:29:29.237 回答