| 
					
					
						
							
						
					
					
				 | 
				@ -2,51 +2,42 @@ import cv2 | 
			
		
		
	
		
			
				 | 
				 | 
				import gi | 
				 | 
				 | 
				import gi | 
			
		
		
	
		
			
				 | 
				 | 
				import threading | 
				 | 
				 | 
				import threading | 
			
		
		
	
		
			
				 | 
				 | 
				import numpy as np | 
				 | 
				 | 
				import numpy as np | 
			
		
		
	
		
			
				 | 
				 | 
				 | 
				 | 
				 | 
				import socket | 
			
		
		
	
		
			
				 | 
				 | 
				
 | 
				 | 
				 | 
				
 | 
			
		
		
	
		
			
				 | 
				 | 
				gi.require_version('Gst', '1.0') | 
				 | 
				 | 
				gi.require_version('Gst', '1.0') | 
			
		
		
	
		
			
				 | 
				 | 
				gi.require_version('GstRtspServer', '1.0') | 
				 | 
				 | 
				gi.require_version('GstRtspServer', '1.0') | 
			
		
		
	
		
			
				 | 
				 | 
				from gi.repository import Gst, GstRtspServer, GLib | 
				 | 
				 | 
				from gi.repository import Gst, GstRtspServer, GLib | 
			
		
		
	
		
			
				 | 
				 | 
				import socket | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				
 | 
				 | 
				 | 
				
 | 
			
		
		
	
		
			
				 | 
				 | 
				def get_local_ip(): | 
				 | 
				 | 
				def get_local_ip(): | 
			
		
		
	
		
			
				 | 
				 | 
				 | 
				 | 
				 | 
				    """Retrieve the local IP address of the machine.""" | 
			
		
		
	
		
			
				 | 
				 | 
				    try: | 
				 | 
				 | 
				    try: | 
			
		
		
	
		
			
				 | 
				 | 
				        # Create a socket object | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) | 
				 | 
				 | 
				        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)) | 
				 | 
				 | 
				        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() | 
				 | 
				 | 
				        s.close() | 
			
		
		
	
		
			
				 | 
				 | 
				
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				        return local_ip | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				 | 
				 | 
				 | 
				        return ip | 
			
		
		
	
		
			
				 | 
				 | 
				    except Exception as e: | 
				 | 
				 | 
				    except Exception as e: | 
			
		
		
	
		
			
				 | 
				 | 
				        return str(e) | 
				 | 
				 | 
				        return str(e) | 
			
		
		
	
		
			
				 | 
				 | 
				
 | 
				 | 
				 | 
				
 | 
			
		
		
	
		
			
				 | 
				 | 
				
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				class VideoStream(GstRtspServer.RTSPMediaFactory): | 
				 | 
				 | 
				class VideoStream(GstRtspServer.RTSPMediaFactory): | 
			
		
		
	
		
			
				 | 
				 | 
				    def __init__(self, fps=25, width=1920, height=1080): | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				 | 
				 | 
				 | 
				    def __init__(self, fps, width, height): | 
			
		
		
	
		
			
				 | 
				 | 
				        super(VideoStream, self).__init__() | 
				 | 
				 | 
				        super(VideoStream, self).__init__() | 
			
		
		
	
		
			
				 | 
				 | 
				        self.fps = fps | 
				 | 
				 | 
				        self.fps = fps | 
			
		
		
	
		
			
				 | 
				 | 
				        self.width = width | 
				 | 
				 | 
				        self.width = width | 
			
		
		
	
		
			
				 | 
				 | 
				        self.height = height | 
				 | 
				 | 
				        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() | 
				 | 
				 | 
				        self.lock = threading.Lock() | 
			
		
		
	
		
			
				 | 
				 | 
				
 | 
				 | 
				 | 
				
 | 
			
		
		
	
		
			
				 | 
				 | 
				    def update_frame(self, frame): | 
				 | 
				 | 
				    def update_frame(self, frame): | 
			
		
		
	
		
			
				 | 
				 | 
				        """Externally updates the current frame.""" | 
				 | 
				 | 
				        """Externally updates the current frame.""" | 
			
		
		
	
		
			
				 | 
				 | 
				        with self.lock: | 
				 | 
				 | 
				        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): | 
				 | 
				 | 
				    def on_need_data(self, src, length): | 
			
		
		
	
		
			
				 | 
				 | 
				        """Provides frames when the pipeline requests data.""" | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				 | 
				 | 
				 | 
				        """Provides frames to the pipeline when requested.""" | 
			
		
		
	
		
			
				 | 
				 | 
				        with self.lock: | 
				 | 
				 | 
				        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 = Gst.Buffer.new_allocate(None, len(data), None) | 
			
		
		
	
		
			
				 | 
				 | 
				        buf.fill(0, data) | 
				 | 
				 | 
				        buf.fill(0, data) | 
			
		
		
	
	
		
			
				| 
					
					
					
						
							
						
					
				 | 
				@ -64,38 +55,74 @@ class VideoStream(GstRtspServer.RTSPMediaFactory): | 
			
		
		
	
		
			
				 | 
				 | 
				            "! h264parse ! rtph264pay config-interval=1 name=pay0 pt=96" | 
				 | 
				 | 
				            "! h264parse ! rtph264pay config-interval=1 name=pay0 pt=96" | 
			
		
		
	
		
			
				 | 
				 | 
				        ).format(self.width, self.height, self.fps) | 
				 | 
				 | 
				        ).format(self.width, self.height, self.fps) | 
			
		
		
	
		
			
				 | 
				 | 
				
 | 
				 | 
				 | 
				
 | 
			
		
		
	
		
			
				 | 
				 | 
				
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				        pipeline = Gst.parse_launch(pipeline_str) | 
				 | 
				 | 
				        pipeline = Gst.parse_launch(pipeline_str) | 
			
		
		
	
		
			
				 | 
				 | 
				        src = pipeline.get_by_name("source") | 
				 | 
				 | 
				        src = pipeline.get_by_name("source") | 
			
		
		
	
		
			
				 | 
				 | 
				        src.connect("need-data", self.on_need_data) | 
				 | 
				 | 
				        src.connect("need-data", self.on_need_data) | 
			
		
		
	
		
			
				 | 
				 | 
				        return pipeline | 
				 | 
				 | 
				        return pipeline | 
			
		
		
	
		
			
				 | 
				 | 
				
 | 
				 | 
				 | 
				
 | 
			
		
		
	
		
			
				 | 
				 | 
				
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				class RTSPServer: | 
				 | 
				 | 
				class RTSPServer: | 
			
		
		
	
		
			
				 | 
				 | 
				    def __init__(self, ip="0.0.0.0", port=8554, mount_point="/stream"): | 
				 | 
				 | 
				    def __init__(self, ip="0.0.0.0", port=8554, mount_point="/stream"): | 
			
		
		
	
		
			
				 | 
				 | 
				        Gst.init(None) | 
				 | 
				 | 
				        Gst.init(None) | 
			
		
		
	
		
			
				 | 
				 | 
				        self.server = GstRtspServer.RTSPServer() | 
				 | 
				 | 
				        self.server = GstRtspServer.RTSPServer() | 
			
		
		
	
		
			
				 | 
				 | 
				        self.server.set_address(ip) | 
				 | 
				 | 
				        self.server.set_address(ip) | 
			
		
		
	
		
			
				 | 
				 | 
				        self.server.set_service(str(port)) | 
				 | 
				 | 
				        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.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): | 
				 | 
				 | 
				    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(): | 
				 | 
				 | 
				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(): | 
				 | 
				 | 
				# def stream_webcam(): | 
			
		
		
	
		
			
				 | 
				 | 
				#     cap = cv2.VideoCapture("/home/mht/Downloads/bcd2890d71caaf0e095b95c9b525973f61186656-360p.mp4")  # Open webcam | 
				 | 
				 | 
				#     cap = cv2.VideoCapture("/home/mht/Downloads/bcd2890d71caaf0e095b95c9b525973f61186656-360p.mp4")  # Open webcam | 
			
		
		
	
	
		
			
				| 
					
						
							
						
					
					
					
				 | 
				
  |