如何修改PySimpleGUI录屏代码以解决录制文件无法打开问题
解决PySimpleGUI摄像头应用录制文件无法打开的问题
核心问题是GUI事件循环和视频录制逻辑抢占主线程资源,导致视频文件写入不完整(比如缺少文件头、帧数据中断),最终无法正常打开。以下是具体修改方案:
关键修改思路
- 将录制逻辑移到独立线程运行,避免阻塞GUI事件循环
- 确保录制结束时完整释放视频写入器和摄像头资源
- 避免在GUI事件回调中执行耗时的帧处理/写入操作
修改后的代码示例
1. 封装录制线程类
import threading import cv2 class RecorderThread(threading.Thread): def __init__(self, cap, output_path, fps=20.0, frame_size=None): super().__init__() self.cap = cap self.output_path = output_path self.fps = fps self.frame_size = frame_size if frame_size else (int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)), int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))) self.is_recording = False self.writer = None def run(self): self.is_recording = True # 选择兼容性好的编码格式,AVI用XVID,MP4用mp4v fourcc = cv2.VideoWriter_fourcc(*'XVID') self.writer = cv2.VideoWriter(self.output_path, fourcc, self.fps, self.frame_size) while self.is_recording: ret, frame = self.cap.read() if ret: self.writer.write(frame) else: break # 强制释放写入器,保证文件写入完整 if self.writer: self.writer.release() self.is_recording = False def stop(self): self.is_recording = False
2. 整合GUI主逻辑
import PySimpleGUI as sg # 初始化摄像头 cap = cv2.VideoCapture(0) if not cap.isOpened(): sg.popup_error("无法打开摄像头") exit() # GUI布局 layout = [ [sg.Image(key='-CAM_FEED-')], [sg.Button('开始录制', key='-START-'), sg.Button('停止录制', key='-STOP-'), sg.Button('退出')] ] window = sg.Window('Camera App.', layout, finalize=True) recorder = None while True: # 超时读取事件,保证摄像头画面实时刷新 event, values = window.read(timeout=15) # 退出逻辑:先停止录制再释放资源 if event in (sg.WIN_CLOSED, '退出'): if recorder and recorder.is_recording: recorder.stop() recorder.join() # 等待线程完全结束 cap.release() window.close() break # 更新摄像头画面到GUI ret, frame = cap.read() if ret: img_bytes = cv2.imencode('.png', frame)[1].tobytes() window['-CAM_FEED-'].update(data=img_bytes) # 开始录制 if event == '-START-': if not (recorder and recorder.is_recording): recorder = RecorderThread(cap, 'recorded_video.avi') recorder.start() sg.popup_auto_close("录制已启动", auto_close_duration=1) # 停止录制 if event == '-STOP-': if recorder and recorder.is_recording: recorder.stop() recorder.join() sg.popup_auto_close("录制已停止", auto_close_duration=1)
重要说明
- 编码格式匹配:输出文件后缀要和编码格式对应,比如用
XVID编码对应.avi,mp4v对应.mp4,否则文件可能无法播放。 - 资源释放顺序:必须先停止录制线程,等待线程执行完释放
VideoWriter,再释放摄像头,否则会导致文件损坏。 - 线程安全:录制线程只负责读取帧并写入,主线程负责GUI更新和摄像头初始化/释放,避免多线程同时操作摄像头对象引发冲突。
内容的提问来源于stack exchange,提问作者tkr
相关产品推荐
相关产品推荐

