V1
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
"""Accès simple à la caméra d'Alfred, avec aperçu MJPEG activé à la demande.
|
||||
|
||||
Une seule lecture par instance Alfred. La vidéo ne démarre que lorsque
|
||||
l'utilisateur clique sur Activer, pour éviter de monopoliser la caméra.
|
||||
"""
|
||||
import os
|
||||
import threading
|
||||
import time
|
||||
|
||||
_CAMERA_LOCK = threading.Lock()
|
||||
|
||||
|
||||
def snapshot(path, index=0):
|
||||
import cv2
|
||||
if not _CAMERA_LOCK.acquire(blocking=False):
|
||||
raise RuntimeError('Caméra déjà utilisée par la prévisualisation Alfred')
|
||||
try:
|
||||
cap = cv2.VideoCapture(index)
|
||||
try:
|
||||
ok, frame = cap.read()
|
||||
finally:
|
||||
cap.release()
|
||||
if not ok:
|
||||
raise RuntimeError('Impossible de lire la caméra locale')
|
||||
cv2.imwrite(path, frame)
|
||||
return path
|
||||
finally:
|
||||
_CAMERA_LOCK.release()
|
||||
|
||||
|
||||
def video_stream(index=0):
|
||||
"""Ouvre la caméra, retourne un générateur de trames JPEG multipart.
|
||||
|
||||
L'appelant doit retourner ce générateur dans une réponse Flask en streaming.
|
||||
L'absence de cv2 ou de webcam déclenche une exception avant HTTP 200.
|
||||
"""
|
||||
import cv2
|
||||
if not _CAMERA_LOCK.acquire(blocking=False):
|
||||
raise RuntimeError('Prévisualisation vidéo déjà active')
|
||||
|
||||
cap = None
|
||||
try:
|
||||
cap = cv2.VideoCapture(index)
|
||||
if not cap.isOpened():
|
||||
cap.release()
|
||||
raise RuntimeError(f'Caméra {index} indisponible')
|
||||
cap.set(cv2.CAP_PROP_FRAME_WIDTH, int(os.getenv('CAMERA_WIDTH', '640')))
|
||||
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, int(os.getenv('CAMERA_HEIGHT', '480')))
|
||||
fps = min(15.0, max(1.0, float(os.getenv('CAMERA_FPS', '8'))))
|
||||
quality = min(95, max(35, int(os.getenv('CAMERA_JPEG_QUALITY', '75'))))
|
||||
except Exception:
|
||||
if cap is not None:
|
||||
cap.release()
|
||||
_CAMERA_LOCK.release()
|
||||
raise
|
||||
|
||||
def frames():
|
||||
try:
|
||||
while True:
|
||||
ok, frame = cap.read()
|
||||
if not ok:
|
||||
break
|
||||
ok_jpeg, encoded = cv2.imencode('.jpg', frame, [cv2.IMWRITE_JPEG_QUALITY, quality])
|
||||
if ok_jpeg:
|
||||
yield b'--frame\r\nContent-Type: image/jpeg\r\n\r\n' + encoded.tobytes() + b'\r\n'
|
||||
time.sleep(1.0 / fps)
|
||||
finally:
|
||||
cap.release()
|
||||
_CAMERA_LOCK.release()
|
||||
|
||||
return frames()
|
||||
Reference in New Issue
Block a user