Spaces:
Sleeping
Sleeping
File size: 4,810 Bytes
6a298df 90eeca9 6a298df 3269f7b 227eeeb ac394ea e2c8d12 90eeca9 6a298df 64b5200 6a298df 64b5200 d1bc6a5 64b5200 d1bc6a5 6a298df 90eeca9 ac394ea 90eeca9 e62e725 6a298df 95b7f7e 018bd02 95b7f7e 018bd02 6a298df e62e725 6a298df 018bd02 6a298df 40c772f 6a298df c3dd12a 95b7f7e c3dd12a 78f6c9b 11d27a3 e2c8d12 6a298df e62e725 6a298df 606bd1d 11d27a3 606bd1d d1bc6a5 3269f7b 9f27d12 a8ac2a3 6a298df 84f1606 018bd02 78f6c9b 90eeca9 018bd02 e62e725 64b5200 e62e725 018bd02 d1bc6a5 e62e725 d1bc6a5 6a298df d4a39d3 40c772f 6d68c77 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
from flask import Flask, Response, stream_with_context, request
import cv2
from cv2.typing import MatLike
import threading
import time
import os
import psutil
class Session:
def __init__(self, id: str):
self.id = id
self.latest_frame: MatLike = None
self.published_frame: MatLike = None
self.measured_fps = 0
self.cpu_usage = 0
self.show_stats = True
app = Flask(__name__)
PORT = int(os.environ.get("PORT", 5000))
sessions: dict[str, Session] = {}
def draw_stats(frame: MatLike, session: Session):
font = cv2.FONT_HERSHEY_SIMPLEX
font_scale = 1
thickness = 2
color = (0, 255, 0)
text = f"""
ID: {session.id}
FPS: {session.measured_fps:.0f}
CPU: {session.cpu_usage:02.0f}%
"""
y0, dy = 30, 36
for i, line in enumerate(text.split("\n")):
(text_width, text_height), _ = cv2.getTextSize(line, font, font_scale, thickness)
x = frame.shape[1] - text_width - 10
y = y0 + (i - 1) * dy
cv2.putText(frame, line, (x, y), font, font_scale, color, thickness, cv2.LINE_AA)
def process_frame(session_id: str, video_path: str):
global sessions
session: Session = sessions.get(session_id, None)
if session is not None:
cap = cv2.VideoCapture(video_path)
framerate = cap.get(cv2.CAP_PROP_FPS)
frame_duration = 1 / framerate
# variables to measure FPS
frame_count = 0
last_time = time.time()
rolling_duration = 0.5
# variables to control framerate
next_frame_time = time.time()
while True:
if session_id not in sessions:
break
# control framerate
if time.time() >= next_frame_time:
ret, frame = cap.read()
# measure FPS
frame_count += 1
now = time.time()
if now - last_time >= rolling_duration:
session.measured_fps = frame_count / (now - last_time)
session.cpu_usage = psutil.cpu_percent(interval=None)
frame_count = 0
last_time = now
if not ret:
cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
continue
else:
if session.show_stats:
draw_stats(frame, session)
session.latest_frame = frame
next_frame_time += frame_duration
else:
time.sleep(0.01)
def stream_mjpeg(session_id: str):
global sessions
session: Session = sessions.get(session_id, None)
if session is not None:
while True:
if session.published_frame is session.latest_frame:
time.sleep(0.01)
else:
if session.latest_frame is None:
continue
encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), 50]
ret, jpeg = cv2.imencode(".jpg", session.latest_frame, encode_param)
frame_bytes = jpeg.tobytes() if ret else None
if frame_bytes is not None:
session.published_frame = session.latest_frame
yield (b"--frame\r\n"b"Content-Type: image/jpeg\r\n\r\n" + frame_bytes + b"\r\n")
@app.get("/")
def get_video():
global sessions
session_id = request.args.get("video_index", "0")
show_stats = request.args.get("show_stats", "1") == "1"
video_index = int(request.args.get("video_index", 0)) % 4
video_files = sorted([f for f in os.listdir("videos") if f.lower().endswith((".mp4", ".avi", ".mov"))])
video_path = os.path.join("videos", video_files[int(video_index)])
if session_id not in sessions:
session = Session(session_id)
sessions[session_id] = session
threading.Thread(target=process_frame, args=[session_id, video_path], daemon=True).start()
else:
session = sessions[session_id]
session.show_stats = show_stats
return Response(stream_with_context(stream_mjpeg(session_id)), mimetype="multipart/x-mixed-replace; boundary=frame")
@app.get("/sessions")
def get_sessions():
global sessions
return {
"sessions": [session.id for session in sessions.values()]
}
@app.get("/threads")
def get_threads():
threads = threading.enumerate()
return {
"threads_count": len(threads)
}
@app.get("/killall")
def kill_all():
global sessions
sessions.clear()
for thread in threading.enumerate():
if thread is not threading.current_thread():
thread.join(0.1)
return {"status": "all sessions cleared and threads joined"}
if __name__ == "__main__":
app.run(host="0.0.0.0", port=PORT, threaded=True) |