DEV Community

Mate Technologies
Mate Technologies

Posted on

How to Build a Fast Video Splitter with Python and Tkinter

In this tutorial, we’ll create VID Splitter, a lightweight desktop app that splits videos into short clips. It supports MP4, AVI, and MOV files, shows a live preview of total duration and clips, and includes a progress bar and live log.

We’ll use Python, Tkinter, ttkbootstrap, and OpenCV. This guide is beginner-friendly—no prior GUI experience needed.

Step 1: Set Up the Project

First, install the required Python packages:

pip install opencv-python ttkbootstrap

opencv-python: For reading/writing video files.

ttkbootstrap: For a modern, styled Tkinter interface.

Create a Python file, e.g., vid_splitter.py.

Step 2: Import Libraries

At the top of your file, import the necessary modules:

import sys
from pathlib import Path
import tkinter as tk
from tkinter import filedialog, messagebox
import ttkbootstrap as tb
from ttkbootstrap.widgets.scrolled import ScrolledText
import threading
import cv2
import os
import math
Enter fullscreen mode Exit fullscreen mode

Explanation:

tkinter and ttkbootstrap are used to create the GUI.

threading allows the video splitting to run in the background.

cv2 (OpenCV) handles video processing.

math and os help with file and clip calculations.

Step 3: Create the Main App Window

Initialize the Tkinter window and set its title, size, and style:

app = tk.Tk()
style_obj = tb.Style(theme="superhero")  # Modern UI theme

app.title("VID Splitter v1.0.0")
app.geometry("950x600")
Enter fullscreen mode Exit fullscreen mode

Explanation:

tb.Style from ttkbootstrap lets you use sleek themes.

geometry sets the window size.

Step 4: Input & Output Selection

We need users to select a video file and an output folder.

# Input video
video_path = tk.StringVar()
tb.Label(app, text="Video Input").pack()
tb.Entry(app, textvariable=video_path).pack(fill="x")
tb.Button(app, text="Browse Video", bootstyle="info",
          command=lambda: video_path.set(filedialog.askopenfilename(
              filetypes=[("Video Files", "*.mp4 *.avi *.mov")]
          ))).pack()

# Output folder
output_dir = tk.StringVar()
tb.Label(app, text="Output Folder").pack()
tb.Entry(app, textvariable=output_dir).pack(fill="x")
tb.Button(app, text="Browse Folder", bootstyle="info",
          command=lambda: output_dir.set(filedialog.askdirectory())).pack()
Enter fullscreen mode Exit fullscreen mode

Explanation:

StringVar stores dynamic text values for GUI entries.

filedialog opens file/folder selection dialogs.

Step 5: Add Clip Settings

Let users set clip length and filename prefix:

clip_length = tk.IntVar(value=5)
file_prefix = tk.StringVar(value="clip")

tb.Label(app, text="Clip Length (seconds)").pack()
tb.Entry(app, textvariable=clip_length, width=5).pack()

tb.Label(app, text="Filename Prefix").pack()
tb.Entry(app, textvariable=file_prefix, width=15).pack()
Enter fullscreen mode Exit fullscreen mode

Explanation:

IntVar stores numeric values for clip length.

Users can define how many seconds each clip should be.

Step 6: Live Preview of Clips

Show total video duration and how many clips will be generated:

preview_label = tb.Label(app, text="Total: --s | Clips: --")
preview_label.pack()

def update_preview():
    path = video_path.get()
    if not path or clip_length.get() <= 0:
        preview_label.config(text="Total: --s | Clips: --")
        return
    cap = cv2.VideoCapture(path)
    if not cap.isOpened():
        preview_label.config(text="Total: --s | Clips: --")
        return
    total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
    fps = cap.get(cv2.CAP_PROP_FPS)
    duration = total_frames / fps
    clips = math.ceil(duration / clip_length.get())
    preview_label.config(text=f"Total: {duration:.2f}s | Clips: {clips}")
    cap.release()

video_path.trace_add("write", lambda *args: update_preview())
clip_length.trace_add("write", lambda *args: update_preview())
Enter fullscreen mode Exit fullscreen mode

Explanation:

OpenCV reads the video and calculates total duration.

trace_add automatically updates the preview when the user changes inputs.

Step 7: Add a Live Log & Progress Bar

# Live log
log_card = tb.Labelframe(app, text="Live Output")
log_card.pack(fill="both", expand=True)
log = ScrolledText(log_card)
log.pack(fill="both", expand=True)
log.text.config(state="disabled", height=5)

# Progress bar
progress = tb.Progressbar(app)
progress.pack(fill="x", pady=5)
Enter fullscreen mode Exit fullscreen mode

Explanation:

Users can see each clip as it’s saved.

Progress bar gives real-time feedback.

Step 8: Video Splitting Logic

Here’s the core function:

stop_event = threading.Event()

def split_video():
    if not video_path.get() or not output_dir.get():
        messagebox.showerror("Missing Input", "Please select video and output folder.")
        return

    cap = cv2.VideoCapture(video_path.get())
    fps = cap.get(cv2.CAP_PROP_FPS)
    total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
    frames_per_clip = int(fps * clip_length.get())
    clip_count = 0
    frame_idx = 0

    while frame_idx < total_frames:
        remaining_frames = total_frames - frame_idx
        current_clip_frames = min(frames_per_clip, remaining_frames)
        frames = []

        for _ in range(current_clip_frames):
            ret, frame = cap.read()
            if not ret:
                break
            frames.append(frame)
            frame_idx += 1
            progress.configure(value=(frame_idx / total_frames) * 100)

        if not frames:
            break

        clip_name = f"{file_prefix.get()}_{clip_count:03d}.mp4"
        clip_path = os.path.join(output_dir.get(), clip_name)
        h, w, _ = frames[0].shape
        out = cv2.VideoWriter(clip_path, cv2.VideoWriter_fourcc(*"mp4v"), fps, (w, h))
        for f in frames:
            out.write(f)
        out.release()
        clip_count += 1

    cap.release()
    messagebox.showinfo("Done", f"Total clips: {clip_count}")
Enter fullscreen mode Exit fullscreen mode

Explanation:

Splits the video into chunks based on clip_length.

Saves each clip using OpenCV’s VideoWriter.

Updates the progress bar while processing.

Step 9: Add Buttons to Start/Stop

tb.Button(app, text="Start Splitting", bootstyle="success",
          command=lambda: threading.Thread(target=split_video, daemon=True).start()).pack()
tb.Button(app, text="Stop", bootstyle="danger",
          command=lambda: stop_event.set()).pack()
Enter fullscreen mode Exit fullscreen mode

Explanation:

Video splitting runs in a background thread so the UI stays responsive.

Stop button lets the user interrupt processing safely.

Step 10: Run the App

Finally, start the Tkinter main loop:

app.mainloop()
Enter fullscreen mode Exit fullscreen mode

Open vid_splitter.py and try splitting a video! 🎬

✅ What You Learned

Creating a modern GUI with Tkinter + ttkbootstrap

Using OpenCV for video processing

Managing threads to keep the UI responsive

Adding live preview, logs, and progress bars

Top comments (0)