A dead-simple tool to trim a piece out of a video without opening a full editor.
Double-click Video Clipper.bat. If it reports the venv is missing, run
setup-venv.bat once first (it creates .venv and installs PySide6).
Don't run
python clipper.pydirectly — barepythonmay resolve to a different Python on your machine that doesn't have PySide6. The.batuses this project's own.venv, so it doesn't depend on whatever Python is on your PATH.
- Drag & drop a video file onto the window, or
- Click Open Video...
The position readout shows both time and frame: 00:01.533 / 00:30.000 · Frame 47 / 900
(frame numbers are 1-based — the first frame is Frame 1, the last is Frame N / N).
- Play / scrub the timeline (drag the bar) to roughly find your start.
- Press I (or Set In) to drop the In point, O (or Set Out) for the Out point.
- Fine-tune frame-by-frame:
,/.step the current frame (playhead) back / forward — this never moves your In/Out points.- To adjust a cut point, toggle Edit In or Edit Out (only one at a time;
click it again to deselect). While one is selected, Shift +
</>— or Shift-clicking the Frame ◀ / ▶ buttons — moves that point one frame. With neither selected, Shift-stepping just moves the playhead too. - The left / right thumbnails show the frames just before and after the
current playhead — they update live as you jog with
,/., so you always see the exact frame-strip around where you are. - Or click the In / Out readout to type an exact timestamp
(
1:23.500,0:01:23.500, or plain seconds83.5). Invalid formats or times outside the video are rejected.
- Export Clip... — choose where to save. Default name is
<original>_clip.<ext>.
The timeline shows time tick marks at sensible round increments that adapt to the clip length (e.g. every 5s on a short clip, every 15min on a long one).
- Click / drag the track to scrub the playhead.
- Drag the green In / orange Out handles to move those points — hover over a handle and it enlarges with a resize cursor. Dragging one also moves the playhead to it so the preview shows that exact frame.
- Shift + drag across the track to select a span — the region you drag over becomes the new In→Out.
- Shift + drag starting on the playhead anchors the selection at the head: the head's starting position and where you release become In and Out (earlier = In, later = Out).
−/+buttons (bottom right, at the end of the scrollbar) zoom out / in, centred on the playhead. Fully zoomed out shows the whole clip; fully zoomed in shows 1 second.- At maximum zoom, per-frame tick marks appear above the timeline (numbered, derived from the source's frame rate) alongside the time ticks below it.
- Shift + scroll wheel over the timeline zooms, centred on the mouse cursor.
- Scroll wheel (no shift) pans the zoomed view left/right.
- A scrollbar appears under the timeline whenever you're zoomed in, and stays in sync with panning and zooming (drag it to scroll too).
- Moving the playhead near either edge pans the view to follow it, keeping it about one tick from the edge — the head keeps its position in time while the timeline scrolls around it, until you reach the clip's actual start or end.
| Key | Action |
|---|---|
| Space | Play / pause |
| I / O | Set In / Out at the playhead |
| , / . | Step the current frame (playhead) — never moves In/Out |
| Shift + < / > | Move the selected In/Out one frame (or the playhead if neither is selected) |
| ← / → | Scrub the playhead ±1 second |
Save Frame (PNG)... exports the current frame as a full-resolution PNG (default name
<original>_frame_<n>.png, where n is the 1-based frame number shown on screen). It
uses the same frame-exact seek as the clip export, so you get precisely the frame you're
parked on. The PNG also carries metadata for that exact frame (see below).
Export Audio (MP3)... exports just the audio of the In→Out range as an MP3
(<original>_clip.mp3), with timecode metadata (source file + In/Out times). Audio has
no frames, so no frame numbers are written. If the source has no audio track, it tells you
instead of writing an empty file.
The Write metadata checkbox (on by default) controls all of this. Uncheck it and exports get no extra metadata at all — no source filename, In/Out, frame info, or comment — and inherited source tags are stripped too, giving clean files.
When you open (or drag in) a video clip made by this tool, a line appears under the
filename showing where it came from, e.g.
↳ Clipped from holiday.mp4 · In 00:10.000 (frame 301) · Out 00:25.000 (frame 751) · of 900 frames.
Plain videos show nothing.
What each export records:
Video clip — source file, In/Out timecodes, and the frame range of the original:
comment,original_filename,clip_in,clip_outclip_in_frame,clip_out_frame,clip_frame_range(e.g.301-751),source_total_frames
MP3 — timecodes only: comment, original_filename, clip_in, clip_out.
Still PNG — the one exact frame it is: source_frame, frame_timecode,
source_total_frames, original_filename, comment.
Read them back:
# video / mp3 (ffprobe)
ffprobe -v error -show_entries format_tags -of default=noprint_wrappers=1 yourclip.mp4
# still PNG (PNG text chunks — ffprobe doesn't read these; use ImageMagick)
magick identify -format "%[source_frame] / %[source_total_frames] @ %[frame_timecode]\n" frame.png
- Frame-accurate (default, checkbox on): re-encodes (x264/AAC) and cuts on the exact
frames you set — verified to the frame at both 30 and 29.97 fps. Slower, tiny quality
cost, always outputs
.mp4. - Instant lossless (uncheck the box): stream-copy — instant, no quality loss, keeps the original format. Not frame-accurate: stream-copy can only start on a keyframe, so ffmpeg snaps the In point back to the nearest keyframe (often 1–2s earlier). This is a fundamental codec limitation — a non-keyframe can't start a clip because it's stored as a difference from earlier frames.
The In and Out frames you set are both included in the clip; the Length readout shows the frame count.
The prev/current/next preview frames are always frame-accurate (rendered directly by ffmpeg) regardless of export mode.
ffmpegandffprobeon PATH (both ship with a standard ffmpeg build)- Python 3.11 (via the Windows
pylauncher) - PySide6 in the project's
.venv(runsetup-venv.batto create it)
The .venv is deliberately not committed. After cloning:
- Run
setup-venv.bat— creates.venvwith Python 3.11 and installs PySide6. - Run
Video Clipper.bat.
Video Clipper.bat launches via .venv\Scripts\pythonw.exe (an absolute path inside the
project), so it doesn't depend on whatever Python is on your PATH. If the venv is missing
it says so and points you at setup-venv.bat rather than failing silently.
Note: a venv hardcodes its own location, so if you move this folder, re-run
setup-venv.bat to rebuild it.
| File | Purpose |
|---|---|
clipper.py |
The whole application |
Video Clipper.bat |
Launcher (no console window) |
setup-venv.bat |
Creates/rebuilds .venv with PySide6 |
clipper.ico |
App / taskbar icon |