DirectShow筛选器图形在某些计算机上永远不会完成
DirectShow filter graph never completes on some machines
我正在使用DirectShow过滤器图从视频文件中检索IMediaSample
。不久前,我们从一位合同开发人员那里收到了最初的实现,我一直在绞尽脑汁,试图弄清楚为什么这些代码在我的开发机器上有效,而在我的另外两个测试服务器上却无效。
我所能告诉你的是,在"坏"的机器上,过滤图永远不会完成。我总是从IMediaEvent->WaitForCompletion()
呼叫接收E_ABORT
。然而,在"工作"机器上,此调用通常在大约两个循环后返回S_OK
。
更新:
DirectShow Spy似乎不适合我。也许这是因为我们有一个自定义的、未注册的(<--正如建议的消息泵送解决了这个问题)CTransInPlaceFilter
来收集链中的IMediaSample
?没有错误,但GraphEdit和GraphStudio在尝试连接到远程图形时都挂起了
使用GraphStudio,我能够从连接到我们的CTransInPlaceFilter
的MPEG-4解码器中获得媒体子类型。在我的机器上是MEDIASUBTYPE_YV12
,但在"坏"的机器上却是MEDIASUBTYPE_IYUV
。在CTransInPlaceFilter
的CheckInputType
方法中,我们只接受MEDIASUBTYPE_RGB24
,这让我相信在图中插入了一个或多个"魔术过滤器"。
更新:多亏了Roman R.,我才能让DirectShow Spy正常工作。至少在"坏了"的机器上。在"工作"的机器上,我遇到了访问违规,但过滤图运行得很快,而且被破坏了,所以很难连接到它。
我还发现我们有一个颜色空间转换器,它能够在MEDIASUBTYPE_RGB24
out中处理MEDIASUBTYPE_IYUV
。我把它添加到图表中,现在应该是正确的。
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);
允许源线程向合并线程让步,问题似乎得到了解决。
内部播放完成包括从流源发送流结束通知,这些通知由下游过滤器中继,在渲染器上收集,然后合并报告给应用程序。因此,成功完成取决于过滤图的所有参与者是否正确操作。
您发现了图形的拓扑结构,需要比较不同机器上的拓扑结构。如果您看到任何差异,它们可能会提示哪个过滤器可能会丢失完成通知。
然而,即使拓扑结构精确匹配,由于其他原因,某些过滤器的作用也可能不同。特别是,在图形上拥有自己的自定义过滤器很有可能会丢失通知,并且图形永远不会完成。它停止处理数据,并从那里开始空转(这是另一件需要检查的事情——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
如果不看整件事,很难说。当我开发DS过滤器时,我经常使用GraphStudio和FilterGraph Spy。
一个常见的错误是使用目标机器上可能不可用的"自动过滤器"。假设您的视频是h264,并且您尝试从中读取原始RGB,DS将自动为您提供解码器过滤器和颜色空间变换。许多中间过滤器将在您没有从代码中注意到的情况下生成。这就是为什么在可视化工具中转储图形并检查所有内容的连接方式非常重要。
我的猜测是,部署服务器上不存在一个或多个这样的"神奇过滤器"。您可以尝试直接在服务器上使用GraphStudio,并像编程一样连接所有内容,然后查看它是如何以及为什么失败的。
- 为什么使用 P/Invoke 调用 dll 时,某些计算机中的 LoadLibrary 失败?
- EvtExportLogneneneba API正在将远程计算机的事件日志保存到远程PC本身.如何将其保存到主机
- 为什么是谷神星协方差.计算()似乎永远运行而不返回?
- 密码登录程序将永远循环并显示不正确的结果
- 我想在C++中读取一些多个字符,但它永远不会读取第二个字符
- SFML 碰撞永远不会在我的系统中注册
- 为什么我能够为阵列分配比计算机实际拥有的内存更多的内存
- 我可以使用任何好的逻辑来阻止计算机将 O 放在井字游戏中的现有 X 上
- C++ 计算机猜测用户数量在 7 次猜测以内
- C++为什么我的编译器成功了,但我的计算机给出了调试错误?
- 在 c++ 中连接字符串和整数,以便在 C++ 11 不支持计算机的情况下读取多个文件
- 先进先出:一个进程永远不会从管道读取
- 移动构造函数永远不会被调用
- 我的 SDL2 程序需要哪些二进制文件,以便它在另一台未安装 SDL2 的计算机中工作
- 将非常大的 int 转换为双倍,在某些计算机上会损失精度
- 如何在个人计算机和群集 (c++) 上生成相同的随机数
- 程序永远不会进入虚拟析构函数
- 系统错误:程序无法启动,因为您的计算机中缺少MSVCP140D.DLL。尝试重新安装该程序以解决此问题
- 预处理的 C/C++ 文件是否特定于计算机?
- Windows桌面程序保存您的计算机会话 - 基于程序崩溃时的恢复会话