python+ffmpeg 屏幕录制程序

python+ffmpeg 屏幕录制程序

不同平台使用对应的ffmpeg

例如 windows on arm 平台使用这个:
https://github.com/wmx-github/ffmpeg-wos-arm64-build/releases

ScreenRecorder.py :

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()
相关推荐
databook6 小时前
Manim实现闪光轨迹特效
后端·python·动效
Juchecar7 小时前
解惑:NumPy 中 ndarray.ndim 到底是什么?
python
用户8356290780517 小时前
Python 删除 Excel 工作表中的空白行列
后端·python
Json_7 小时前
使用python-fastApi框架开发一个学校宿舍管理系统-前后端分离项目
后端·python·fastapi
数据智能老司机14 小时前
精通 Python 设计模式——分布式系统模式
python·设计模式·架构
数据智能老司机15 小时前
精通 Python 设计模式——并发与异步模式
python·设计模式·编程语言
数据智能老司机15 小时前
精通 Python 设计模式——测试模式
python·设计模式·架构
数据智能老司机15 小时前
精通 Python 设计模式——性能模式
python·设计模式·架构
c8i15 小时前
drf初步梳理
python·django
每日AI新事件15 小时前
python的异步函数
python