我对 Gstreamer 还很陌生,我正在尝试创建一个管道来获取视频或另一个 RTSP 摄像机流并将其作为 RTSP 进行流式传输。 我设法创建了此代码,并且可以使用以下链接使用 VLC 打开流:rtsp://localhost:8554/stream,但它仅向我显示视频的第一帧。我应该更改什么才能使其正常工作?
import cv2
import gi
gi.require_version('Gst', '1.0')
gi.require_version('GstRtspServer', '1.0')
from gi.repository import Gst, GstRtspServer, GLib
Gst.init(None)
class Camera:
def __init__(self):
self.camera_url = 'RTSP link/video path'
self.number_frames = 0
self.fps = 12
self.duration = 1 / self.fps * Gst.SECOND
self.pipe = "appsrc name=source is-live=true block=true format=GST_FORMAT_TIME " \
" caps=video/x-raw,format=BGR,width=1280,height=720,framerate={}/1 " \
"! videoconvert ! video/x-raw,format=I420 ! x264enc speed-preset=ultrafast tune=zerolatency " \
"! rtph264pay config-interval=1 name=pay0 pt=96 " \
"! udpsink host=127.0.0.1 port=5400 sync=true async=false".format(self.fps)
self.pipeline = Gst.parse_launch(self.pipe)
self.loop = None
appsrc=self.pipeline.get_by_name('source')
appsrc.connect('need-data', self.start_camera)
def create_rtsp_server(self):
server = GstRtspServer.RTSPServer.new()
server.set_property("service", "8554")
server.attach(None)
factory = GstRtspServer.RTSPMediaFactory.new()
pipeline = "( udpsrc port=5400 name=pay0 caps=\"application/x-rtp, media=video, clock-rate=90000, encoding-name=(string)H264, payload=96 \" )"
factory.set_launch(pipeline)
factory.set_shared(True)
server.get_mount_points().add_factory("/stream", factory)
def run(self):
self.pipeline.set_state(Gst.State.READY)
self.pipeline.set_state(Gst.State.PLAYING)
self.create_rtsp_server()
self.loop = GLib.MainLoop()
self.loop.run()
def start_camera(
self, src, lenght
):
cap = cv2.VideoCapture(self.camera_url)
try:
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
data = frame.tobytes()
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 = src.emit('push-buffer', buf)
print('pushed buffer, frame {}, duration {} ns, durations {} s'.format(self.number_frames, self.duration, self.duration / Gst.SECOND))
if retval != Gst.FlowReturn.OK:
print(retval)
return True
finally:
cap.release()
cv2.destroyAllWindows()
我尝试搜索类似的 Gstreamer 管道,但找不到类似的东西
令我惊讶的是,rtsp 工厂能够使用
name
元素上设置的 udpsrc
属性创建流。虽然有可能,但我认为 udpsrc
元素卡在接收数据包和通过 rtsp 发送数据包之间。因为它是单线程,所以它可能会达到竞争条件。
通常最好在
queue
元素之后、src
等重处理元素之前添加 x264enc
元素。 queue
为帧添加缓冲区,并模拟GStreamer
中的多线程。
所以我建议按如下方式更改两个管道并尝试一下
self.pipe = "appsrc name=source is-live=true block=true format=GST_FORMAT_TIME " \
" caps=video/x-raw,format=BGR,width=1280,height=720,framerate={}/1 " \
"! queue ! videoconvert ! video/x-raw,format=I420 ! queue ! x264enc speed-preset=ultrafast tune=zerolatency " \
"! rtph264pay config-interval=1 name=pay0 pt=96 " \
"! queue ! udpsink host=127.0.0.1 port=5400 sync=true async=false".format(self.fps)
pipeline = "( udpsrc port=5400 caps=\"application/x-rtp, media=video, clock-rate=90000, encoding-name=(string)H264\" ! queue ! rtph264depay ! h264parse ! rtph264pay name=pay0 pt=96 )"