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()
相关推荐
nuclear201118 分钟前
使用Python 在Excel中创建和取消数据分组 - 详解
python·excel数据分组·创建excel分组·excel分类汇总·excel嵌套分组·excel大纲级别·取消excel分组
Lucky小小吴33 分钟前
有关django、python版本、sqlite3版本冲突问题
python·django·sqlite
GIS 数据栈1 小时前
每日一书 《基于ArcGIS的Python编程秘笈》
开发语言·python·arcgis
爱分享的码瑞哥1 小时前
Python爬虫中的IP封禁问题及其解决方案
爬虫·python·tcp/ip
傻啦嘿哟2 小时前
如何使用 Python 开发一个简单的文本数据转换为 Excel 工具
开发语言·python·excel
B站计算机毕业设计超人2 小时前
计算机毕业设计SparkStreaming+Kafka旅游推荐系统 旅游景点客流量预测 旅游可视化 旅游大数据 Hive数据仓库 机器学习 深度学习
大数据·数据仓库·hadoop·python·kafka·课程设计·数据可视化
lxkj_20242 小时前
使用线程局部存储解决ffmpeg中多实例调用下自定义日志回调问题
ffmpeg
IT古董3 小时前
【人工智能】Python在机器学习与人工智能中的应用
开发语言·人工智能·python·机器学习
湫ccc3 小时前
《Python基础》之pip换国内镜像源
开发语言·python·pip
hakesashou3 小时前
Python中常用的函数介绍
java·网络·python