我正在研究 DirectShow 过滤器图以IMediaSample
从视频文件中检索。不久前,我们从合同开发人员那里收到了最初的实现,我一直在努力想弄清楚为什么这段代码可以在我的开发机器上运行,但不能在我拥有的另外两台测试服务器上运行。
尽我所能告诉过滤器图永远不会在“损坏”的机器上完成。我总是接到E_ABORT
电话IMediaEvent->WaitForCompletion()
。然而,在“工作”机器上,这个调用通常S_OK
在大约两个循环后返回。
更新: DirectShow Spy似乎对我不起作用。也许那是因为我们有一个未注册的习惯(<--正如建议的消息抽水解决了这个问题)CTransInPlaceFilter
来收集IMediaSample
链中的?没有错误,但 GraphEdit 和 GraphStudio 在尝试连接到远程图形时都会挂起。
使用GraphStudio,我能够从连接到我们的CTransInPlaceFilter
. 在我的机器上它是MEDIASUBTYPE_YV12
,但在“坏”机器上它是MEDIASUBTYPE_IYUV
. 在我们的CheckInputType
方法中,CTransInPlaceFilter
我们只接受MEDIASUBTYPE_RGB24
这让我相信有一个或多个“魔法过滤器”被插入到图中。
更新:感谢 Roman R。我能够让DirectShow Spy工作。至少在“坏掉”的机器上。在“工作”的机器上,我遇到了访问冲突,但过滤器图运行很快并且被拆除,因此很难连接到它。
我还发现我们有一个能够处理MEDIASUBTYPE_IYUV
输入MEDIASUBTYPE_RGB24
输出的色彩空间转换器。我将其添加到图表中,现在应该是正确的。
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/核心。该应用程序由每个源视频的线程、合并线程和目标线程组成。
源线程运行一个过滤器图(我假设过滤器图也在它自己的线程中运行)以从 an 检索数据IMediaSample
并将其放入CQueue<BYTE*>
.
合并线程遍历源,从源检索样本数据CQueue<BYTE*>
,将帧合并为单个图像,并将它们发送到CQueue<BYTE*>
目标线程消耗。
目标线程运行另一个过滤器图来编码视频/音频。
Put 上的CQueue<BYTE*>
块,直到有可用空间。通常这很好,因为合并线程正在删除项目。然而,在单个 CPU/核心机器上,合并线程被源线程阻塞。
长话短说,Sleep(0);
这里和那里允许源线程屈服于合并线程,问题似乎得到了解决。