Debian 12服务器上Flask渲染RTSP摄像头流10秒后冻结的问题求助
Debian 12服务器上Flask渲染RTSP摄像头流10秒后冻结的问题求助
我现在在尝试用Flask模板渲染RTSP摄像头流,在Windows本地运行时视频完全正常,但部署到Debian 12的Linux服务器上就出问题了——视频大概运行10秒就会冻结,之后必须断开重连才能恢复。有没有人遇到过类似问题并解决了?
PS:服务器系统是Debian 12。
threaded_camera.py
import cv2 import time import logging import os from threading import Thread, Event from urllib.parse import urlparse logging.basicConfig(level=logging.INFO) class ThreadedCamera(object): def __init__(self, src): self.capture = cv2.VideoCapture(src, cv2.CAP_FFMPEG) if not self.capture.isOpened(): print(f"Failed to open stream: {src}") self.src = src self.hostname = self.extract_hostname(src) self.capture.set(cv2.CAP_PROP_BUFFERSIZE, 1) self.capture.set(cv2.CAP_PROP_FRAME_WIDTH, 640) self.capture.set(cv2.CAP_PROP_FPS, 30) self.min_fps = 10 self.FPS = 1/30 self.FPS_MS = int(self.FPS * 1000) self.status, self.frame = self.capture.read() self.frame_count = 0 self.total_time = 0 self.origin_info = { "width": 0, "height": 0, "fps": 0, "codec": '', "latency": False, "processing_time": 0 } self.transcoded_info = { "width": 640, "height": 480, "fps": 30, "codec": 'mjpg', "latency": False, "processing_time": 0 } # Start frame retrieval thread self.thread = Thread(target=self.update, args=()) self.thread.daemon = True self.thread.start() def extract_hostname(self, url): parsed_url = urlparse(url) return parsed_url.hostname def update(self): while True: if self.capture.isOpened(): start_time = time.time() self.status, self.frame = self.capture.read() network_latency = self.check_network_latency(self.hostname) end_time = time.time() logging.info(f"Status: {self.status}, Start Time: {start_time}, End Time: {end_time}, Duration: {end_time - start_time}") self.frame_count += 1 self.total_time += (end_time - start_time) if self.status: logging.info(f"Frame Count: {self.frame_count}, Total Time: {self.total_time}") # Update origin info self.origin_info['width'] = self.capture.get(cv2.CAP_PROP_FRAME_WIDTH) self.origin_info['height'] = self.capture.get(cv2.CAP_PROP_FRAME_HEIGHT) self.origin_info['fps'] = self.capture.get(cv2.CAP_PROP_FPS) codec = int(self.capture.get(cv2.CAP_PROP_FOURCC)) self.origin_info['codec'] = ''.join([chr((codec >> 8 * i) & 0xFF) for i in range(4)]) self.origin_info['latency'] = network_latency if self.frame_count % int(self.capture.get(cv2.CAP_PROP_FPS)) == 0: logging.info(f"Frame Count Reached FPS Interval: {self.frame_count}") avg_processing_time = self.total_time / self.frame_count if self.frame_count > 0 else 0 logging.info(f"Average Processing Time: {avg_processing_time}, Network Latency: {network_latency}") self.adjust_stream_settings(avg_processing_time, network_latency) self.transcoded_info['latency'] = network_latency self.transcoded_info['processing_time'] = round(avg_processing_time * 1000, 4) logging.info(f"Transcoded Info Updated: {self.transcoded_info}") # Reset frame count and total time for next calculation period self.frame_count = 0 self.total_time = 0 time.sleep(self.FPS) def check_network_latency(self, hostname): # response = os.system(f"ping -c 1 {hostname}") # return response == 0 return 1 def get_frame(self): if self.frame is not None: self.frame = self.resize_frame(self.frame, width=640) _, buffer = cv2.imencode('.webp', self.frame) self.transcoded_info['width'] = self.frame.shape[1] self.transcoded_info['height'] = self.frame.shape[0] return buffer.tobytes() return None def stop(self): self.stopped.set() self.thread.join() self.capture.release() def resize_frame(self, frame, width): height = int(width * (frame.shape[0] / frame.shape[1])) return cv2.resize(frame, (width, height)) def adjust_stream_settings(self, avg_processing_time, network_latency): current_fps = self.capture.get(cv2.CAP_PROP_FPS) if avg_processing_time > 0.1 or not network_latency: new_fps = max(self.min_fps, current_fps - 5) else: new_fps = current_fps + 5 # Incremento mais suave self.capture.set(cv2.CAP_PROP_FPS, new_fps) # Ensure minimum FPS if self.capture.get(cv2.CAP_PROP_FPS) < self.min_fps: self.capture.set(cv2.CAP_PROP_FPS, self.min_fps) self.FPS = 1 / self.capture.get(cv2.CAP_PROP_FPS) self.FPS_MS = int(self.FPS * 1000) def get_origin_stream_info(self): logging.info(f"get_origin_stream_info: {self.transcoded_info}") return self.origin_info def get_transcoded_stream_info(self): logging.info(f"get_transcoded_stream_info: {self.transcoded_info}") return self.transcoded_info
stream_routes.py
from flask import Blueprint, Response, request, stream_with_context, current_app, jsonify, redirect, url_for from threaded_camera import ThreadedCamera import logging bp = Blueprint('stream', __name__) cameras = {} @bp.route('/stream') def stream(): try: rtsp_url = request.args.get('rtsp_url') if not rtsp_url: return "RTSP URL not set", 400 if rtsp_url not in cameras: cameras[rtsp_url] = ThreadedCamera(rtsp_url) camera = cameras[rtsp_url] def generate(): while True: try: frame = camera.get_frame() if frame: yield (b'--frame\r\n' b'Content-Type: image/webp\r\n\r\n' + frame + b'\r\n') except Exception as e: current_app.logger.error(f"Error generating frame: {e}") break return Response(stream_with_context(generate()), mimetype='multipart/x-mixed-replace; boundary=frame') except Exception as e: current_app.logger.error(f"Error in /stream route: {e}") return "Internal Server Error", 500 @bp.route('/stop') def stop_stream(): try: rtsp_url = request.args.get('rtsp_url') if not rtsp_url: return "RTSP URL not set", 400 if rtsp_url in cameras: cameras[rtsp_url].stop() del cameras[rtsp_url] return redirect(url_for('view_stream')) except Exception as e: current_app.logger.error(f"Error in /stop route: {e}") return redirect(url_for('view_stream')) @bp.route('/stream_info') def stream_info(): try: rtsp_url = request.args.get('rtsp_url') if not rtsp_url: return jsonify(error="RTSP URL not set"), 400 camera = ThreadedCamera(rtsp_url) origin_info = camera.get_origin_stream_info() trans_info = camera.get_transcoded_stream_info() return jsonify( origin=origin_info, transcoded=trans_info ) except Exception as e: logging.error(f"Error in stream_info: {e}") return jsonify(error="Internal Server Error"), 500
Gunicorn日志
(ivia_dev) root@srv527791:/var/www/ivia_dev# journalctl -u app.service -f Dec 09 04:28:11 srv527791 systemd[1]: Started app.service - Gunicorn instance to serve your application. Dec 09 04:28:11 srv527791 gunicorn[469]: [2024-12-09 04:28:11 +0000] [469] [INFO] Starting gunicorn 23.0.0 Dec 09 04:28:11 srv527791 gunicorn[469]: [2024-12-09 04:28:11 +0000] [469] [INFO] Listening at: unix:/var/www/ivia_dev/app.sock (469) Dec 09 04:28:11 srv527791 gunicorn[469]: [2024-12-09 04:28:11 +0000] [469] [INFO] Using worker: sync Dec 09 04:28:11 srv527791 gunicorn[493]: [2024-12-09 04:28:11 +0000] [493] [INFO] Booting worker with pid: 493 Dec 09 04:28:11 srv527791 gunicorn[495]: [2024-12-09 04:28:11 +0000] [495] [INFO] Booting worker with pid: 495 Dec 09 04:28:11 srv527791 gunicorn[500]: [2024-12-09 04:28:11 +0000] [500] [INFO] Booting worker with pid: 500 Dec 09 04:30:32 srv527791 gunicorn[469]: [2024-12-09 04:30:32 +0000] [469] [CRITICAL] WORKER TIMEOUT (pid:493) Dec 09 04:30:32 srv527791 gunicorn[493]: [2024-12-09 04:30:32 +0000] [493] [ERROR] Error handling request /stream?rtsp_url=htt
备注:内容来源于stack exchange,提问作者Demon0102
相关产品推荐
相关产品推荐

