| 
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -2,51 +2,42 @@ import cv2 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import gi | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import threading | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import numpy as np | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import socket | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					gi.require_version('Gst', '1.0') | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					gi.require_version('GstRtspServer', '1.0') | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					from gi.repository import Gst, GstRtspServer, GLib | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import socket | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					def get_local_ip(): | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    """Retrieve the local IP address of the machine.""" | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    try: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        # Create a socket object | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        # Connect to an external server (doesn't actually send any data) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        s.connect(("8.8.8.8", 80)) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        # Get the local IP address | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        local_ip = s.getsockname()[0] | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        # Close the socket | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        ip = s.getsockname()[0] | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        s.close() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        return local_ip | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        return ip | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    except Exception as e: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        return str(e) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					class VideoStream(GstRtspServer.RTSPMediaFactory): | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    def __init__(self, fps=25, width=1920, height=1080): | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    def __init__(self, fps, width, height): | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        super(VideoStream, self).__init__() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        self.fps = fps | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        self.width = width | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        self.height = height | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        self.frame = np.zeros((height, width, 3), dtype=np.uint8)  # Black frame initially | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        self.frame = np.zeros((height, width, 3), dtype=np.uint8)  # Initial black frame | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        self.lock = threading.Lock() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    def update_frame(self, frame): | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        """Externally updates the current frame.""" | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        with self.lock: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            self.frame = cv2.resize(frame, (self.width, self.height))  # Resize if necessary | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            self.frame = cv2.resize(frame, (self.width, self.height)) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    def on_need_data(self, src, length): | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        """Provides frames when the pipeline requests data.""" | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        """Provides frames to the pipeline when requested.""" | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        with self.lock: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            frame_rgb = cv2.cvtColor(self.frame, cv2.COLOR_BGR2RGB)  # Convert BGR to RGB | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            data = frame_rgb.tobytes()  # Convert to bytes | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            frame_rgb = cv2.cvtColor(self.frame, cv2.COLOR_BGR2RGB) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            data = frame_rgb.tobytes() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        buf = Gst.Buffer.new_allocate(None, len(data), None) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        buf.fill(0, data) | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -64,38 +55,74 @@ class VideoStream(GstRtspServer.RTSPMediaFactory): | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            "! h264parse ! rtph264pay config-interval=1 name=pay0 pt=96" | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        ).format(self.width, self.height, self.fps) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        pipeline = Gst.parse_launch(pipeline_str) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        src = pipeline.get_by_name("source") | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        src.connect("need-data", self.on_need_data) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        return pipeline | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					class RTSPServer: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    def __init__(self, ip="0.0.0.0", port=8554, mount_point="/stream"): | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        Gst.init(None) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        self.server = GstRtspServer.RTSPServer() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        self.server.set_address(ip) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        self.server.set_service(str(port)) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        self.mount_point = mount_point | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        self.video_stream = VideoStream() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        self.server.get_mount_points().add_factory(mount_point, self.video_stream) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        self.video_stream = None | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        self.server.attach(None) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        self.current_fps = None | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        self.current_width = None | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        self.current_height = None | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        self.lock = threading.Lock() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    def create_stream(self, fps, width, height): | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        """Create a new streaming channel with the given size & FPS.""" | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        with self.lock: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            # Check if we need to recreate the stream | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (self.video_stream and | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                self.current_fps == fps and | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                self.current_width == width and | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                self.current_height == height): | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                return  # No need to recreate | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            # Remove old stream if exists | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if self.video_stream: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                print("Recreating RTSP stream for new resolution/fps...") | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                self.server.get_mount_points().remove_factory(self.mount_point) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            # Create a new stream with the updated settings | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            self.video_stream = VideoStream(fps, width, height) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            self.server.get_mount_points().add_factory(self.mount_point, self.video_stream) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    def start(self): | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        print(f"RTSP Server running at rtsp://{self.server.get_address()}:{self.server.get_service()}/stream") | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        loop = GLib.MainLoop() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        loop.run() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            self.current_fps = fps | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            self.current_width = width | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            self.current_height = height | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            print(f"New RTSP stream created: {width}x{height} at {fps}fps") | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    def update_frame(self, frame): | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        """Externally updates the current frame for streaming.""" | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        self.video_stream.update_frame(frame) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        """Push frames to the current streaming channel.""" | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        if frame is None or frame.size == 0: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            return | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        height, width, _ = frame.shape | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        fps = 30  # Default FPS, can be adjusted dynamically if needed | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        # Ensure we have a valid stream for the given resolution | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        self.create_stream(fps, width, height) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        # Update the current stream with the new frame | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        if self.video_stream: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            self.video_stream.update_frame(frame) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					# Global server instance | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					rtsp_server = RTSPServer(get_local_ip(),41231) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					# Global RTSP server instance | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					rtsp_server = RTSPServer(get_local_ip(), 41231) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					def run_server(): | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    rtsp_server.start() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    """Start the RTSP server loop.""" | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    print(f"RTSP Server running at rtsp://{rtsp_server.server.get_address()}:{rtsp_server.server.get_service()}/stream") | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    loop = GLib.MainLoop() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    loop.run() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					# def stream_webcam(): | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					#     cap = cv2.VideoCapture("/home/mht/Downloads/bcd2890d71caaf0e095b95c9b525973f61186656-360p.mp4")  # Open webcam | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
						
					 | 
				
				 | 
				
					
  |