BodyBalanceEvaluation/backend/screen_recorder.py
2025-08-20 08:54:36 +08:00

297 lines
9.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
屏幕录制工具
支持录制当前屏幕并保存为视频文件
"""
import cv2
import numpy as np
import pyautogui
import threading
import time
from datetime import datetime
import os
class ScreenRecorder:
def __init__(self, output_dir="recordings", fps=20, quality=80, region=None):
"""
初始化屏幕录制器
Args:
output_dir (str): 输出目录
fps (int): 帧率
quality (int): 视频质量 (1-100)
region (tuple): 录制区域 (x, y, width, height)None表示全屏录制
"""
self.output_dir = output_dir
self.fps = fps
self.quality = quality
self.recording = False
self.paused = False
self.video_writer = None
self.thread = None
self.region = region
# 创建输出目录
if not os.path.exists(output_dir):
os.makedirs(output_dir)
# 获取屏幕尺寸
self.screen_size = pyautogui.size()
print(f"屏幕尺寸: {self.screen_size}")
# 设置录制区域
if self.region:
x, y, width, height = self.region
# 确保区域在屏幕范围内
x = max(0, min(x, self.screen_size[0] - 1))
y = max(0, min(y, self.screen_size[1] - 1))
width = min(width, self.screen_size[0] - x)
height = min(height, self.screen_size[1] - y)
self.region = (x, y, width, height)
self.record_size = (width, height)
print(f"录制区域: {self.region}")
else:
self.record_size = self.screen_size
print("录制模式: 全屏录制")
def start_recording(self, filename=None):
"""
开始录制
Args:
filename (str): 输出文件名如果为None则自动生成
"""
if self.recording:
print("录制已在进行中")
return
if filename is None:
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
filename = f"screen_record_{timestamp}.mp4"
self.output_path = os.path.join(self.output_dir, filename)
# 设置视频编码器
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
self.video_writer = cv2.VideoWriter(
self.output_path,
fourcc,
self.fps,
self.record_size
)
self.recording = True
self.paused = False
# 在新线程中开始录制
self.thread = threading.Thread(target=self._record_loop)
self.thread.daemon = True
self.thread.start()
print(f"开始录制: {self.output_path}")
def _record_loop(self):
"""
录制循环
"""
while self.recording:
if not self.paused:
# 截取屏幕
if self.region:
# 区域录制
x, y, width, height = self.region
screenshot = pyautogui.screenshot(region=(x, y, width, height))
else:
# 全屏录制
screenshot = pyautogui.screenshot()
# 转换为numpy数组
frame = np.array(screenshot)
# 转换颜色格式 (RGB -> BGR)
frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
# 写入视频文件
self.video_writer.write(frame)
# 控制帧率
time.sleep(1.0 / self.fps)
def pause_recording(self):
"""
暂停录制
"""
if not self.recording:
print("当前没有在录制")
return
self.paused = not self.paused
status = "暂停" if self.paused else "继续"
print(f"录制{status}")
def stop_recording(self):
"""
停止录制
"""
if not self.recording:
print("当前没有在录制")
return
self.recording = False
self.paused = False
# 等待录制线程结束
if self.thread:
self.thread.join()
# 释放视频写入器
if self.video_writer:
self.video_writer.release()
self.video_writer = None
print(f"录制完成: {self.output_path}")
def set_region(self, region):
"""
设置录制区域
Args:
region (tuple): 录制区域 (x, y, width, height)None表示全屏录制
"""
if self.recording:
print("录制进行中,无法更改区域设置")
return False
self.region = region
# 重新计算录制区域
if self.region:
x, y, width, height = self.region
# 确保区域在屏幕范围内
x = max(0, min(x, self.screen_size[0] - 1))
y = max(0, min(y, self.screen_size[1] - 1))
width = min(width, self.screen_size[0] - x)
height = min(height, self.screen_size[1] - y)
self.region = (x, y, width, height)
self.record_size = (width, height)
print(f"录制区域已设置: {self.region}")
else:
self.record_size = self.screen_size
print("录制模式已设置: 全屏录制")
return True
def get_status(self):
"""
获取录制状态
Returns:
dict: 包含录制状态信息的字典
"""
return {
'recording': self.recording,
'paused': self.paused,
'output_path': getattr(self, 'output_path', None),
'screen_size': self.screen_size,
'record_size': self.record_size,
'region': self.region,
'fps': self.fps
}
def main():
"""
主函数 - 命令行界面
"""
recorder = ScreenRecorder()
print("\n=== 屏幕录制工具 ===")
print("命令:")
print(" start [filename] - 开始录制")
print(" pause - 暂停/恢复录制")
print(" stop - 停止录制")
print(" status - 查看状态")
print(" region x y w h - 设置录制区域 (x, y, 宽度, 高度)")
print(" fullscreen - 设置全屏录制")
print(" center w h - 设置居中区域录制 (宽度, 高度)")
print(" quit - 退出程序")
print("\n输入命令:")
while True:
try:
command = input("> ").strip().split()
if not command:
continue
cmd = command[0].lower()
if cmd == "start":
filename = command[1] if len(command) > 1 else None
recorder.start_recording(filename)
elif cmd == "pause":
recorder.pause_recording()
elif cmd == "stop":
recorder.stop_recording()
elif cmd == "status":
status = recorder.get_status()
print(f"录制状态: {'进行中' if status['recording'] else '已停止'}")
print(f"暂停状态: {'' if status['paused'] else ''}")
print(f"输出文件: {status['output_path']}")
print(f"屏幕尺寸: {status['screen_size']}")
print(f"录制尺寸: {status['record_size']}")
print(f"录制区域: {status['region'] if status['region'] else '全屏'}")
print(f"帧率: {status['fps']} FPS")
elif cmd == "region":
if len(command) != 5:
print("用法: region x y width height")
continue
try:
x, y, w, h = map(int, command[1:5])
if recorder.set_region((x, y, w, h)):
print(f"录制区域已设置: ({x}, {y}, {w}, {h})")
except ValueError:
print("请输入有效的数字")
elif cmd == "fullscreen":
if recorder.set_region(None):
print("已设置为全屏录制")
elif cmd == "center":
if len(command) != 3:
print("用法: center width height")
continue
try:
w, h = map(int, command[1:3])
screen_w, screen_h = recorder.screen_size
x = (screen_w - w) // 2
y = (screen_h - h) // 2
if recorder.set_region((x, y, w, h)):
print(f"居中录制区域已设置: ({x}, {y}, {w}, {h})")
except ValueError:
print("请输入有效的数字")
elif cmd == "quit":
if recorder.recording:
recorder.stop_recording()
print("程序退出")
break
else:
print("未知命令")
except KeyboardInterrupt:
if recorder.recording:
recorder.stop_recording()
print("\n程序退出")
break
except Exception as e:
print(f"错误: {e}")
if __name__ == "__main__":
main()