当前位置: 首页 > article >正文

python+ffmpeg 屏幕录制程序

python+ffmpeg 屏幕录制程序

不同平台使用对应的ffmpeg

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

ScreenRecorder.py :

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()

http://www.kler.cn/news/358693.html

相关文章:

  • 多系统萎缩患者必看!这些维生素是你的“生命守护者”✨
  • 美国Honeywell霍尼韦尔气体检测仪SPXCDALMCX说明书
  • XML Schema 复合空元素
  • 若依前后端框架学习——新建模块(图文详解)
  • 深度学习相关知识点
  • 029 elasticsearch文档管理(ElasticsearchRepository、ElasticsearchRestTemplate)
  • VScode远程服务器之远程 远程容器 进行开发(五)
  • 第二代GPT-SoVITS V2:让声音克隆变得简单
  • Spark广播变量(类似小表广播)
  • 关于django这个python服务器的并发能力?
  • Java EE规范
  • 白炽灯和节能灯哪个更护眼?央视公认最好的护眼灯分享
  • Vue.js组件开发:深入理解与代码实现
  • 安装nginx实现多ip访问多网站
  • Vue中watch侦听器(监视器)
  • C语言 | Leetcode C语言题解之第496题下一个更大元素I
  • 解决后端给前端的返回数据过大的问题(压缩)
  • 代码工具箱:18个实用的 JavaScript 函数
  • pytorch 张量的masked_fill函数介绍
  • flutter TabBar自定义指示器(带文字的指示器、上弦弧形指示器、条形背景指示器、渐变色的指示器)