Last active
May 14, 2025 22:26
-
-
Save krisstibex/0bfaf72b63734b89ff89ba791a7c1d7f to your computer and use it in GitHub Desktop.
使用FFMPEG的视频处理压缩gui脚本 需要安装FFMPEG
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
tkinter | |
tkinterdnd2 | |
subprocess32 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import tkinter as tk | |
from tkinter import filedialog, messagebox | |
from tkinterdnd2 import DND_FILES, TkinterDnD | |
import subprocess | |
import os | |
from pathlib import Path | |
def select_file(): | |
file_path = filedialog.askopenfilename(filetypes=[("Video Files", "*.mp4 *.mkv *.mov *.avi")]) | |
input_path_var.set(file_path) | |
update_output_name() | |
def handle_drop(data): | |
if data: | |
path = data.strip('{}') # Windows 拖拽带花括号 | |
input_path_var.set(path) | |
update_output_name() | |
def update_output_name(): | |
input_path = input_path_var.get() | |
if input_path: | |
name = Path(input_path).stem | |
ext = ".mkv" if codec_var.get() == "libsvtav1" else ".mp4" | |
output_name_var.set(f"compressed_{name}{ext}") | |
def toggle_crf_mode(): | |
use_crf = use_crf_var.get() | |
crf_entry.config(state="normal" if use_crf else "disabled") | |
bitrate_entry.config(state="disabled" if use_crf else "normal") | |
def toggle_audio_settings(): | |
state = "disabled" if remove_audio_var.get() else "normal" | |
audio_codec_menu.config(state=state) | |
audio_bitrate_entry.config(state=state) | |
def compress(): | |
input_path = input_path_var.get() | |
if not Path(input_path).is_file(): | |
messagebox.showerror("错误", "无效输入文件路径") | |
return | |
output_path = Path.cwd() / output_name_var.get() | |
cmd = ["ffmpeg", "-y", "-i", input_path] | |
if resolution_var.get(): | |
cmd += ["-s", resolution_var.get()] | |
if framerate_var.get(): | |
cmd += ["-r", framerate_var.get()] | |
cmd += ["-c:v", codec_var.get()] | |
if use_crf_var.get(): | |
cmd += ["-crf", crf_var.get()] | |
else: | |
cmd += ["-b:v", bitrate_var.get()] | |
cmd += ["-preset", preset_var.get()] | |
if threads_var.get().isdigit() and int(threads_var.get()) > 0: | |
cmd += ["-threads", threads_var.get()] | |
if remove_audio_var.get(): | |
cmd += ["-an"] | |
else: | |
cmd += ["-c:a", audio_codec_var.get(), "-b:a", audio_bitrate_var.get()] | |
if two_pass_var.get(): | |
null_output = "NUL" if os.name == 'nt' else "/dev/null" | |
try: | |
subprocess.run(cmd + ["-pass", "1", "-f", "null", null_output], check=True) | |
subprocess.run(cmd + ["-pass", "2", str(output_path)], check=True) | |
except subprocess.CalledProcessError: | |
messagebox.showerror("错误", "两遍压缩失败!") | |
return | |
else: | |
cmd += [str(output_path)] | |
try: | |
subprocess.run(cmd, check=True) | |
except subprocess.CalledProcessError: | |
messagebox.showerror("错误", "压缩失败,请检查 FFmpeg 是否正确安装") | |
return | |
messagebox.showinfo("完成", f"压缩完成:\n{output_path}") | |
# ----------------- GUI 构建 ----------------- | |
app = TkinterDnD.Tk() | |
app.title("🎬 FFmpeg 视频压缩器(拖放支持)") | |
# 输入文件路径(拖放) | |
input_path_var = tk.StringVar() | |
tk.Label(app, text="视频文件路径").grid(row=0, column=0, sticky="e") | |
input_entry = tk.Entry(app, textvariable=input_path_var, width=40) | |
input_entry.grid(row=0, column=1) | |
input_entry.drop_target_register(DND_FILES) | |
input_entry.dnd_bind('<<Drop>>', lambda e: handle_drop(e.data)) | |
tk.Button(app, text="选择文件", command=select_file).grid(row=0, column=2) | |
# 编码器 | |
codec_var = tk.StringVar(value="libx264") | |
tk.Label(app, text="视频编码器").grid(row=1, column=0, sticky="e") | |
tk.OptionMenu(app, codec_var, "libx264", "libx265", "libsvtav1", command=lambda _: update_output_name()).grid(row=1, column=1, sticky="w") | |
# 分辨率和帧率 | |
resolution_var = tk.StringVar(value="1280x720") | |
framerate_var = tk.StringVar(value="30") | |
tk.Label(app, text="分辨率").grid(row=2, column=0, sticky="e") | |
tk.Entry(app, textvariable=resolution_var).grid(row=2, column=1, sticky="w") | |
tk.Label(app, text="帧率").grid(row=3, column=0, sticky="e") | |
tk.Entry(app, textvariable=framerate_var).grid(row=3, column=1, sticky="w") | |
# CRF / 码率 | |
use_crf_var = tk.BooleanVar(value=True) | |
tk.Checkbutton(app, text="使用 CRF 模式", variable=use_crf_var, command=toggle_crf_mode).grid(row=4, column=1, sticky="w") | |
crf_var = tk.StringVar(value="23") | |
bitrate_var = tk.StringVar(value="2000k") | |
tk.Label(app, text="CRF").grid(row=5, column=0, sticky="e") | |
crf_entry = tk.Entry(app, textvariable=crf_var) | |
crf_entry.grid(row=5, column=1, sticky="w") | |
tk.Label(app, text="码率").grid(row=6, column=0, sticky="e") | |
bitrate_entry = tk.Entry(app, textvariable=bitrate_var) | |
bitrate_entry.grid(row=6, column=1, sticky="w") | |
# 音频设置 | |
remove_audio_var = tk.BooleanVar(value=False) | |
tk.Checkbutton(app, text="移除音频", variable=remove_audio_var, command=toggle_audio_settings).grid(row=7, column=1, sticky="w") | |
audio_codec_var = tk.StringVar(value="aac") | |
audio_bitrate_var = tk.StringVar(value="128k") | |
tk.Label(app, text="音频编码器").grid(row=8, column=0, sticky="e") | |
audio_codec_menu = tk.OptionMenu(app, audio_codec_var, "aac", "libopus", "libmp3lame") | |
audio_codec_menu.grid(row=8, column=1, sticky="w") | |
tk.Label(app, text="音频码率").grid(row=9, column=0, sticky="e") | |
audio_bitrate_entry = tk.Entry(app, textvariable=audio_bitrate_var) | |
audio_bitrate_entry.grid(row=9, column=1, sticky="w") | |
# 高级设置 | |
preset_var = tk.StringVar(value="medium") | |
threads_var = tk.StringVar(value="0") | |
two_pass_var = tk.BooleanVar(value=False) | |
tk.Label(app, text="Preset").grid(row=10, column=0, sticky="e") | |
tk.OptionMenu(app, preset_var, "ultrafast", "fast", "medium", "slow", "veryslow").grid(row=10, column=1, sticky="w") | |
tk.Label(app, text="线程数").grid(row=11, column=0, sticky="e") | |
tk.Entry(app, textvariable=threads_var).grid(row=11, column=1, sticky="w") | |
tk.Checkbutton(app, text="启用两遍压缩", variable=two_pass_var).grid(row=12, column=1, sticky="w") | |
# 输出文件名(自动) | |
output_name_var = tk.StringVar(value="compressed_output.mp4") | |
tk.Label(app, text="输出文件名").grid(row=13, column=0, sticky="e") | |
tk.Entry(app, textvariable=output_name_var, width=30).grid(row=13, column=1, sticky="w") | |
# 开始压缩 | |
tk.Button(app, text="开始压缩", command=compress, bg="#4CAF50", fg="white", width=20).grid(row=14, column=1, pady=10) | |
toggle_crf_mode() | |
toggle_audio_settings() | |
app.mainloop() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment