python+ffmpeg 屏幕录制程序
不同平台使用对应的ffmpeg
例如 windows on arm 平台使用这个:
https://github.com/wmx-github/ffmpeg-wos-arm64-build/releases
ScreenRecorder.py :
import sys
import subprocess
import tkinter as tk
from tkinter import filedialog, messagebox, ttkclass ScreenRecorder:def __init__(self, root):self.root = rootself.root.title("Screen Recorder")self.root.geometry("350x200")self.create_widgets()self.load_config()def create_widgets(self):# 创建一个Notebook(标签控件)self.notebook = ttk.Notebook(self.root)# 主界面self.main_frame = ttk.Frame(self.notebook)self.notebook.add(self.main_frame, text='Main')# 配置界面self.config_frame = ttk.Frame(self.notebook)self.notebook.add(self.config_frame, text='Config')# 按钮列表布局button_frame = ttk.Frame(self.main_frame)button_frame.pack(pady=10, fill='x')self.record_button = tk.Button(button_frame, text="Start Recording", command=self.start_recording, width=20)self.record_button.pack(pady=5, fill='x')self.play_button = tk.Button(button_frame, text="Play Video", command=self.play_video, width=20)self.play_button.pack(pady=5, fill='x')# 配置界面组件config_label_frame = ttk.LabelFrame(self.config_frame, text="Configuration")config_label_frame.pack(fill="both", expand="yes", padx=10, pady=10)# FFmpeg路径self.ffmpeg_path_var = tk.StringVar()ffmpeg_label = ttk.Label(config_label_frame, text="FFmpeg Path:")ffmpeg_label.grid(row=0, column=0, padx=5, pady=5, sticky='w')ffmpeg_entry = ttk.Entry(config_label_frame, textvariable=self.ffmpeg_path_var, width=30)ffmpeg_entry.grid(row=0, column=1, padx=5, pady=5)ffmpeg_browse_button = ttk.Button(config_label_frame, text="Browse", command=self.browse_ffmpeg)ffmpeg_browse_button.grid(row=0, column=2, padx=5, pady=5)# 文件保存路径self.save_path_var = tk.StringVar()save_path_label = ttk.Label(config_label_frame, text="Save Path:")save_path_label.grid(row=1, column=0, padx=5, pady=5, sticky='w')save_path_entry = ttk.Entry(config_label_frame, textvariable=self.save_path_var, width=30)save_path_entry.grid(row=1, column=1, padx=5, pady=5)save_path_browse_button = ttk.Button(config_label_frame, text="Browse", command=self.browse_save_path)save_path_browse_button.grid(row=1, column=2, padx=5, pady=5)self.notebook.pack(expand=1, fill='both')# 快捷键self.root.bind('<Control-r>', lambda event: self.start_recording())self.root.bind('<Control-p>', lambda event: self.play_video())self.is_recording = Falseself.record_process = Noneself.file_path = Noneself.play_process = Nonedef load_config(self):# 这里可以加载配置文件或使用默认值self.ffmpeg_path_var.set("ffmpeg")self.save_path_var.set(".")def browse_ffmpeg(self):path = filedialog.askopenfilename(filetypes=[("Executable files", "*.exe")])if path:self.ffmpeg_path_var.set(path)def browse_save_path(self):path = filedialog.askdirectory()if path:self.save_path_var.set(path)def start_recording(self):if not self.is_recording:file_path = filedialog.asksaveasfilename(initialdir=self.save_path_var.get(), defaultextension=".mp4", filetypes=[("MP4 Files", "*.mp4")])if file_path:self.file_path = file_pathffmpeg_path = self.ffmpeg_path_var.get()self.record_process = subprocess.Popen([ffmpeg_path,"-f", "gdigrab","-framerate", "25","-i", "desktop","-c:v", "libx264","-preset", "ultrafast","-crf", "0",file_path],stdin=subprocess.PIPE # Create a pipe for stdin)self.is_recording = Trueself.record_button.config(text="Stop Recording")else:self.stop_recording()def stop_recording(self):if self.record_process and self.is_recording:try:self.record_process.stdin.write(b'q') # Send 'q' to ffmpeg to request a graceful shutdownself.record_process.stdin.flush() # Ensure the command is sent immediatelyself.record_process.wait() # Wait for the process to finishexcept BrokenPipeError:pass # If the pipe is broken, the process has already terminatedfinally:self.record_process = Noneself.is_recording = Falseself.record_button.config(text="Start Recording")def play_video(self):file_path = filedialog.askopenfilename(initialdir=self.save_path_var.get(), defaultextension=".mp4", filetypes=[("MP4 Files", "*.mp4"), ("All Files", "*.*")])if file_path:ffmpeg_path = self.ffmpeg_path_var.get()self.play_process = subprocess.Popen([ffmpeg_path.replace('ffmpeg', 'ffplay'),"-autoexit", # Automatically exit when the video ends"-x", "800", # Set initial window width"-y", "600", # Set initial window height"-window_title", "Video Player", # Set window titlefile_path])def on_closing(self):if self.record_process and self.is_recording:if messagebox.askokcancel("Quit", "Recording is in progress. Do you want to stop recording and quit?"):self.stop_recording()self.root.destroy()elif self.play_process and self.play_process.poll() is None:if messagebox.askokcancel("Quit", "Video is playing. Do you want to stop playback and quit?"):self.play_process.terminate()self.play_process.wait()self.root.destroy()else:self.root.destroy()if __name__ == "__main__":root = tk.Tk()app = ScreenRecorder(root)root.protocol("WM_DELETE_WINDOW", app.on_closing)root.mainloop()