如何让 Gstreamer return 只有关键帧?

How to make Gstreamer return only keyframes?

gstreamer 管道中,我试图找出是否有一种方法可以指定 我只想要来自 RTSP 流的关键帧.

ffmpeg 中,您可以使用 -skip_frame nokey 标志来执行此操作。例如:

ffmpeg -skip_frame nokey -i rtsp://184.72.239.149/vod/mp4:BigBuckBunny_175k.mov -qscale 0 -r 1/1 frame%03d.jpg

读取 RTSP 提要的相应 gstreamer 命令如下所示:

gst-launch-1.0 rtspsrc location=rtsp://184.72.239.149/vod/mp4:BigBuckBunny_175k.mov ! decodebin ! videorate ! "video/x-raw,framerate=1/1" ! videoconvert ! autovideosink

有谁知道是否可以要求 gstreamer 仅 return 个关键帧?

我认为您可以尝试在设置了 GST_BUFFER_FLAG_DELTA_UNIT 标志的缓冲区上添加 GST_PAD_PROBE_TYPE_BUFFER 填充探针和 return GST_PAD_PROBE_DROP

您可以使用带有标记 GstSeekFlags 的新搜索事件 gst_event_new_seek 来实现特技模式 GST_SEEK_FLAG_TRICKMODE、跳过帧 GST_SEEK_FLAG_SKIP 和仅关键帧 GST_SEEK_FLAG_TRICKMODE_KEY_UNITS

您还可以使用 identity 及其 属性 drop-buffer-flags 来筛选 GST_BUFFER_FLAG_DELTA_UNIT,也许 GST_BUFFER_FLAG_DROPPABLE

请参阅 trickmodes, seeking and GstSeekFlags in the documentation for the seeking and identity:drop-buffer-flags and GstBufferFlags 了解身份。

在花了几天时间寻找这个问题的完整答案后,我最终得到了一个解决方案,它为我提供了我一直在寻找的 rtsp 处理能力提升。

这是 Python 中管道的差异,它从处理每个 RTSP 帧过渡到只处理关键帧。

https://github.com/ambianic/ambianic-edge/pull/171/files#diff-f89415777c559bba294250e788230c5e

首先注册流启动总线事件:

Gst.MessageType.STREAM_START

流处理开始时触发。当这个事件发生时,请求寻找下一个关键帧。

当请求完成时,管道触发我们需要监听的下一个总线事件:

Gst.MessageType.ASYNC_DONE

最后,这是关键帧搜索请求本身:

    def _gst_seek_next_keyframe(self):
        found, pos_int = self.gst_pipeline.query_position(Gst.Format.TIME)
        if not found:
            log.warning('Gst current pipeline position not found.')
            return
        rate = 1.0  # keep rate close to real time
        flags = \
            Gst.SeekFlags.FLUSH | Gst.SeekFlags.KEY_UNIT | \
            Gst.SeekFlags.TRICKMODE | Gst.SeekFlags.SNAP_AFTER | \
            Gst.SeekFlags.TRICKMODE_KEY_UNITS | \
            Gst.SeekFlags.TRICKMODE_NO_AUDIO
        is_event_handled = self.gst_pipeline.seek(
            rate,
            Gst.Format.TIME,
            flags,
            Gst.SeekType.SET, pos_int,
            Gst.SeekType.END, 0)