1

我有一个在 Google 中似乎很常见的问题,但对我没有帮助。当我的应用程序试图关闭所有内容时,释放对象之前调用的最后一个函数是 IMediaControl::stop。有信号时一切正常。但是当我在没有信号的情况下启动应用程序(或在应用程序工作时终止它)程序永远不会从 stop() 返回。更重要的是,如果我在信号已经挂起时提供信号,一切都会恢复正常,程序会取消挂起并正确退出。

这是我的主要代码的一部分:

hr = connectFilters(pGraph, pCaptureDevice, AUDIO_INPUT_DEVICE_PIN_NAME,
pAnalyzerFilter, SPDIF_ANAL_FILTER_PIN_NAME);
if(SUCCEEDED(hr))
{
    // run the graph
    hr = pControl->Run();
    if(SUCCEEDED(hr))
    {        
        // wait for UI thread to finish
        pFilterObject->WaitForThread();

        // stop the graph and exit
        pControl->Stop();
    }
}

releaseObjects();
return 0;

谷歌建议死锁(确实是这样)是由一些线程相互等待引起的。UI线程似乎不是问题,因为我在没有Window的情况下基于这个应用程序做了一个DLL,问题是一样的。

非常感谢提前,

编辑

我只有两个过滤器:源和转换。问题肯定在变换过滤器中,因为没有它程序运行良好。可能是某处未释放缓冲区或样本的问题吗?我不知道 DirectShow 是如何工作的,但是如果没有信号,可能需要做一些额外的事情?

编辑 2

我在 Google 中发现有人通过在停止图表之前停止源过滤器解决了这个问题。我做了同样的事情,它也挂起......我用它来获取源过滤器:

hr = pFG2->AddSourceFilterForMoniker(pMoniker, pContext, wszName, &pSource);
*ppF = pSource;
(*ppF)->AddRef();

当我附加 VS 调试器时,它说它无法显示代码,所以我认为它在 MS 代码中的某个地方。即使我评论我的函数处理 IMediaSamples 它仍然挂起。现在我已经没有什么想法了。我还尝试以不同的方式从图表中停止和删除过滤器。

4

1 回答 1

1

尝试将传入图像从后台线程发送到 WPF 窗口时,我遇到了同样的问题。一切都很好,直到我试图停止媒体控制或释放任何东西。

问题在于调度程序调用操作以将其发送到 UI 线程。我暂时注释掉了这个电话,这使视频完全没有出现在屏幕上,但我可以随时在采样器中中断,看到它实际上仍在运行。

需要在线程之间手动分离图像。泛型函数中的某些东西保持引用,所以 com 对象

为了解决这个问题,我在窗口中创建了一个 dispatchertimer,将其间隔设置为 1ms,将其回调到执行 UI 更新的函数,然后在抓取器中,让 buffercb 事件将帧保存到独立变量并启用计时器.

以下是我最终得到的简要介绍:

    InteropBitmap newbmp;
    DispatcherTimer refreshTimer;
    refreshTimer = new DispatcherTimer(TimeSpan.FromMilliseconds(1), DispatcherPriority.Render, ontimer, this.Dispatcher);
    videoSampleCB.newframearrived += capGrabber_NewFrameArrived;

    void capGrabber_NewFrameArrived(object sender, EventArgs e)
    {
        newbmp = videoSampleCB.newimage;
        refreshTimer.IsEnabled = true;
    }
    void ontimerobject sender, EventArgs e)
    {
        this.BitmapSource = newbmp;
        refreshTimer.IsEnabled = false;
    }
class VideoSampleGrabberCallBack : ISampleGrabberCB  
{
        event eventhandler newframearrived;

        public InteropImage newimage;
        public int BufferCB(double sampleTime, IntPtr buffer, int bufferLen)
        {
             newimage = ...
             newframearrived(this, eventargs.empty);
        }
}
于 2015-10-22T16:07:51.623 回答