除非我有两个队列,为什么屏幕上的视频无法更新?

时间:2018-03-21 05:22:58

标签: gstreamer gstreamer-1.0

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而不是原始,我的Logitech BRIO输出1080p的视频jpeg,而不是原始的720p。这已经是经过测试,效果比简单的“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低级别比特的人来说,这是令人难以置信的反直觉。但是,如果它有效,我猜。

1 个答案:

答案 0 :(得分:1)

了解GStreamer中PREROLLING的概念:

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

  

一个sink元素只能在a之后完成对PAUSED的状态更改   缓冲区已在输入焊盘或焊盘上排队。

文档中没有强调的是,在所有接收器PAUSED之后,管道只会从PLAYING过渡到PREROLLED

另请注意,tee没有线程,因此它会顺序推送下游的样本。

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

现在,接收器1正在等待它有效阻止tee阻止它发送更多数据 - 在这种情况下,因此接收2.因为没有数据将到达接收器2,所以你处于死锁状态。

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

如果您只有一个队列,它实际上可以工作 - 这取决于您将接收器连接到发球台的顺序。如果首先传递带有队列的路径,它将不会死锁,并且tee可以将数据传递给另一个,并且状态更改将成功。 (与具有三个接收器的示例相同,如果所有路径都有队列但不是最后一个你可以使用它的话)

最好为所有tee输出使用队列。

x264enc示例特别棘手。你在这里遇到的问题是编码器消耗太多数据但没有产生任何(但是)有效地阻塞管道。

两种解决方法:

  1. 使用tune=zerolatency作为x264enc元素
  2. 增加非编码器路径队列中的缓冲区大小,以补偿编码器延迟。
  3. 使用queue ! queue,您实际上是通过将缓冲区大小加倍来执行大小写2.