这个真的让我把头发拉出来。我编写了一个派生自CTransformFilter的DirectShow变换过滤器。我从CTransformInputPin派生了一个输入引脚。当我的输入引脚的Receive方法被调用时,它会将IMediaSample的显示时间记录到文件中。这一切都正常,直到我停止图表并再次启动它(我正在使用MS的图形)。大多数时候,再次跑步,没有问题。但是,在我停止然后再次运行图表的大约十几次中,开始呈现时间是负面的。当图表运行时,它最终增加到零并且高于零,但它从不赶上流时间,结果是流时间仍然是每个样本的显示开始时间的主要时间。
我用Logitech Webcam Pro 9000和Logitech C600相机观察到这一点,但没有使用Winbook相机,所以我想知道这是否是Logitech问题。停止运行后,有没有其他人在视频IMediaSamples上看到负面的演示时间? (我查看了IMediaSample中的preroll标志:它总是S_FALSE。)
更新
我用这个覆盖了CTransformFilter(实际上是CBaseFilter的)Run方法:
STDMETHODIMP MyTransformFilter::Run(REFERENCE_TIME tStart)
{
char buff[1000];
REFERENCE_TIME rTime;
m_pClock->GetTime(&rTime);
sprintf(buff, "Run tstart = %lld, rTime = %lld", tStart, rTime);
Trace(buff); // open my log file, add buff, close my log file
return CTransformFilter::Run(tStart);
}
我使用graphedt启动图表,运行10秒,暂停5秒,然后重新开始。这是输出:
Run tstart = 7855978550000, rTime = 7855978450000
Run tstart = 7856030610000, rTime = 7856126960000
传递给Run的两次相差5.2秒(大约是我暂停的时间)。两个参考时钟时间相差14.6秒(大约是调用Run之间的总时间)。除了稍微增加之外,过滤器图形管理器增加了传递给Run的时间(10 mS,在第一次调用中),我希望每次调用Run时它们几乎相同。相反,在第二次调用时传递给Run的时间比参考时钟晚了大约10秒。我非常感谢帮助理解为什么在第二次调用中传递给Run的时间与第二次调用时参考时钟返回的时间不同(几乎)相同。
更新2:
问题似乎出现在Logitech 13.31.1044.0版驱动程序中。见下面的答案。
答案 0 :(得分:3)
负面时间不是什么大问题。基本上它意味着“媒体样本应该在不久前提出”。那么您可能会认为媒体样本可能会被丢弃?有时这是真实的,有时它不是:想象一系列时间压缩的视频帧,其中关键帧后跟10个delta帧。您希望演示文稿从第5帧开始,您怎么做?您必须从关键帧推进,以便解码器可以从拼接点有效解码,否则它不能以delta帧开始。无论帧是否迟到,解码器都可以传送输出帧,这就是这些帧最终到达你的方式。
导致负时间的另一种情况是由线程,流和控制的竞争条件引起的。捕获线程可能正在开始其操作,但手上没有基本的“开始时间”。
答案 1 :(得分:1)
经过相当多的实验,我得出结论,问题很可能是Logitech 13.31.1044.0相机驱动程序特有的。使用早期的Logitech 12.10.1110驱动程序,Winbook DC-6120相机(及其驱动程序)和Chicony USB 2.0相机(及其驱动程序),我无法重复出现问题。由于没有明显的原因,Logitech 13驱动程序将以大约十分之一左右的时间从负表示时间开始提供样本,包括它的图表重新启动(也就是说,在我将其停在graphedt中然后再次启动它之后) )。将这些时间与流时间进行比较并不提供MSDN描述的样本是否被安排在过去,现在或将来显示,因为流时间似乎不受影响。每次重新启动时,无论相机的演示时间何时开始,流时间都会从零开始,如同人们所期望的那样。 (请注意,Logitech是以RGB24子类型进行流式传输,没有压缩帧。)
我正在开发一个多线程传递过滤器,它可以根据流时间重新分配显示时间,并且足够快地“伪造”正确的值,如果我在这里发布获得有意义的结果。此外,我将记录我的测试并将其传达给Logitech。如果他们回复,我也会在这里发布。
如果其他人正在使用使用上述驱动程序的Logitech产品(或以其他方式观察我所述的行为),请在此处发表评论。我很高兴向您发送我的过滤器副本,该过滤器记录时间,帧等。我们或许能够共同努力寻找解决这个问题的好方法。
<强>更新强>
通过编写尽可能最简单的Tranform过滤器(简单地将输入IMediaSample的负图像复制到输出中),我已经能够相当一致地重现这种行为。我每五到六次中就会重新启动一个由Camera-&gt; Filter-&gt; Renderer组成的图表,前几个样本的交付时间为负帧时间,这些时间落后于流时间,而且从未赶上。 (也就是说,流时间永远保持在样本的呈现时间之前)。同样,这种情况不会发生在其他相机上,也不会发生在较旧的Logitech驱动程序上。
这是有趣的部分:如果我在过滤器的Run方法中添加一些延迟(在重写CTransformFilter :: Run之后),问题就会消失。这是代码:
STDMETHODIMP DLPassThrough::Run(REFERENCE_TIME tStart)
{
Sleep(10);
return CTransformFilter::Run(tStart);
}
我可以通过评论或恢复“Sleep(10)”电话来解决问题。我可以猜到的是,摄像机代码是多线程的,需要一段时间在“暂停”调用之间,该调用始终位于“运行”调用之前,并且需要在下一次“运行”调用之间调用,以清理它正在执行的操作。据我了解MSDN文档,图形管理器将在渲染器上调用“暂停”,然后调用我的过滤器,然后是相机,然后返回并在渲染器,我的过滤器和摄像头上调用“运行”。我相信这些调用都是同步的,但是如果摄像头代码是多线程的,那么当调用其“Run”方法时,它可能仍在处理来自图形管理器的最新“暂停”调用。通过向我的过滤器的“运行”方法添加延迟,最近的“暂停”呼叫到摄像机和下一次“运行”呼叫到摄像机之间会有较长的延迟。
仍在等待/希望听到Logitech对此的回复。同时,我确实编写了一个多线程的现场转换过滤器,它只是添加对它获得的最新样本的引用,用当前流时间替换它的呈现时间,保存它以供下游过滤器在下次下游时使用过滤器已准备好接收它,然后返回等待下一个传入的样本。 (如果在下游过滤器之前有多个样本进入,则前一个样本将被释放,并替换为最新样本。)到目前为止似乎正在运行。
更新2
这是罗技的回答:
我想通知您,该设备主要用于视频流的IM应用程序,而不是开发软件或过滤器的主题。