#!/usr/bin/env python3 """ Serveur Flask - Stream vidéo Raspberry Pi HQ Camera M12 Compatible Raspberry Pi 4 et 5 avec Picamera2 """ import io import threading import time from flask import Flask, Response, render_template_string from picamera2 import Picamera2 from picamera2.encoders import JpegEncoder from picamera2.outputs import FileOutput # ─── Configuration ──────────────────────────────────────────────────────────── RESOLUTION = (1280, 720) # Résolution du stream (largeur, hauteur) FRAMERATE = 30 # Images par seconde QUALITY = 85 # Qualité JPEG (1-100) HOST = "0.0.0.0" # Ecoute sur toutes les interfaces réseau PORT = 5000 # ─── Buffer de frames thread-safe ───────────────────────────────────────────── class StreamOutput(io.BufferedIOBase): def __init__(self): self.frame = None self.condition = threading.Condition() def write(self, buf): with self.condition: self.frame = buf self.condition.notify_all() # ─── Initialisation caméra ──────────────────────────────────────────────────── picam2 = Picamera2() video_config = picam2.create_video_configuration( main={"size": RESOLUTION, "format": "RGB888"}, controls={"FrameRate": FRAMERATE} ) picam2.configure(video_config) output = StreamOutput() encoder = JpegEncoder(q=QUALITY) picam2.start_recording(encoder, FileOutput(output)) print(f"[✓] Caméra démarrée ({RESOLUTION[0]}x{RESOLUTION[1]} @ {FRAMERATE}fps)") # ─── Générateur MJPEG ───────────────────────────────────────────────────────── def generate_frames(): """Génère un flux MJPEG frame par frame.""" while True: with output.condition: output.condition.wait() frame = output.frame yield ( b"--frame\r\n" b"Content-Type: image/jpeg\r\n\r\n" + frame + b"\r\n" ) # ─── Interface HTML ─────────────────────────────────────────────────────────── HTML_PAGE = """ Pi Camera Stream

Raspberry Pi Camera

HQ Camera M12 — Live Stream

Camera stream
""" # ─── Application Flask ──────────────────────────────────────────────────────── app = Flask(__name__) @app.route("/") def index(): return render_template_string( HTML_PAGE, width=RESOLUTION[0], height=RESOLUTION[1], quality=QUALITY ) @app.route("/video_feed") def video_feed(): """Endpoint du flux MJPEG.""" return Response( generate_frames(), mimetype="multipart/x-mixed-replace; boundary=frame" ) # ─── Lancement ──────────────────────────────────────────────────────────────── if __name__ == "__main__": try: print(f"[✓] Serveur démarré → http://{HOST}:{PORT}") print(f" Accès local : http://localhost:{PORT}") print(f" Accès réseau : http://:{PORT}") app.run(host=HOST, port=PORT, threaded=True) except KeyboardInterrupt: print("\n[!] Arrêt du serveur...") finally: picam2.stop_recording() picam2.close() print("[✓] Caméra arrêtée proprement.")