2

这个真的让我把头发拉出来。我编写了一个从 CTransformFilter 派生的 DirectShow 变换过滤器。我从 CTransformInputPin 派生了一个输入引脚。当我的输入引脚的 Receive 方法被调用时,它会将 IMediaSample 的呈现时间记录到一个文件中。这一切都很好,直到我停止图表并重新启动它(我正在使用 MS 的 graphedt)。大多数时候,再次运行时,没有任何问题。但是,大约每十次左右我停下来然后再次运行图表,开始呈现时间是负数。随着图表的运行,它最终会增加到零并超过零,但它永远不会赶上流时间,因此流时间仍然明显领先于每个样本的呈现开始时间。

我用 Logitech Webcam Pro 9000 和 Logitech C600 相机观察到了这一点,但没有用 Winbook 相机观察到,所以我想知道这是否是 Logitech 的问题。有没有其他人在停止并再次运行后在视频 IMediaSamples 上看到负面的演示时间?(我查看了 IMediaSample 中的预卷标志:它始终为 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 毫秒,在第一次调用中),我希望每次调用 Run 时这些几乎相同。相反,在第二次调用中传递给 Run 的时间比参考时钟晚了大约 10 秒。我将非常感谢帮助理解为什么第二次调用时传递给 Run 的时间与第二次调用时参考时钟返回的时间不同(几乎)相同。

更新 2:

问题似乎出在 Logitech 版本 13.31.1044.0 驱动程序中。请参阅下面的答案。

4

2 回答 2

4

负时间没什么大不了的。本质上,它的意思是“媒体样本应该在不久前呈现”。所以你可能认为媒体样本可以被丢弃?有时这是真的,有时不是:想象一系列时间压缩的视频帧,其中一个关键帧后跟 10 个增量帧。您希望演示从第 5 帧开始,您该怎么做?您必须从关键帧推入,以便解码器可以从拼接点有效解码,否则它无法从增量帧开始。无论帧是否迟到,解码器都可能会传递输出帧,这就是这些帧最终到达您的方式。

导致负时间的另一种情况是由线程、流和控制的竞争条件引起的。捕获线程可能正在开始其操作,但手头上没有基本的“开始时间”。

于 2012-04-11T15:41:43.877 回答
1

经过相当多的实验,我得出结论,该问题很可能是 Logitech 13.31.1044.0 摄像头驱动程序特有的。使用较早的 Logitech 12.10.1110 驱动程序、Winbook DC-6120 摄像头(及其驱动程序)和 Chicony USB 2.0 摄像头(及其驱动程序),我无法使问题再次出现。没有明显的原因,Logitech 13 驱动程序将在包含它的图形重新启动的大约每十次左右的时间中以负演示时间开始提供样本(也就是说,在我在 graphedt 中停止它然后再次启动它之后)。将这些时间与流时间进行比较不会提供 MSDN 描述的关于样本是否计划在过去、现在或将来显示的信息,因为流时间似乎没有受到影响。每次重启,正如人们所期望的那样,流时间再次从零开始,无论相机的演示时间是什么时候开始的。(请注意,Logitech 以 RGB24 子类型进行流式传输,没有压缩帧。)

我正在研究一个多线程直通过滤器,它可能能够根据流时间重新分配具有值的呈现时间,并且做得足够快以“伪造”正确的值,如果我得到一个有意义的值,我会在这里发布结果。此外,我将记录我的测试并将它们传达给罗技。如果他们回复,我也会在这里发布。

如果其他人正在使用使用上述驱动程序的罗技产品(或以其他方式观察我所描述的行为),请在此处发表评论。我很乐意向您发送我的过滤器的副本,其中记录了时间、帧等。我们也许可以一起寻找解决这个问题的好方法。

更新

通过编写我可以编写的最简单的可能的变换过滤器(一个简单地将输入 IMediaSample 的负图像复制到输出的过滤器),我已经能够相当一致地重现这种行为。大约每五六次我重新启动一个由 Camera->Filter->Renderer 组成的图表,前几个样本以负帧时间传递,远远落后于流时间,并且永远不会赶上。(也就是说,流时间永远领先于样本的呈现时间)。同样,其他相机和较旧的罗技驱动程序都不会发生这种情况。

这是有趣的部分:如果我在过滤器的 Run 方法中添加一些延迟(在覆盖 CTransformFilter::Run 之后),问题就会消失。这是代码:

STDMETHODIMP DLPassThrough::Run(REFERENCE_TIME tStart)
{
    Sleep(10);

    return CTransformFilter::Run(tStart);
}

我可以通过注释掉或恢复“Sleep(10)”调用来解决问题。我能猜到的是相机代码是多线程的,并且在总是在“运行”调用之前的“暂停”调用和它得到的下一个“运行”调用之间需要一些时间来清理它正在做的事情。据我了解 MSDN 文档,图形管理器将在渲染器上调用“暂停”,然后是我的过滤器,然后是相机,然后返回并在渲染器、我的过滤器和相机上调用“运行”。我相信这些调用中的每一个都是同步的,但如果相机代码是多线程的,当调用其“运行”方法时,它可能仍在处理来自图形管理器的最新“暂停”调用。通过向我的过滤器的“运行”方法添加延迟,

仍在等待/希望收到罗技的回复。同时,我确实编写了一个多线程就地转换过滤器,它只是添加对它获得的最新样本的引用,用当前流时间替换它的呈现时间,将其保存给下游过滤器以供下次下游使用过滤器准备好接收它,然后返回等待下一个传入样本。(如果在下游过滤器取一个之前有多个样本进入,则先前的样本将被释放,并替换为最新的样本。)到目前为止似乎正在工作。

更新 2

这是罗技的回答:

我想通知您,该设备主要用于视频流的 IM 应用程序,而不是作为开发软件或过滤器的主题。

于 2012-04-19T12:28:46.567 回答