我试图与DirectShow同时播放多个图形。经过研究后,我在How to play multiple videos in sync over multiple monitors using directshow?处找到了Geraint Davies的出色解决方案
选择一个图作为主图。
确保主机有时钟。这通常在去的时候完成
活动,但您可以通过致电强制将其提前发生
图上的SetDefaultSyncSource。
查询图表中的IMediaFilter,从主时钟获取时钟
使用GetSyncSource绘制图形并将其传递给其他图形
SetSyncSource。
暂停所有图形。
等待直到GetState返回S_OK(暂停完成)。
从图表中获取时间并增加10毫秒左右。
调用IMediaFilter :: Run在所有图形上运行,经过此时间(现在+ 10ms)
作为参数。
结果证明效果不错,视频在视觉上保持同步。
但是,当我使用IMediaFilter :: Run测试时,确实让我感到困扰。
我尝试将较大的偏移值传递给IMediaFilter :: Run,例如(现在+ 1000ms),该视频似乎仍在视觉上立即开始,而不是在开始之前延迟1000ms。
这是正常现象还是我做错了什么?
编辑:谢谢您的快速答复,罗曼R。我想当您说“视频时间”时,您是指时间戳吗?我会立即检查出来。
编辑:视频不仅显示第一帧,还可以正常播放而没有任何延迟。我还发布了一些我所做的粗略代码。希望有人能对此有所启发。
CComQIPtr<IMediaFilter>pMasterF(m_pMasterGraphBuilder);
CComQIPtr<IMediaFilter>pSlaveF(m_pSlaveGraphBuilder);
IReferenceClock* pClock;
HRESULT clkHR = pMasterF->GetSyncSource(&pClock); // Get Master Clock
pSlaveF->SetSyncSource(pClock); //Set slave to Master Clock
pMasterF->Pause(); //Pause Master
pSlaveF->Pause(); // Pause slave
FILTER_STATE sFs;
HRESULT hrcue;
hrcue = pMasterF->GetState(0, &sFs);
while(hrcue == VFW_S_STATE_INTERMEDIATE) { // wait for master to cue data
hrcue = pMasterF->GetState(0, &sFs);
if (hrcue == S_OK)
break;
Sleep(5);
}
FILTER_STATE ssFs;
HRESULT hrcues;
hrcues = pSlaveF->GetState(0, &ssFs);
while(hrcues == VFW_S_STATE_INTERMEDIATE) { // wait for slave cue data
hrcue = pSlaveF->GetState(0, &ssFs);
if (hrcues == S_OK)
break;
Sleep(5);
}
REFERENCE_TIME refTime;
HRESULT timeHR = pClock->GetTime(&refTime); // get master ref time
REFERENCE_TIME temp = refTime+100000000000000; // now + offset
pMF->Run(temp); // run master
pSF->Run(temp); // run slave
如您所见,我设置了一些荒谬的偏移量。但是,我仍然看不到任何延迟。也许我把“现在”的时间弄错了?
编辑:谢谢您的回复,杰兰特。
我确实发现每个IReferenceClock :: GetTime调用(pClock-> GetTime)都给了我一个巨大的飞跃参考时间(可能是由于我给了很大的偏移量)。
那是指流时间向前跳的意思吗?
如何检查Audio Renderer是否提供时钟?
最佳答案
这可能是由您的音频渲染器引起的。如果提供时钟,它可能会立即开始播放,而忽略实际的开始时间(我已经在某些音频渲染器中看到了此问题)。然后,一旦开始运行,时钟就是您正在播放的时间。这样您将看到流时间向前跳跃。也许您可以检查一下?