In this tutorial, we’ll build QuickVideo, a Windows desktop tool to batch adjust video speed with perfectly synced audio. You can drag & drop videos, preview changes, and export them in multiple formats.
You can download the EXE or clone the repository:
Windows EXE:
https://github.com/rogers-cyber/QuickVideo/releases
Source Code:
git clone https://github.com/rogers-cyber/QuickVideo.git
- Project Setup
Install the required Python packages:
pip install ttkbootstrap tkinterdnd2
Ensure you have FFmpeg installed and its path configured:
FFMPEG_PATH = r"C:\ffmpeg\bin\ffmpeg.exe"
FFPLAY_PATH = r"C:\ffmpeg\bin\ffplay.exe"
- Create the Main Window
We’ll use tkinterdnd2 for drag & drop and ttkbootstrap for a modern dark theme.
from tkinterdnd2 import TkinterDnD
import ttkbootstrap as tb
app = TkinterDnD.Tk()
app.title("QuickVideo – Change Video Speed v1.0.0")
app.geometry("1200x760")
tb.Style("darkly")
- Define Application State
Keep track of videos, UI updates, and preview state:
video_list = []
ui_queue = Queue()
stop_flag = False
pause_flag = False
preview_process = None
- Add File Selection UI
Create a file card with drag & drop support and buttons to add or clear videos:
files_card = tb.Labelframe(app, text="🎬 Video Files", padding=12)
files_card.pack(fill="x", padx=12, pady=6)
listbox = tk.Listbox(files_card, height=4)
listbox.pack(side="left", fill="x", expand=True)
scroll = tk.Scrollbar(files_card, command=listbox.yview)
scroll.pack(side="right", fill="y")
listbox.config(yscrollcommand=scroll.set)
Add buttons to add or clear videos:
tb.Button(files_card, text="➕ Add Files", bootstyle="success", command=add_videos).pack(side="left")
tb.Button(files_card, text="🧹 Clear", bootstyle="danger-outline", command=clear_videos).pack(side="left", padx=8)
- Playback Speed and Output Settings
Add a slider for speed and preset buttons:
speed_var = tb.DoubleVar(value=1.0)
speed_lbl = tb.Label(app, text="1.00x", foreground="#22c55e")
speed_lbl.pack()
def update_speed(val):
speed_lbl.config(text=f"{float(val):.2f}x")
tb.Scale(app, from_=0.5, to=3.0, variable=speed_var, orient="horizontal", command=update_speed).pack()
Preset buttons:
for v in [0.75, 1.0, 1.25, 1.5, 2.0]:
tb.Button(app, text=f"{v}x", bootstyle="info-outline", command=lambda x=v: speed_var.set(x)).pack(side="left")
- Output Format and Folder
Let users select the output format and folder:
output_format = tb.StringVar(value="mp4")
output_dir = tb.StringVar()
tb.Combobox(app, values=["mp4","mkv","avi","mov","webm"], textvariable=output_format, state="readonly").pack()
tb.Entry(app, textvariable=output_dir).pack()
tb.Button(app, text="Browse", bootstyle="secondary", command=lambda: output_dir.set(filedialog.askdirectory())).pack()
- Progress and Logging
Add a progress bar and a log panel:
progress_var = tb.IntVar()
tb.Progressbar(app, variable=progress_var, maximum=100).pack()
log_text = tk.Text(app, height=5)
log_text.pack(fill="both", expand=True)
log_text.config(state="disabled")
8. Core Video Processing
Use FFmpeg to adjust video speed:
def process_videos():
for video in video_list:
speed = speed_var.get()
fmt = output_format.get()
out_file = os.path.join(output_dir.get() or os.path.dirname(video), f"{os.path.splitext(os.path.basename(video))[0]}_{speed:.2f}x.{fmt}")
cmd = [
FFMPEG_PATH, "-y",
"-i", video,
"-filter:v", f"setpts=PTS/{speed}",
"-filter:a", f"atempo={speed}",
out_file
]
subprocess.run(cmd, creationflags=CREATE_NO_WINDOW)
- Live Preview
Preview the video speed with FFplay:
def play_preview():
video = listbox.get(listbox.curselection()[0])
speed = speed_var.get()
cmd = [FFPLAY_PATH, "-autoexit", "-vf", f"setpts=PTS/{speed}", "-af", f"atempo={speed}", video]
subprocess.Popen(cmd, creationflags=CREATE_NO_WINDOW)
- Controls
Add Start, Pause, Stop, and Preview buttons:
tb.Button(app, text="🚀 Start", bootstyle="success", command=lambda: threading.Thread(target=process_videos, daemon=True).start()).pack(side="left")
tb.Button(app, text="⏸ Pause", bootstyle="warning-outline", command=lambda: setattr(sys.modules[__name__], "pause_flag", not pause_flag)).pack(side="left")
tb.Button(app, text="🛑 Stop", bootstyle="danger-outline", command=lambda: setattr(sys.modules[__name__], "stop_flag", True)).pack(side="left")
tb.Button(app, text="▶ Play Preview", bootstyle="info", command=play_preview).pack(side="left")
- Drag & Drop Support
Enable users to drop videos directly into the app:
def drop(event):
files = app.tk.splitlist(event.data)
for f in files:
if os.path.isfile(f) and f not in video_list:
video_list.append(f)
ui_queue.put(("add", f))
app.drop_target_register(DND_FILES)
app.dnd_bind("<<Drop>>", drop)
- Start the App
Finally, run the UI loop:
app.after(100, process_ui)
app.mainloop()
✅ Result: You now have a fully functional QuickVideo desktop tool that can batch adjust video playback speed, preview changes live, and export multiple formats on Windows.

Top comments (0)