我有两个 GStreamer 管道,一个就像“源”管道,将实时摄像机输入流式传输到外部通道,第二个管道就像“接收器”管道,从该通道的另一端读取并输出实时数据视频到某种形式的接收器。
[videotestsrc] -> [appsink] ----- Serial Channel ------> [appsrc] -> [autovideosink]
First Pipeline Second Pipeline
第一个管道从
videotestsrc
开始,对视频进行编码并将其包装在 gdppay
有效负载中,然后将管道汇入串行通道(但就问题而言,任何可以从中读取的接收器都可以)另一个管道(例如写入串行端口或 udpsink 的文件接收器),由下一个管道的源读取并通过 autovideosrc
: 显示
gst-launch-1.0 -v videotestsrc ! videoconvert ! video/x-raw,format=I420 ! x265enc ! gdppay ! udpsink host=127.0.0.1 port=5004
gst-launch-1.0 -v udpsrc uri=udp://127.0.0.1:5004 ! gdpdepay ! h265parse ! avdec_h265 ! autovideosink
注意:考虑到使用 udpsink/udpsrc 引起的延迟,该管道抱怨时间戳问题。如果您将 udpsrc/udpsink 替换为串行端口的 filesrc/filesink,您可以看到我将要描述的问题。
现在我已经描述了管道,问题是: 如果我启动两条管道,一切都会按预期进行。但是,如果 30 秒后,我停止“源”管道,然后重新启动管道,运行时间将重置为零,导致发送的所有缓冲区的时间戳被接收器管道视为旧缓冲区,因为它已经收到时间戳 0 到 30 秒的缓冲区,因此另一端的播放要到 30 秒后才会恢复:
Source Pipeline: [28][29][30][0 ][1 ][2 ][3 ]...[29][30][31]
Sink Pipeline: [28][29][30][30][30][30][30]...[30][30][31]
________________________^
Source pipeline restarted
^^^^^^^^^^^^^^^^...^^^^^^^^
Sink pipeline will continue
to only show the "frame"
received at 30s until a
"newer" frame is sent, when
in reality each sent frame
is newer and should be shown
immediately.
我发现将
sync=false
添加到 autovideosink
确实可以解决问题,但是我希望找到一种解决方案,其中源将根据 Clock time 发送其时间戳(DTS 和 PTS),如该页面上的图像。
我已经看过这篇文章,并在我的视频源上尝试了
is-live
和do-timestamp
,但它们似乎没有达到我想要的效果。我还尝试根据系统时间手动设置缓冲区中的时间戳(DTS、PTS),但无济于事。
有什么建议吗?
GstBaseSrc 有
do-timestamp
属性,它完全可以满足您的需求。当您设置 do-timestamp=true
时,大多数实时源将使用时钟时间为缓冲区添加时间戳(如果它们遵守的话)。
这是来自 Aravis 的示例: https://github.com/AravisProject/aravis/commit/d1cbf643e5251d26199d799d98b8d05d1ad255a7
这是我正在谈论的属性: https://gstreamer.freedesktop.org/documentation/base/gstbasesrc.html?gi-language=c#GstBaseSrc:do-timestamp
我认为你也应该重新启动接收器管道。您可以将
-e
开关添加到发送方管道,当您停止管道时,它应该通过 GDP 元素将 EOS 正确传播到接收方管道。否则我想你可以向接收者发送一个新的段或不连续性。但必须发出某些事件信号才能使管道意识到该变化,否则它就是有点虚假的数据。我想说重新启动接收器是最简单的方法。