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()
相关推荐
顾安r16 分钟前
11.5 脚本 本地网站收藏(解封归来)
linux·服务器·c语言·python·bash
Blossom.11823 分钟前
把AI“贴”进路灯柱:1KB决策树让老旧路灯自己报「灯头松动」
java·人工智能·python·深度学习·算法·决策树·机器学习
❀͜͡傀儡师36 分钟前
快速定位并解决Java应用CPU占用过高问题
java·开发语言·python
linuxxx11039 分钟前
django中request.GET.urlencode的使用
后端·python·django
冬天vs不冷42 分钟前
Java基础(十五):注解(Annotation)详解
android·java·python
汤姆yu1 小时前
基于大数据的全国降水可视化分析预测系统
大数据·开发语言·python
星空的资源小屋3 小时前
Text Grab,一款OCR 截图文字识别工具
python·django·ocr·scikit-learn
寒秋丶3 小时前
Milvus:Json字段详解(十)
数据库·人工智能·python·ai·milvus·向量数据库·rag
自由随风飘7 小时前
python 题目练习1~5
开发语言·python
fl1768319 小时前
基于python的天气预报系统设计和可视化数据分析源码+报告
开发语言·python·数据分析