#!/usr/bin/env python3 """ Simple HTTP server that proxies MJPEG stream from tcpserversink Adds proper HTTP headers for browser compatibility """ import socket import sys from http.server import HTTPServer, BaseHTTPRequestHandler from socketserver import ThreadingMixIn class MJPEGProxyHandler(BaseHTTPRequestHandler): tcp_host = 'localhost' tcp_port = 9000 def do_GET(self): """Handle GET requests and proxy the MJPEG stream""" try: # Connect to the GStreamer tcpserversink sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((self.tcp_host, self.tcp_port)) # Send HTTP headers self.send_response(200) self.send_header('Content-Type', 'multipart/x-mixed-replace; boundary=--videoboundary') self.send_header('Cache-Control', 'no-cache') self.send_header('Pragma', 'no-cache') self.send_header('Connection', 'close') self.end_headers() # Stream data from TCP socket to HTTP client while True: data = sock.recv(4096) if not data: break self.wfile.write(data) except Exception as e: print(f"Error: {e}", file=sys.stderr) finally: try: sock.close() except: pass def log_message(self, format, *args): """Custom logging""" print(f"[{self.client_address[0]}] {format % args}") class ThreadedHTTPServer(ThreadingMixIn, HTTPServer): """Handle requests in separate threads""" pass if __name__ == '__main__': tcp_port = int(sys.argv[1]) if len(sys.argv) > 1 else 8081 http_port = int(sys.argv[2]) if len(sys.argv) > 2 else 8080 MJPEGProxyHandler.tcp_port = tcp_port server = ThreadedHTTPServer(('0.0.0.0', http_port), MJPEGProxyHandler) print(f"MJPEG HTTP Proxy Server") print(f"========================") print(f"Proxying TCP stream from localhost:{tcp_port}") print(f"HTTP server listening on port {http_port}") print(f"") print(f"Configure vizionStreamer with:") print(f' ./scripts/set_pipeline_mjpeg.sh {tcp_port}') print(f"") print(f"Access stream at: http://localhost:{http_port}") print(f"") try: server.serve_forever() except KeyboardInterrupt: print("\nShutting down...") server.shutdown()