add services
This commit is contained in:
+18
-21
@@ -9,23 +9,26 @@ import os
|
||||
import threading
|
||||
import time
|
||||
from datetime import datetime
|
||||
from flask import Flask, Response, jsonify, render_template, send_from_directory
|
||||
|
||||
from flask import Flask, Response, jsonify, render_template, send_from_directory
|
||||
from libcamera import Transform
|
||||
from picamera2 import Picamera2
|
||||
from picamera2.encoders import JpegEncoder
|
||||
from picamera2.outputs import FileOutput
|
||||
from PIL import Image
|
||||
|
||||
# ─── 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
|
||||
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
|
||||
PHOTOS_DIR = os.path.join(os.path.dirname(__file__), "photos")
|
||||
|
||||
# ─── Buffer de frames thread-safe ─────────────────────────────────────────────
|
||||
|
||||
|
||||
class StreamOutput(io.BufferedIOBase):
|
||||
def __init__(self):
|
||||
self.frame = None
|
||||
@@ -43,7 +46,8 @@ picam2 = Picamera2()
|
||||
|
||||
video_config = picam2.create_video_configuration(
|
||||
main={"size": RESOLUTION, "format": "RGB888"},
|
||||
controls={"FrameRate": FRAMERATE}
|
||||
transform=Transform(rotation=90),
|
||||
controls={"FrameRate": FRAMERATE},
|
||||
)
|
||||
picam2.configure(video_config)
|
||||
|
||||
@@ -58,16 +62,14 @@ os.makedirs(PHOTOS_DIR, exist_ok=True)
|
||||
|
||||
# ─── 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"
|
||||
)
|
||||
yield (b"--frame\r\nContent-Type: image/jpeg\r\n\r\n" + frame + b"\r\n")
|
||||
|
||||
|
||||
# ─── Application Flask ────────────────────────────────────────────────────────
|
||||
@@ -78,10 +80,7 @@ app = Flask(__name__)
|
||||
@app.route("/")
|
||||
def index():
|
||||
return render_template(
|
||||
"index.html",
|
||||
width=RESOLUTION[0],
|
||||
height=RESOLUTION[1],
|
||||
quality=QUALITY
|
||||
"index.html", width=RESOLUTION[0], height=RESOLUTION[1], quality=QUALITY
|
||||
)
|
||||
|
||||
|
||||
@@ -94,8 +93,8 @@ def capture():
|
||||
|
||||
filename = datetime.now().strftime("%Y%m%d_%H%M%S.jpg")
|
||||
filepath = os.path.join(PHOTOS_DIR, filename)
|
||||
with open(filepath, "wb") as f:
|
||||
f.write(frame)
|
||||
image = Image.open(io.BytesIO(frame)).rotate(-90, expand=True)
|
||||
image.save(filepath, "JPEG", quality=QUALITY)
|
||||
|
||||
return jsonify({"status": "ok", "file": filename})
|
||||
|
||||
@@ -103,8 +102,7 @@ def capture():
|
||||
@app.route("/photos")
|
||||
def photos():
|
||||
files = sorted(
|
||||
[f for f in os.listdir(PHOTOS_DIR) if f.endswith(".jpg")],
|
||||
reverse=True
|
||||
[f for f in os.listdir(PHOTOS_DIR) if f.endswith(".jpg")], reverse=True
|
||||
)[:5]
|
||||
return jsonify(files)
|
||||
|
||||
@@ -118,8 +116,7 @@ def photo(filename):
|
||||
def video_feed():
|
||||
"""Endpoint du flux MJPEG."""
|
||||
return Response(
|
||||
generate_frames(),
|
||||
mimetype="multipart/x-mixed-replace; boundary=frame"
|
||||
generate_frames(), mimetype="multipart/x-mixed-replace; boundary=frame"
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user