如何创建具有可变帧率的 GStreamer RTSP 服务器

问题描述

我有一个应用程序,它要求我使用 RTSP 流,从视频中提取帧,对视频帧执行一些处理,对帧进行注释,然后将视频重新传输为新的 RTSP 流。听起来很简单。

我正在使用从另一个 SO 答案中获得的以下代码

import gi
import cv2
import os

# import required library like Gstreamer and GstreamerRtspServer
gi.require_version('Gst','1.0')
gi.require_version('GstRtspServer','1.0')
from gi.repository import Gst,GstRtspServer,GObject


# Sensor Factory class which inherits the GstRtspServer base class and add
# properties to it.
class SensorFactory(GstRtspServer.RTSPMediaFactory):
    def __init__(self,**properties):
        super(SensorFactory,self).__init__(**properties)
        
        # Create a connection to our input RTSP stream and obtain the width and height
        self.cap = cv2.VideoCapture("rtspsrc location=rtsp://root:admin@192.168.88.248/stream1 ! decodebin ! videoconvert ! appsink max-buffers=3 drop=true")
        width  = int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH))
        height = int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) 
        print(width)
        print(height)

        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 is-live=true block=true format=GST_FORMAT_TIME ' \
                             'caps=video/x-raw,format=BGR,width={},height={},framerate={}/1 ' \
                             '! videoconvert ! video/x-raw,format=I420 ' \
                             '! x264enc speed-preset=ultrafast tune=zerolatency ' \
                             '! rtph264pay config-interval=1 name=pay0 pt=96' \
                             .format(width,height,self.fps)

    

    # Method for grabbing frames from the video capture,process,then pushing annotated images to streaming buffer
    def on_need_data(self,src,lenght):
        if self.cap.isOpened():
            ret,frame = self.cap.read()
            if ret:
               
                # --------------------------
                # --------------------------
                # Do processing here       
                # --------------------------
                # --------------------------

                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)
    # attach the launch string to the override method
    def do_create_element(self,url):
        return Gst.parse_launch(self.launch_string)
    
    # attaching the source element to the rtsp media
    def do_configure(self,rtsp_media):
        self.number_frames = 0
        appsrc = rtsp_media.get_element().get_child_by_name('source')
        appsrc.connect('need-data',self.on_need_data)

# Rtsp server implementation where we attach the factory sensor with the stream uri
class GstServer(GstRtspServer.RTSPServer):
    def __init__(self,**properties):
        super(GstServer,self).__init__(**properties)
        self.factory = SensorFactory()
        self.factory.set_shared(True)
        self.get_mount_points().add_factory("/my_stream",self.factory)
        self.attach(None)

# initializing the threads and running the stream on loop.
GObject.threads_init()
Gst.init(None)
server = GstServer()
loop = GObject.MainLoop()
loop.run()


# To connect:
# rtsp://localhost:8554/my_stream

我在标记为:

的部分中执行我的处理
                # --------------------------
                # --------------------------
                # Do processing here       
                # --------------------------
                # --------------------------

在这代码非常适合处理时间恒定的情况,因为那时我知道输出 rtsp 流 fps。 但是,我的处理时间不固定;花费的时间取决于来自源 rtsp 流的输入帧。就上下文而言,我正在构建一个人脸识别应用程序,帧中每个检测到的人脸的处理时间约为 50 毫秒 + 100 毫秒。

如何使输出 rtsp 流以这种可变帧速率工作?

我的猜测是我需要修改 gstreamer 管道字符串:

        self.launch_string = 'appsrc name=source is-live=true block=true format=GST_FORMAT_TIME ' \
                             'caps=video/x-raw,self.fps)

而且我可能也需要更改这部分:

                buf.duration = self.duration
                timestamp = self.number_frames * self.duration
                buf.pts = buf.dts = int(timestamp)
                buf.offset = timestamp

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)