python+ffmpeg 屏幕录制程序
不同平台使用对应的ffmpeg
例如 windows on arm 平台使用这个:
https://github.com/wmx-github/ffmpeg-wos-arm64-build/releases
python
import sys
import subprocess
import tkinter as tk
from tkinter import filedialog, messagebox, ttk
class ScreenRecorder:
def __init__(self, root):
self.root = root
self.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 = False
self.record_process = None
self.file_path = None
self.play_process = None
def 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_path
ffmpeg_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 = True
self.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 shutdown
self.record_process.stdin.flush() # Ensure the command is sent immediately
self.record_process.wait() # Wait for the process to finish
except BrokenPipeError:
pass # If the pipe is broken, the process has already terminated
finally:
self.record_process = None
self.is_recording = False
self.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 title
file_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()