视频转 WEBM

python 代码

import os
import subprocess
from concurrent.futures import ThreadPoolExecutor
import tkinter as tk
from tkinter import ttk, filedialog, messagebox
from threading import Thread
import queue

class VideoConverterApp:

def __init__(self, root):
    self.root = root
    self.root.title("视频转换器")
    self.root.geometry("400x200")

    # 设置暗黑主题(macOS 需要额外支持)
    self.root.tk_setPalette(background='#2d2d2d', foreground='#ffffff')

    self.label = tk.Label(root, text="选择视频文件进行转换", bg='#2d2d2d', fg='#ffffff')
    self.label.pack(pady=10)

    self.select_button = tk.Button(root, text="选择文件", command=self.select_files, bg='#3c3c3c', fg='#ffffff')
    self.select_button.pack(pady=10)

    self.progress = ttk.Progressbar(root, orient="horizontal", length=300, mode="determinate")
    self.progress.pack(pady=20)

    self.convert_button = tk.Button(root, text="开始转换", command=self.start_conversion, state=tk.DISABLED, bg='#3c3c3c', fg='#ffffff')
    self.convert_button.pack(pady=10)

    self.video_files = []
    self.progress_queue = queue.Queue()

def select_files(self):
    self.video_files = filedialog.askopenfilenames(
        title="选择视频文件",
        filetypes=[("视频文件", "*.mp4 *.mov *.avi *.mkv *.flv *.m4v")]
    )
    if self.video_files:
        self.convert_button.config(state=tk.NORMAL)
        self.label.config(text=f"已选择 {len(self.video_files)} 个文件")

def start_conversion(self):
    self.progress["value"] = 0
    self.progress["maximum"] = len(self.video_files)
    self.convert_button.config(state=tk.DISABLED)
    self.select_button.config(state=tk.DISABLED)

    # 启动后台线程处理转换任务
    self.conversion_thread = Thread(target=self.run_conversion, daemon=True)
    self.conversion_thread.start()

    # 启动进度更新循环
    self.update_progress()

def run_conversion(self):
    with ThreadPoolExecutor(max_workers=min(6, os.cpu_count() - 2 or 4)) as executor:
        for i, _ in enumerate(executor.map(self.convert_to_webm, self.video_files)):
            self.progress_queue.put(i + 1)  # 将进度信息放入队列

    # 转换完成后,发送完成信号
    self.progress_queue.put("done")

def convert_to_webm(self, input_path):
    output_path = os.path.splitext(input_path)[0] + '.webm'
    
    if os.path.exists(output_path):
        print(f"Skipped existing: {output_path}")
        return

    ffmpeg_cmd = [
        'ffmpeg',
        '-y', '-i', input_path,
        '-c:v', 'libvpx-vp9',
        '-crf', '15',               # 质量调节核心参数
        '-b:v', '0',
        '-row-mt', '1',             # 启用行级多线程
        '-cpu-used', '2',           # 更高质量预设(相比默认值3)
        '-threads', '8',            # 针对M1 Max调整线程数
        '-slices', '8',             # 并行处理单元
        '-tile-columns', '4',       # 提升并行度
        '-frame-parallel', '1',     # 帧级并行
        '-c:a', 'libopus',
        '-b:a', '192k',
        '-vbr', 'on',
        '-vf', 'scale=iw:ih:flags=lanczos',
        '-progress', '-',           # 启用进度输出
        '-color_primaries', 'bt709',
        '-colorspace', 'bt709',
        '-color_trc', 'bt709',
        '-auto-alt-ref', '0',
        output_path
    ]

    try:
        process = subprocess.Popen(
            ffmpeg_cmd,
            stdout=subprocess.PIPE,
            stderr=subprocess.STDOUT,
            universal_newlines=True
        )

        # 实时进度解析
        while True:
            line = process.stdout.readline()
            if not line:
                break
            if 'out_time=' in line:
                time = line.split('=')[1].strip()
                print(f"Processing {input_path}: {time}", end='\r')
        
        process.wait()
        if process.returncode == 0:
            print(f"\n✅ Completed: {output_path}")
        else:
            print(f"\n❌ Failed: {input_path}")

    except Exception as e:
        print(f"\n⚠️ Error processing {input_path}: {str(e)}")

def update_progress(self):
    try:
        while True:
            # 从队列中获取进度信息
            value = self.progress_queue.get_nowait()
            if value == "done":
                messagebox.showinfo("完成", "所有转换已完成!")
                self.convert_button.config(state=tk.NORMAL)
                self.select_button.config(state=tk.NORMAL)
                self.label.config(text="选择视频文件进行转换")
                break
            else:
                self.progress["value"] = value
                self.root.update_idletasks()
    except queue.Empty:
        # 如果队列为空,继续等待
        self.root.after(100, self.update_progress)

if name == "__main__":

root = tk.Tk()
app = VideoConverterApp(root)
root.mainloop()

webm 转换.zip

附件中的可执行文件只能用在 macos

本文链接:

http://152.69.194.25:22380/index.php/archives/8/
1 + 5 =
快来做第一个评论的人吧~