Flask部署中实现后台播放音频不阻塞OpenCV循环的方法
解决Flask中播放音频阻塞OpenCV视频流的问题
问题根源是playsound属于同步阻塞调用,执行时会卡住视频处理的主线程,导致画面卡顿。下面用你提到的threading和asyncio两种方案解决,直接替换现有代码即可。
方法1:使用threading(最简单直接,适配同步Flask)
把音频播放逻辑放到后台线程中执行,主线程继续处理视频流,完全不会阻塞。
修改后的代码
import threading from playsound import playsound # 确保已导入该库 # ... 你的其他初始化代码(比如加载模型、视频流) ... while True: ret, frame = self.video.read() results = self.model.track(frame) frame_result = results[0].plot() for r in results: boxes = r.boxes for box in boxes: c = box.cls if model.names[int(c)] == 'cell phone': # 启动后台线程播放音频,daemon=True确保线程随主线程退出 threading.Thread(target=playsound, args=('audio.mp3',), daemon=True).start() ret, jpeg = cv2.imencode('.jpg', frame_result) frame = jpeg.tobytes() yield (b'--frame\r\n' b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
可选优化:避免重复触发
如果短时间内多次检测到手机,会重复启动播放线程导致音频重叠。可以加个标志位控制:
import threading from playsound import playsound is_playing = False def play_alert(): global is_playing if not is_playing: is_playing = True playsound('audio.mp3') is_playing = False # ... 循环内的判断逻辑 ... if model.names[int(c)] == 'cell phone': threading.Thread(target=play_alert, daemon=True).start()
方法2:使用asyncio(适配异步Flask场景)
如果你的Flask应用用了2.0+的异步路由(async def定义的路由),可以用asyncio结合线程池执行同步的playsound:
修改后的代码
import asyncio from playsound import playsound # ... 异步路由内的视频循环逻辑 ... while True: ret, frame = self.video.read() results = self.model.track(frame) frame_result = results[0].plot() for r in results: boxes = r.boxes for box in boxes: c = box.cls if model.names[int(c)] == 'cell phone': # 用线程池异步执行同步播放函数 await asyncio.get_event_loop().run_in_executor(None, playsound, 'audio.mp3') ret, jpeg = cv2.imencode('.jpg', frame_result) frame = jpeg.tobytes() yield (b'--frame\r\n' b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
注意:此方案要求你的Flask路由必须是异步定义的(即async def your_route():),否则无法使用await关键字。
内容的提问来源于stack exchange,提问作者dirb
相关产品推荐
相关产品推荐

