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

没有。为什么不?为什么 tee 的两个输出都需要排队?在最坏的情况下,我希望一个自动视频接收器可以工作而另一个是空白的,但是一个显示单帧而另一个是黑色的。

但以下确实有效。这是怎么回事?

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 低级位的任何人来说,这是非常违反直觉的。但如果它有效,我猜它会有效。

4

1 回答 1

2

阅读PREROLLINGGStreamer 中的概念:

https://gstreamer.freedesktop.org/documentation/design/preroll.html

接收器元素只能在缓冲区已在输入焊盘或多个焊盘上排队后才能完成状态更改为 PAUSED。

文档中没有强调的是,管道只会PAUSEDPLAYING所有接收器都具有PREROLLED.

另请注意, atee没有线程,因此它按顺序将样本推送到下游。

以下是发生的情况:接收器 1 接收到一个样本,但不会开始播放,因为它一直等到管道中的所有其他接收器都接收到一个样本,因此可以尊重音频/视频同步。

因此,现在接收器 1 正在等待它有效地阻止tee它发送更多数据 - 在这种情况下,接收器 2 也是如此。由于没有数据将到达接收器 2,因此您处于死锁状态。

队列将自动在管道路径中添加一个线程作为副作用 - 防止死锁。

如果您只有一个队列,它实际上可能会起作用 - 取决于您将接收器连接到三通的顺序。如果带有队列的路径首先传递,则不会死锁,并且三通可以将数据传递给另一个,并且状态更改将成功。(与三个接收器的示例相同,如果所有路径都有一个队列但不是最后一个,您可能会侥幸逃脱)

tee对所有输出使用队列是一种很好的做法。

这个x264enc例子特别棘手。您在这里面临的问题是编码器消耗了太多数据但没有产生任何东西(还)有效地停止了管道。

修复它的两种方法:

  1. 用于元素tune=zerolatency_x264enc
  2. 增加非编码器路径队列中的缓冲区大小以补偿编码器延迟。

queue ! queue你实际上是通过将缓冲区大小加倍来做的2.

于 2018-03-21T09:16:49.030 回答