๐ŸŽต Local web app ยท FastAPI + FFmpeg

Choir Video Editor

Drag-and-drop video clip stitching with seamless crossfade transitions and audio sync โ€” purpose-built for choir and orchestra video productions.

๐ŸŽฏ What it does

Drop your video clips, reorder them on a timeline, pick a transition, and render a seamless final video โ€” all from your browser.

๐ŸŽฌ

Drag & Drop

Drop MP4, MOV, AVI, MKV, or WebM clips onto the interface. Multiple files at once.

๐Ÿ”„

11 Crossfade Transitions

Fade, dissolve, circle open/close, slide, pixelize, radial, and more โ€” with adjustable duration (0.3โ€“3s).

๐ŸŽต

Audio Sync

Automatic audio crossfade between clips with optional level normalization.

๐Ÿ“

Output Resolution

Export at original, 1080p, 720p, or 480p with smart letterboxing.

๐Ÿ“Š

Live Progress

Real-time progress bar via SSE while FFmpeg renders the final video.

โฌ‡๏ธ

Preview & Download

Play the assembled video in-browser or download as MP4 (H.264 + AAC).

โ–ถ๏ธ Run it locally

Requires Python 3.12+ and FFmpeg. Start in under 30 seconds.

1

Clone or download the project

The source is at C:\Users\HomePC\choir-video-editor\ on the development machine.

2

Install dependencies

pip install fastapi uvicorn jinja2

FFmpeg must be installed and available on your PATH.

3

Start the server

cd choir-video-editor
python -m uvicorn main:app --host 127.0.0.1 --port 5000 --log-level warning
4

Open the editor

Navigate to http://localhost:5000 in your browser. Drag in your clips and render.

โœจ Available Transitions

All powered by FFmpeg's xfade filter.

fadefadeblackfadewhite dissolvedistancefadegrays hslmixradialpixelize smoothleftsmoothrightsmoothup smoothdowncircleopencircleclose vertopenvertclosehorzopenhorzclose

๐Ÿ”ง API Endpoints

The FastAPI backend exposes a clean REST API.

EndpointMethodDescription
/GETMain UI
/uploadPOSTUpload a video clip
/clipsGETList uploaded clips
/clips/{filename}DELETERemove a clip
/renderPOSTStart render job
/progress/{job_id}GETSSE progress stream
/transitionsGETList available transitions
/output/{filename}GETDownload rendered video

๐Ÿง  How it works

The FFmpeg filter graph chains crossfades across N clips.

# For N clips with transition duration T: # Total duration = sum(clip_durations) - (N-1) ร— T # xfade offset for transition i = sum(durs[0:i]) - i ร— T # Video chain with chained xfade filters: [0:v]setpts=PTS-STARTPTS[v0_in]; [1:v]setpts=PTS-STARTPTS[v1_in]; [v0_in][v1_in]xfade=transition=fade:duration=1:offset=4.0[v1_xf] # Audio chain with chained acrossfade: [0:a]asetpts=PTS-STARTPTS[a0_in]; [1:a]asetpts=PTS-STARTPTS[a1_in]; [a0_in][a1_in]acrossfade=d=1.0[a1_xf]