当没有信号时,IMediaControl :: stop会挂起

时间:2012-08-16 09:52:10

标签: c++ directshow

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

这是我在main中的代码的一部分:

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,问题就是一样。

非常感谢,

修改

我只有两个过滤器:source和transform。问题在于转换过滤器,因为没有它,程序运行正常。这是不是在某处释放缓冲区或样本的问题?我不确切知道DirectShow的工作原理,但如果没有信号,可能需要做一些额外的事情吗?

编辑2

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

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

当我附加VS调试器时,它说它不能显示代码,所以我认为它在MS代码中的某个地方。即使我评论我的功能处理IMediaSamples它仍然挂起。现在我用完了错误的想法。我还尝试以不同的方式停止并从图表中删除过滤器。

1 个答案:

答案 0 :(得分:0)

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

问题在于调度程序调用该操作以将其移至UI线程。我暂时注释掉了这个电话,它阻止了视频在屏幕上显示,但我可以随时在samplegrabber中断,看它还在运行。

需要在线程之间手动分离图像。泛型函数中的某些东西保持引用,因此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);
        }
}