【问题标题】:DirectShow filter graph never completes on some machinesDirectShow 过滤器图在某些机器上永远不会完成
【发布时间】:2013-08-15 17:11:54
【问题描述】:

我正在制作 DirectShow 过滤器图以从视频文件中检索 IMediaSample。不久前,我们从合同开发人员那里收到了最初的实现,我一直在拼命想弄清楚为什么这段代码在我的开发机器上运行,但在我拥有的另外两台测试服务器上却不行。

尽我所能告诉过滤器图永远不会在“坏”机器上完成。我总是从IMediaEvent->WaitForCompletion() 电话中收到E_ABORT。然而,在“工作”机器上,此调用通常在大约两个循环后返回 S_OK

更新: DirectShow Spy 似乎对我不起作用。也许那是因为我们有一个自定义的、未注册的CTransInPlaceFilter 来收集链中的IMediaSample?没有错误,但 GraphEdit 和 GraphStudio 在尝试连接到远程图形时都会挂起。

使用GraphStudio,我能够从连接到CTransInPlaceFilter 的MPEG-4 解码器中获取媒体子类型。在我的机器上是MEDIASUBTYPE_YV12,但在“损坏”的机器上是MEDIASUBTYPE_IYUV。在我们的CTransInPlaceFilterCheckInputType 方法中,我们只接受MEDIASUBTYPE_RGB24,这让我相信图中插入了一个或多个“魔法过滤器”。

更新:感谢 Roman R。我能够让 DirectShow Spy 正常工作。至少在“坏掉”的机器上。在“工作”的机器上,我遇到了访问冲突,但过滤器图运行很快并且被拆除,因此很难连接到它。

我还发现我们有一个色彩空间转换器,它能够处理MEDIASUBTYPE_IYUV in MEDIASUBTYPE_RGB24 out。我将它添加到图表中,现在应该是正确的。

DirectShow Spy 将此显示为过滤器图(对我来说看起来很完整):

文件源 -> MPEG Demux -> MPEG4 解码器 -> 颜色空间转换器 -> CTransInPlaceFilter -> 空渲染

但是 IMediaEvent->WaitForCompletion() 调用永远不会返回 S_OK 并且过滤器图只会永远运行。所以现在我对发生了什么感到困惑。还有什么我应该检查错误状态或什么的吗?

更新:我修改了循环以枚举图中的过滤器并查询它们的状态:

char debugString[512];

int count = 0;
long EvCode;
mediaFilter->SetSyncSource(NULL);
hr = mediaControl->Run();

sprintf(debugString, "mediaControl->Run() %d", hr);
DebugLog(debugString);

while (!m_ThreadKill)
{
    hr = mediaEvent->WaitForCompletion(200, &EvCode);

    sprintf(debugString, "mediaEvent->WaitForCompletion() %d, %d", hr, count);
    DebugLog(debugString);
    count++;

    IEnumFilters *pEnum = NULL;
    IBaseFilter *pFilter;
    ULONG cFetched;

    graphBuilder->EnumFilters(&pEnum);

    while(pEnum->Next(1, &pFilter, &cFetched) == S_OK)
    {
        FILTER_INFO FilterInfo;
        FILTER_STATE FilterState;

        char szName[256];

        pFilter->GetState(200, &FilterState);
        pFilter->QueryFilterInfo(&FilterInfo);
        WideCharToMultiByte(CP_ACP, 0, FilterInfo.achName, -1, szName, 256, 0, 0);

        sprintf(debugString, "Filter: %s, %d", szName, FilterState);

        DebugLog(debugString);

        SAFE_RELEASE(FilterInfo.pGraph);
        SAFE_RELEASE(pFilter);
    }

    SAFE_RELEASE(pEnum);

    if (hr == S_OK)
    {
        break;
    }
}

sprintf(debugString, "mediaControl->Stop()");
DebugLog(debugString);

mediaControl->Stop();

它们都处于“运行”状态。那么,如果过滤器连接正确并且所有过滤器都在运行,为什么图表永远不会在“损坏”的机器上完成?

更新: 正如 Roman R 所建议的那样。我从损坏机器上的过滤器图中删除了我们的 CTransInPlaceFilter,并且该图成功完成。连接CTransInPlaceFilter 后,CPU 使用率降至零。所以现在我不确定为什么下面的代码适用于某些机器而不适用于其他机器。我将开始向CTransInPlaceFilter 添加一些调试日志,以尝试找出发生了什么(或没有发生)。


解决方案: 正如 Roman R. 所建议的那样(我觉得我在重复自己:P)问题最终陷入僵局。损坏的机器都有一个 CPU/核心,而工作机器有多个 CPU/核心。该应用程序由每个源视频一个线程、一个合并线程和一个目标线程组成。

源线程运行一个过滤器图(我假设过滤器图也在它自己的线程中运行)以从IMediaSample 检索数据并将其放入CQueue<BYTE*>

合并线程循环遍历源,从源 CQueue<BYTE*> 检索样本数据,将帧合并为单个图像,并将它们发送到目标线程使用的 CQueue<BYTE*>

目标线程运行另一个过滤器图来编码视频/音频。

CQueue<BYTE*> 在 Put 上阻塞,直到有可用空间。通常这很好,因为合并线程正在删除项目。然而,在单 CPU/核心机器上,合并线程被源线程阻塞。

长话短说Sleep(0); 在这里和那里允许源线程让步给合并线程,问题似乎已经解决。

【问题讨论】:

  • 代码 sn-p 不太可能与问题相关。您需要确保首先成功创建过滤器图。然后,在运行图之前,您需要检查它的有效拓扑以查看里面的内容。在此步骤中,您可能会看到系统之间的差异。然后您将看到是什么导致流式传输不完整。
  • 如果你看到你的图表,那么 spy 确实有效。但是,如果您在流式传输过程中不泵送窗口消息,则间谍和图形远程处理工具将冻结 - 所以这更多的是您的代码问题(当然不是致命的,但无论如何消息泵送是个好主意)。

标签: c++ visual-c++ directshow


【解决方案1】:

播放完成在内部包括从流源发送流结束通知,这些通知由下游过滤器中继,在渲染器上收集,然后组合起来报告给应用程序。因此,成功完成取决于过滤图的所有参与者都正确行事。

您发现了图的拓扑,并且需要比较不同机器上的拓扑。如果您在那里看到任何差异,他们可能会建议哪个过滤器可能会丢失完成通知。

但是,即使拓扑准确匹配,某些过滤器也可能由于其他原因而采取不同的行动。特别是,在图表上拥有自己的自定义过滤器很可能会丢失通知并且图表永远不会完成。它停止处理数据并从那里闲置(这是您要检查的另一件事 - CPU 消耗是否降至零或仍在进行某些处理,在这种情况下,您可以将问题重新定性为死锁)。

您可以或多或少轻松解决此问题的方法是开始从图表中删除过滤器,以识别正是哪个过滤器带来了问题。尝试这些图表可能会发现问题:

File Source -> MPEG Demux -> MPEG4 Decoder -> Color Space Converter -> Null Render
File Source -> MPEG Demux -> MPEG4 Decoder -> Null Render
File Source -> MPEG Demux -> Null Render

【讨论】:

  • 好的,这让我在某个地方。我从图中删除了我们的 CTransInPlaceFilter 并成功完成。仍然不确定为什么过滤器可以在某些机器上工作,但不能在其他机器上工作。问题更新了更多细节。
  • 您需要在此过滤器上检查 IPin::EndOfStream 周围的内容。那里出了点问题。
  • 据我所知,他没有在任何地方实现IPin::EndOfStream,只是依赖于基础。但是我认为您可能会对死锁有所了解,因为我只看到 CTransInPlaceFilter::Transform 方法被调用了四次,然后它就停止了。在我的工作机器上,我看到了调用与帧数相关的适当次数的方法。
【解决方案2】:

不看整个事情很难说。我在开发 DS 过滤器时,大量使用了 GraphStudio 和 FilterGraph Spy

一个常见的错误是使用目标机器上可能不可用的“自动过滤器”。假设您的视频是 h264 并且您尝试从中读取原始 RGB,DS 将自动为您提供解码器过滤器和色彩空间转换。将生成许多中间过滤器,而您不会从代码中注意到它。这就是为什么将图形转储到可视化工具中并检查所有连接方式非常重要的原因。

我的猜测是您的部署服务器上不存在这些“魔法过滤器”中的一个或多个。您可以尝试直接在服务器上使用 GraphStudio,并像以编程方式执行的所有操作一样连接所有内容,然后从那里查看失败的原因和原因。

【讨论】:

  • 感谢您的提示。我会看看这些工具,看看我能找到什么。
猜你喜欢
  • 2010-12-29
  • 1970-01-01
  • 2016-07-13
  • 1970-01-01
  • 1970-01-01
  • 2017-01-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多