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()
相关推荐
铁盒薄荷糖1 小时前
【Pytorch】Pytorch的安装
人工智能·pytorch·python
yyfhq1 小时前
rescorediff
python·深度学习·机器学习
糊涂君-Q1 小时前
Python小白学习教程从入门到入坑------第十九课 异常模块与包【下】(语法基础)
开发语言·python·学习·程序人生·改行学it
API199701081101 小时前
京东平台接口技术详解及示例代码
开发语言·前端·python
(●'◡'●)知1 小时前
基于树莓派的安保巡逻机器人--(一、快速人脸录入与精准人脸识别)
人工智能·python·opencv·机器学习·计算机视觉
秦朝胖子得加钱2 小时前
Flask
后端·python·flask
幽兰的天空2 小时前
Python实现的简单时钟
开发语言·python
NCU_AI3 小时前
Python 网络爬虫快速入门
python·网络爬虫
幽兰的天空3 小时前
简单的Python爬虫实例
开发语言·爬虫·python
IT·小灰灰4 小时前
Python——自动化发送邮件
运维·网络·后端·python·自动化