После обработки я использую GStreamer для публикации измененного видео как нового потока RTSP.
Когда я тестирую выходной поток непосредственно в VLC, все работает нормально — видео отображается правильно с датой наложение.
Однако, когда я пытаюсь просмотреть тот же вывод RTSP в RTSPtoWeb, поток показывает только зеленый экран:

Я пытался увеличить битрейт, но он все еще зеленый, самое близкое, что я получил, это что поток отображает частично поврежденное изображение (видны нижние 20%, остальные просто повреждены)
Вот мой код:
import cv2
import numpy as np
import threading
import sys
try:
import gi
gi.require_version('Gst', '1.0')
gi.require_version('GstRtspServer', '1.0')
from gi.repository import Gst, GstRtspServer, GLib
Gst.init(None)
GST_AVAILABLE = True
except Exception as e:
print(f"GStreamer not available: {e}")
GST_AVAILABLE = False
sys.exit(1)
# ========== CONFIGURATION ==========
INPUT_SOURCE = "rtsp://xxxx/xxx"
OUTPUT_RTSP_PORT = "8554"
OUTPUT_RTSP_PATH = "/live"
OUTPUT_FPS = 25
class GstRTSPFactory(GstRtspServer.RTSPMediaFactory):
def __init__(self, width, height, fps):
super().__init__()
self.width = width
self.height = height
self.fps = fps
self.set_shared(True)
self.appsrc = None
self.pts = 0
self.frame_duration = Gst.util_uint64_scale_int(1, Gst.SECOND, int(fps))
def do_create_element(self, url):
"""Create GStreamer pipeline with appsrc"""
caps = f"video/x-raw,format=BGR,width={self.width},height={self.height},framerate={self.fps}/1"
pipeline = (
f"appsrc name=source is-live=true do-timestamp=true format=time caps=\"{caps}\" "
f"! queue max-size-buffers=4 leaky=upstream "
f"! videoconvert "
f"! video/x-raw,format=I420 "
f"! x264enc tune=zerolatency speed-preset=ultrafast bitrate=2000 key-int-max=60 "
f"! h264parse config-interval=1 "
f"! rtph264pay name=pay0 pt=96 config-interval=1"
)
return Gst.parse_launch(pipeline)
def do_configure(self, rtsp_media):
"""Get appsrc element from pipeline"""
element = rtsp_media.get_element()
self.appsrc = element.get_child_by_name("source")
def push_frame(self, frame: np.ndarray):
"""Push a frame to the RTSP stream"""
if self.appsrc is None:
return
try:
data = frame.tobytes()
buf = Gst.Buffer.new_allocate(None, len(data), None)
buf.fill(0, data)
buf.pts = self.pts
buf.duration = self.frame_duration
self.pts += self.frame_duration
self.appsrc.emit("push-buffer", buf)
except Exception as e:
print(f"Push error: {e}")
class RTSPServer:
"""Simple RTSP server wrapper"""
def __init__(self, width, height, fps, port, path):
self.width = width
self.height = height
self.fps = fps
self.port = port
self.path = "/" + path.lstrip("/")
self.server = None
self.factory = None
self.loop = None
self.loop_thread = None
def start(self):
"""Start RTSP server"""
try:
self.server = GstRtspServer.RTSPServer()
self.server.set_service(self.port)
self.factory = GstRTSPFactory(self.width, self.height, self.fps)
self.factory.connect("media-configure", lambda f, m: f.do_configure(m))
mounts = self.server.get_mount_points()
mounts.add_factory(self.path, self.factory)
self.server.attach(None)
# Run GLib mainloop in background
self.loop = GLib.MainLoop()
self.loop_thread = threading.Thread(target=self.loop.run, daemon=True)
self.loop_thread.start()
print(f"RTSP Server started: rtsp://localhost:{self.port}{self.path}")
return True
except Exception as e:
print(f"Failed to start RTSP server: {e}")
return False
def write_frame(self, frame):
"""Send frame to RTSP stream"""
if self.factory:
self.factory.push_frame(frame)
def stop(self):
"""Stop RTSP server"""
if self.loop:
self.loop.quit()
if self.loop_thread:
self.loop_thread.join(timeout=2)
def process_frame(frame):
import datetime
processed = frame.copy()
# Add timestamp
timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
cv2.putText(processed, timestamp, (10, 30),
cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
return processed
def main():
print("Test Gstream")
# Open video source
source = INPUT_SOURCE
if source.isdigit():
source = int(source)
cap = cv2.VideoCapture(source)
if not cap.isOpened():
print(f"Cannot open source: {INPUT_SOURCE}")
return
# Get video properties
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
fps = cap.get(cv2.CAP_PROP_FPS) or OUTPUT_FPS
print(f"Input: {width}x{height} @ {fps:.1f}fps")
print(f"Source: {INPUT_SOURCE}")
# Start RTSP server
rtsp = RTSPServer(width, height, OUTPUT_FPS, OUTPUT_RTSP_PORT, OUTPUT_RTSP_PATH)
if not rtsp.start():
return
print(f"Streaming...")
frame_count = 0
try:
while True:
ret, frame = cap.read()
if not ret:
print("EOServices")
break
frame_count += 1
# Process frame with OpenCV
processed = process_frame(frame)
# Send to RTSP stream
rtsp.write_frame(processed)
# Check for exit
key = cv2.waitKey(1) & 0xFF
if key == ord('q') or key == 27:
break
# Print progress every 100 frames
if frame_count % 100 == 0:
print(f"Frames processed: {frame_count}")
except KeyboardInterrupt:
print("\n Interrupted by user")
finally:
print(f"\n Cleanup... ({frame_count} frames processed)")
cap.release()
cv2.destroyAllWindows()
rtsp.stop()
print("Done")
if __name__ == "__main__":
if not GST_AVAILABLE:
print("Please install GStreamer and python-gi bindings")
sys.exit(1)
main()
Подробнее здесь: https://stackoverflow.com/questions/798 ... -gstreamer
Мобильная версия