将图像帧写入 gstreamer rtp 管道

Write image frames into gstreamer rtp pipeline

我正在尝试使用 gstreamer 管道在我的计算机上查看 vlc 中的 rtp 流。我主要研究了这个 。我的最终结果是这样的

#!/usr/bin/env python

import gi
import numpy as np

gi.require_version('Gst', '1.0')
from gi.repository import Gst, GObject
import time


class RtpPipeline(object):
    def __init__(self):
        self.number_frames = 0
        self.fps = 30
        self.duration = 1 / self.fps * Gst.SECOND  # duration of a frame in nanoseconds
        self.launch_string = 'appsrc name=source ' \
                             '!videoconvert !x264enc speed-preset=ultrafast tune=zerolatency byte-stream=true ' \
                             '! mpegtsmux ! rtpmp2tpay ! udpsink host=127.0.0.1 port=5000'
        pipeline = Gst.parse_launch(self.launch_string)
        appsrc = pipeline.get_child_by_name('source')

        while True:
            try:
                img = np.zeros([320, 320, 3], dtype=np.uint8)
                img.fill(255)  # white image
                data = img.tostring()
                buf = Gst.Buffer.new_allocate(None, len(data), None)
                buf.fill(0, data)
                buf.duration = self.duration
                timestamp = self.number_frames * self.duration
                buf.pts = buf.dts = int(timestamp)
                buf.offset = timestamp
                self.number_frames += 1
                retval = appsrc.emit('push-buffer', buf)
                if retval != Gst.FlowReturn.OK:
                    print(retval)
                time.sleep(0.2)
            except Exception as e:
                break


Gst.init(None)

factory = RtpPipeline()

loop = GObject.MainLoop()
loop.run()

这不会引发错误,但不会在我的 vlc 客户端中显示任何内容。任何提示都会很棒(OpenCV VideoWriter 不是一个选项)。

图像帧需要解码(基于您从中读取图像文件的格式),然后转换为 RAW 格式(RGB/BGR/YUV 等),然后传递到 gstreamer 管道。

如果你用特定颜色填充图像缓冲区,而不是从任何图像文件中读取,你应该知道图像缓冲区的格式。

Gstreamer 管道还应该知道传递给它的是什么 RAW 格式以及什么分辨率和 fps 详细信息。

Python 脚本应该以 fps 中设置的相同帧速率推送图像文件。检查你的睡眠时间。

更改这些参数后检查,如果问题仍然存在 - 也添加 gstreamer 日志。

我认为最重要的遗漏是:

pipeline.set_state(Gst.State.PLAYING)

我还添加了来自 的评论。这是最终结果,虽然有点问题,但这是一个好的开始。

class RtpPipeline(object):
    def __init__(self):
        self.number_frames = 0
        self.fps = 30
        self.cap = cv2.VideoCapture(0)
        self.duration = 1 / self.fps * Gst.SECOND  # duration of a frame in nanoseconds
        self.launch_string = 'appsrc name=source is-live=true format=GST_FORMAT_TIME ' \
                             ' caps=video/x-raw,format=BGR,width=640,height=480,framerate=30/1 ' \
                             '! videoconvert ! video/x-raw,format=I420 ' \
                             '! x264enc speed-preset=ultrafast tune=zerolatency byte-stream=true ' \
                             '! mpegtsmux ! rtpmp2tpay ! udpsink host=127.0.0.1 port=5000 sync=false'
        pipeline = Gst.parse_launch(self.launch_string)
        appsrc = pipeline.get_child_by_name('source')
        pipeline.set_state(Gst.State.PLAYING)

        while True:
            try:
                ret, frame = self.cap.read()
                start = time.time()
                data = frame.tostring()
                buf = Gst.Buffer.new_allocate(None, len(data), None)
                buf.fill(0, data)
                buf.duration = self.duration
                timestamp = self.number_frames * self.duration
                buf.pts = buf.dts = int(timestamp)
                buf.offset = timestamp
                self.number_frames += 1
                retval = appsrc.emit('push-buffer', buf)
                if retval != Gst.FlowReturn.OK:
                    print(retval)
            except Exception as e:
                break