除非我有两个队列,否则为什么屏幕上的视频无法更新?
Why does on-screen video fail to update unless i have two queues?
gst-launch-1.0 -v -e \
videotestsrc ! tee name=t0 \
t0. ! queue ! x264enc ! matroskamux ! filesink location="test.mkv" \
t0. ! queue ! queue ! autovideosink
有效,文件和屏幕显示都有效
gst-launch-1.0 -v -e \
videotestsrc ! tee name=t0 \
t0. ! queue ! x264enc ! matroskamux ! filesink location="test.mkv" \
t0. ! queue ! autovideosink
无效。
这是另一组示例。
gst-launch-1.0 -v -e \
videotestsrc ! tee name=t0 \
t0. ! queue ! autovideosink \
t0. ! queue ! autovideosink
有效。
gst-launch-1.0 -v -e \
videotestsrc ! tee name=t0 \
t0. ! queue ! autovideosink \
t0. ! autovideosink
不会。为什么不?为什么发球台的两个输出都需要排队?在最坏的情况下,我希望一个 autovideosink 可以工作而另一个是空白的,但一个显示单个帧而另一个是黑色的。
但以下确实有效。怎么回事?
gst-launch-1.0 -v -e \
videotestsrc ! tee name=t0 \
t0. ! queue ! autovideosink \
t0. ! queue ! autovideosink \
t0. ! autovideosink
为什么添加第三个输出就不需要在所有输出上排队?
gst-launch-1.0 --version
gst-launch-1.0 version 1.12.4
GStreamer 1.12.4
https://packages.gentoo.org/package/media-libs/gstreamer
有谁知道为什么队列会这样?
这是我要制作的管道。以上只是缩小的例子。
(注意:管道第一行中的奇怪上限是为了确保我的 Logitech c920 相机输出 h264 而不是 raw,以及我的 Logitech BRIO 输出 1080p 的视频 jpeg,而不是 720p 的 raw。这已经过测试,效果比简单 "decodebin")
好得多
gst-launch-1.0 -e \
v4l2src device=/dev/video0 ! 'video/x-h264;image/jpeg;video/x-raw' ! decodebin ! 'video/x-raw' ! tee name=t0 \
v4l2src device=/dev/video1 ! 'video/x-h264;image/jpeg;video/x-raw' ! decodebin ! 'video/x-raw' ! tee name=t1 \
v4l2src device=/dev/video2 ! 'video/x-h264;image/jpeg;video/x-raw' ! decodebin ! 'video/x-raw' ! tee name=t2 \
v4l2src device=/dev/video3 ! 'video/x-h264;image/jpeg;video/x-raw' ! decodebin ! 'video/x-raw' ! tee name=t3 \
matroskamux name=mux \
t0. ! queue ! autovideoconvert ! x264enc ! mux. \
t1. ! queue ! autovideoconvert ! x264enc ! mux. \
t2. ! queue ! autovideoconvert ! x264enc ! mux. \
t3. ! queue ! autovideoconvert ! x264enc ! mux. \
mux. ! queue ! filesink location="test.mkv" \
videomixer name=mix \
sink_0::zorder=1 sink_0::alpha=1.0 sink_0::ypos=0 sink_0::xpos=0 \
sink_1::zorder=1 sink_1::alpha=1.0 sink_1::ypos=0 sink_1::xpos=960 \
sink_2::zorder=1 sink_2::alpha=1.0 sink_2::ypos=540 sink_2::xpos=0 \
sink_3::zorder=1 sink_3::alpha=1.0 sink_3::ypos=540 sink_3::xpos=960 \
t0. ! queue ! autovideoconvert ! video/x-raw, width=960, height=540 ! mix.sink_0 \
t1. ! queue ! autovideoconvert ! video/x-raw, width=960, height=540 ! mix.sink_1 \
t2. ! queue ! autovideoconvert ! video/x-raw, width=960, height=540 ! mix.sink_2 \
t3. ! queue ! autovideoconvert ! video/x-raw, width=960, height=540 ! mix.sink_3 \
mix. ! queue ! autovideosink sync=false
通过将 max-size-bytes=0 max-size-buffers=0 max-size-time=10000000000 添加到队列中解决了这个问题。
对于未启动 gstreamer 低级别位的任何人来说,这难以置信 违反直觉。但如果它有效,我想它会起作用。
了解 GStreamer 中 PREROLLING
的概念:
https://gstreamer.freedesktop.org/documentation/design/preroll.html
A sink element can only complete the state change to PAUSED after a
buffer has been queued on the input pad or pads.
文档中没有强调的是,管道只会在所有接收器都具有 PREROLLED
.
后从 PAUSED
过渡到 PLAYING
另请注意,tee
不是线程化的,因此它会按顺序向下游推送样本。
发生的情况是这样的:接收器 1 收到样本,但不会开始播放,因为它会等到管道中的所有其他接收器都收到样本,这样 audio/video 同步才能得到遵守。
所以现在 sink 1 正在等待,它有效地阻止了 tee
阻止它发送更多数据 - 在这种情况下,sink 2 也是如此。因为没有数据会到达 sink 2,所以你陷入了僵局。
队列会自动在管道路径中添加一个线程作为副作用 - 防止死锁。
如果您只有一个队列,它实际上可能有效 - 取决于您将水槽连接到发球台的顺序。如果有队列的路径先被传递,它就不会死锁,并且发球台可以向另一个发球台传递数据,并且状态更改将成功。 (与三个接收器的示例相同,如果所有路径都有一个队列但不是最后一个你可能会逃脱它)
对所有 tee
输出使用队列是一种很好的做法。
x264enc
示例特别棘手。你在这里面临的问题是编码器消耗了太多数据但没有产生任何东西(还)有效地拖延了管道。
两种修复方式:
- 对
x264enc
元素使用 tune=zerolatency
- 增加 non-encoder 路径队列中的缓冲区大小以补偿编码器延迟。
对于 queue ! queue
,您实际上是通过将缓冲区大小加倍来处理案例 2.
。
gst-launch-1.0 -v -e \
videotestsrc ! tee name=t0 \
t0. ! queue ! x264enc ! matroskamux ! filesink location="test.mkv" \
t0. ! queue ! queue ! autovideosink
有效,文件和屏幕显示都有效
gst-launch-1.0 -v -e \
videotestsrc ! tee name=t0 \
t0. ! queue ! x264enc ! matroskamux ! filesink location="test.mkv" \
t0. ! queue ! autovideosink
无效。
这是另一组示例。
gst-launch-1.0 -v -e \
videotestsrc ! tee name=t0 \
t0. ! queue ! autovideosink \
t0. ! queue ! autovideosink
有效。
gst-launch-1.0 -v -e \
videotestsrc ! tee name=t0 \
t0. ! queue ! autovideosink \
t0. ! autovideosink
不会。为什么不?为什么发球台的两个输出都需要排队?在最坏的情况下,我希望一个 autovideosink 可以工作而另一个是空白的,但一个显示单个帧而另一个是黑色的。
但以下确实有效。怎么回事?
gst-launch-1.0 -v -e \
videotestsrc ! tee name=t0 \
t0. ! queue ! autovideosink \
t0. ! queue ! autovideosink \
t0. ! autovideosink
为什么添加第三个输出就不需要在所有输出上排队?
gst-launch-1.0 --version
gst-launch-1.0 version 1.12.4
GStreamer 1.12.4
https://packages.gentoo.org/package/media-libs/gstreamer
有谁知道为什么队列会这样?
这是我要制作的管道。以上只是缩小的例子。
(注意:管道第一行中的奇怪上限是为了确保我的 Logitech c920 相机输出 h264 而不是 raw,以及我的 Logitech BRIO 输出 1080p 的视频 jpeg,而不是 720p 的 raw。这已经过测试,效果比简单 "decodebin")
好得多gst-launch-1.0 -e \
v4l2src device=/dev/video0 ! 'video/x-h264;image/jpeg;video/x-raw' ! decodebin ! 'video/x-raw' ! tee name=t0 \
v4l2src device=/dev/video1 ! 'video/x-h264;image/jpeg;video/x-raw' ! decodebin ! 'video/x-raw' ! tee name=t1 \
v4l2src device=/dev/video2 ! 'video/x-h264;image/jpeg;video/x-raw' ! decodebin ! 'video/x-raw' ! tee name=t2 \
v4l2src device=/dev/video3 ! 'video/x-h264;image/jpeg;video/x-raw' ! decodebin ! 'video/x-raw' ! tee name=t3 \
matroskamux name=mux \
t0. ! queue ! autovideoconvert ! x264enc ! mux. \
t1. ! queue ! autovideoconvert ! x264enc ! mux. \
t2. ! queue ! autovideoconvert ! x264enc ! mux. \
t3. ! queue ! autovideoconvert ! x264enc ! mux. \
mux. ! queue ! filesink location="test.mkv" \
videomixer name=mix \
sink_0::zorder=1 sink_0::alpha=1.0 sink_0::ypos=0 sink_0::xpos=0 \
sink_1::zorder=1 sink_1::alpha=1.0 sink_1::ypos=0 sink_1::xpos=960 \
sink_2::zorder=1 sink_2::alpha=1.0 sink_2::ypos=540 sink_2::xpos=0 \
sink_3::zorder=1 sink_3::alpha=1.0 sink_3::ypos=540 sink_3::xpos=960 \
t0. ! queue ! autovideoconvert ! video/x-raw, width=960, height=540 ! mix.sink_0 \
t1. ! queue ! autovideoconvert ! video/x-raw, width=960, height=540 ! mix.sink_1 \
t2. ! queue ! autovideoconvert ! video/x-raw, width=960, height=540 ! mix.sink_2 \
t3. ! queue ! autovideoconvert ! video/x-raw, width=960, height=540 ! mix.sink_3 \
mix. ! queue ! autovideosink sync=false
通过将 max-size-bytes=0 max-size-buffers=0 max-size-time=10000000000 添加到队列中解决了这个问题。
对于未启动 gstreamer 低级别位的任何人来说,这难以置信 违反直觉。但如果它有效,我想它会起作用。
了解 GStreamer 中 PREROLLING
的概念:
https://gstreamer.freedesktop.org/documentation/design/preroll.html
A sink element can only complete the state change to PAUSED after a buffer has been queued on the input pad or pads.
文档中没有强调的是,管道只会在所有接收器都具有 PREROLLED
.
PAUSED
过渡到 PLAYING
另请注意,tee
不是线程化的,因此它会按顺序向下游推送样本。
发生的情况是这样的:接收器 1 收到样本,但不会开始播放,因为它会等到管道中的所有其他接收器都收到样本,这样 audio/video 同步才能得到遵守。
所以现在 sink 1 正在等待,它有效地阻止了 tee
阻止它发送更多数据 - 在这种情况下,sink 2 也是如此。因为没有数据会到达 sink 2,所以你陷入了僵局。
队列会自动在管道路径中添加一个线程作为副作用 - 防止死锁。
如果您只有一个队列,它实际上可能有效 - 取决于您将水槽连接到发球台的顺序。如果有队列的路径先被传递,它就不会死锁,并且发球台可以向另一个发球台传递数据,并且状态更改将成功。 (与三个接收器的示例相同,如果所有路径都有一个队列但不是最后一个你可能会逃脱它)
对所有 tee
输出使用队列是一种很好的做法。
x264enc
示例特别棘手。你在这里面临的问题是编码器消耗了太多数据但没有产生任何东西(还)有效地拖延了管道。
两种修复方式:
- 对
x264enc
元素使用tune=zerolatency
- 增加 non-encoder 路径队列中的缓冲区大小以补偿编码器延迟。
对于 queue ! queue
,您实际上是通过将缓冲区大小加倍来处理案例 2.
。