我正在使用DirectShow过滤器图来从视频文件中检索IMediaSample
。我们从合同开发人员那里收到了原来的实现,我一直在试图弄清楚为什么这个代码在我的开发机器上运行而不是在我拥有的其他两个测试服务器上。
最好我可以告诉过滤器图表永远不会在“损坏的”机器上完成。我总是从E_ABORT
电话中收到IMediaEvent->WaitForCompletion()
。但是在“工作”机器上,此调用通常在大约两个循环之后返回S_OK
。
更新: DirectShow Spy似乎对我不起作用。也许那是因为我们有一个自定义的,未注册的,(< - 正如建议的消息泵解决了这个)CTransInPlaceFilter
来收集链中的IMediaSample
?没有错误,但GraphEdit和GraphStudio在尝试连接到远程图时都会挂起。
使用GraphStudio我能够从连接到CTransInPlaceFilter
的MPEG-4解码器中获取媒体子类型。在我的机器上它是MEDIASUBTYPE_YV12
但在“损坏的”机器上它是MEDIASUBTYPE_IYUV
。在我们CheckInputType
的{{1}}方法中,我们只接受CTransInPlaceFilter
,这使我相信在图表中插入了一个或多个“魔术过滤器”。
更新:感谢Roman R.我能够让DirectShow Spy工作。至少在“破碎”的机器上。在“工作”机器上,我遇到了访问冲突,但是过滤器图表运行速度很快,并且已经拆除,因此很难连接到它。
我还发现我们有一个能够在MEDIASUBTYPE_RGB24
中处理MEDIASUBTYPE_IYUV
的色彩空间转换器。我将其添加到图表中,现在应该是正确的。
DirectShow Spy将此视为过滤器图表(看起来很完整):
File Source -> MPEG Demux -> MPEG4 Decoder -> Color Space Converter -> CTransInPlaceFilter -> Null Render
但是,MEDIASUBTYPE_RGB24
调用永远不会返回IMediaEvent->WaitForCompletion()
,并且过滤器图形只会永远运行。所以现在我很难知道发生了什么。还有什么我应该检查错误状态或什么?
更新:我修改了循环以枚举图表中的过滤器并查询其状态:
S_OK
他们都处于“正在运行”状态。因此,如果过滤器连接正确并且所有过滤器都在运行,为什么图形永远不会在“损坏的”机器上完成?
更新:正如Roman R.建议的那样,我从已损坏的计算机上的过滤器图表中删除了我们的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();
,并且图表已成功完成。连接CTransInPlaceFilter
后,CPU使用率降至零。所以现在我不确定为什么下面的代码在某些机器上运行而在其他机器上运行。我将开始向CTransInPlaceFilter
添加一些调试日志记录,以尝试找出正在发生的事情(或不继续)。
解决方案:正如Roman R.所说(我觉得我在重复自己:P)问题最终导致了僵局。破碎的机器都有一个CPU /核心,因为工作机器有多个CPU /核心。该应用程序由每个源视频,合并线程和目标线程组成。
源线程运行过滤器图形(我假设过滤器图形也在其自己的线程中运行)以从CTransInPlaceFilter
检索数据并将其放入IMediaSample
。
合并线程循环遍历源,从源CQueue<BYTE*>
检索示例数据,将帧合并为单个图像,并将它们发送到目标线程消耗的CQueue<BYTE*>
。
目标线程运行另一个过滤器图形来编码视频/音频。
Put上的CQueue<BYTE*>
块直到有空位。通常这很好,因为合并线程正在删除项目。但是在单CPU /核心机器上,合并线程被源线程阻塞。
长话短说明CQueue<BYTE*>
这里和那里允许源线程屈服于合并线程,问题似乎得到解决。
答案 0 :(得分:2)
如果不看整件事就很难说。当我开发DS过滤器时,我在很多时候使用了GraphStudio和FilterGraph Spy。
常见的错误是使用目标机器上可能无法使用的“自动过滤器”。假设您的视频是h264并且您尝试从中读取原始RGB,DS将自动为您提供解码器滤镜和色彩空间变换。将生成许多中间过滤器,而无需您从代码中注意到它。这就是为什么将图形转储到可视化工具中并检查所有内容是如何连接的非常重要的原因。
我的猜测是部署服务器上不存在一个或多个“魔术过滤器”。您可以尝试的是直接在服务器上使用GraphStudio,并以编程方式连接所有内容,并查看它从何处以及为何失败。
答案 1 :(得分:2)
内部回放完成包括从流源发送流结束通知,这些通知由下游过滤器中继,在呈现器上收集,然后组合,报告给应用程序。因此,成功完成取决于过滤器图表的所有参与者是否正确。
您发现了图形的拓扑,您需要比较不同计算机上的拓扑。如果您发现任何差异,他们可能会建议哪些过滤器可能会丢失完成通知。
但是,即使拓扑结构准确匹配,某些过滤器也可能因其他原因而采取不同的行为。特别是,在图表上拥有自己的自定义过滤器很可能会丢失通知并且图形永远不会完成。它停止处理数据并从那里闲置(这是你想要检查的另一件事 - 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