Skip to content

0xVacent/mpegado

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

mpegado

A web-based ffmpeg wrapper. Select a file once, stack edits (convert, trim) across tabs, and apply them all in a single ffmpeg pass while you watch live progress.

Note

This project was vibecoded. Nearly all of the code, architecture, and docs were produced iteratively through AI pair-programming with Claude Code (Anthropic), driven by natural-language prompts and verified by testing against real ffmpeg output. It's a hobby project — read the code and review it yourself before relying on it for anything serious.

  • Backend — Java 21 / Spring Boot 3.5 REST API that spawns ffmpeg as a subprocess and tracks progress asynchronously. Jobs are persisted to SQLite and old jobs/files are purged by a scheduled cleanup task.
  • Frontend — Angular single-page app: select once, edit, process, download.

Features

  • Select once, edit everywhere — pick a file at the top; the Convert and Trim tabs configure edits that are stacked into one job. Each tab has an Apply toggle, and the Process button shows a summary of what will run.
  • One-pass processing — trim, resize, fps, compression, codec/format change and audio selection all run as a single ffmpeg command. Trim-only uses fast stream copy; when you also convert, the trim becomes frame-accurate.
  • Encode controls — target resolution (down to 360p), frame rate, video/audio codec, and a compression slider (Lossless → Low → Medium → High → Ultra, mapped to CRF for software encoders and QP for GPU encoders).
  • Target file size — set a max size (MB) and the server computes a constrained video bitrate (90% of the cap, after reserving audio) so the output lands under the limit. Overrides the compression slider.
  • Audio tracks — keep all, select specific tracks, or merge (mix) tracks into one. Track list shows codec, channels, and language.
  • Platform presets — one-click, size-compliant:
    • Discord — HEVC + Opus in MKV, 720p, ≤ 15 MB.
    • Twitter/X — H.264 + AAC in MP4, 1080p, ≤ 500 MB.
  • Original media info — selecting a file uploads it and runs a fast ffprobe (no transcode), showing container, codec, resolution, fps, pixel format, bitrate, audio channels/sample-rate, and size beside the preview.
  • Preview any codec — if the browser can't decode the source (e.g. HEVC/MKV), the server generates a downscaled H.264 preview proxy (range-streamed for seeking). You scrub the proxy; edits run on the original file. Proxies are built with the GPU H.264 encoder (h264_amf/h264_nvenc/h264_qsv) when one is available, falling back to libx264 if the hardware encode fails.
  • Switch preview audio track — for multi-track files, a Preview audio selector swaps which track you hear. Browsers can't switch tracks in <video>, so the server builds a small per-track proxy on demand (cached, position preserved across switches); the natively-playable default track stays instant.
  • Async jobs with live progress (frontend polls the job status).
  • Hardware-accelerated encoding — detected per-machine at startup via a trial encode, so the UI only offers GPU encoders that actually work. On an AMD GPU (AMF) that means H.264 (h264_amf), HEVC (hevc_amf), and AV1 (av1_amf); NVENC/QSV appear automatically on NVIDIA/Intel hardware.
  • Persistence — jobs survive restarts (SQLite). Jobs left running when the server stops are marked FAILED on the next boot.
  • Cleanup — a scheduled task deletes jobs and their files once they pass a configurable TTL.

Prerequisites

  • ffmpeg and ffprobe on the PATH (or set mpegado.ffmpeg-path / mpegado.ffprobe-path).
  • JDK 21+ (the backend uses the bundled Maven wrapper, so no global Maven needed).
  • Node.js 20+ for the Angular frontend.

Running

Backend (port 8080)

cd backend
./mvnw spring-boot:run        # Windows: .\mvnw.cmd spring-boot:run

Frontend (port 4200)

cd frontend
npm start

Open http://localhost:4200. The dev server proxies API calls, and CORS is open to http://localhost:4200 by default.

API

Method Path Description
GET /api/capabilities available formats + video/audio codecs (with a hardware flag) detected on this machine
POST /api/sources upload an original; server ffprobes it. Returns source id + mediaInfo
GET /api/sources/{id} source status (NONE/PREPARING/READY/FAILED), duration, mediaInfo
POST /api/sources/{id}/proxy?track=N lazily build the H.264 preview proxy for audio track N (cached)
GET /api/sources/{id}/preview?track=N range-streamed H.264 preview proxy for audio track N
POST /api/jobs/process JSON { sourceId, trim?: {startSeconds,endSeconds}, convert?: {targetFormat,videoCodec,audioCodec,scaleHeight,fps,compression}, audio?: {mode,tracks} } — applies all edits in one job
GET /api/jobs list jobs (newest first)
GET /api/jobs/{id} job status + progress (0–100)
GET /api/jobs/{id}/download download the output once COMPLETED

Codecs and formats in a request are validated against /api/capabilities, so unknown values are rejected (400) before ffmpeg ever runs.

Configuration

Override in backend/src/main/resources/application.properties or via env vars:

  • mpegado.ffmpeg-path / mpegado.ffprobe-path — binary locations
  • mpegado.work-dir — where uploads/outputs are stored (default: temp dir)
  • mpegado.worker-threads — concurrent conversions (default: 2)
  • mpegado.cors.allowed-origins — comma-separated allowed origins
  • mpegado.db-path — SQLite database file (default: mpegado.db)
  • mpegado.cleanup.ttl-hours — age after which jobs/files are deleted (default: 24)
  • mpegado.cleanup.interval-ms — how often cleanup runs (default: 3600000)
  • spring.servlet.multipart.max-file-size — upload limit (default: 2GB)

Project structure

mpegado/
├── backend/                       # Spring Boot REST API
│   ├── src/main/java/com/mpegado/
│   │   ├── model/                 # JPA entities + enums (ConversionJob, Source, Compression…)
│   │   ├── repository/            # Spring Data JPA repositories
│   │   ├── service/               # ffmpeg orchestration, codec probing, cleanup
│   │   │   ├── ConversionService.java      # builds + runs the one-pass edit job
│   │   │   ├── FfmpegCommandBuilder.java    # assembles the ffmpeg command line
│   │   │   ├── SourceService.java           # uploads, ffprobe, preview proxies
│   │   │   └── CodecService.java            # detects working (incl. GPU) encoders
│   │   └── web/                   # REST controllers + DTOs
│   └── src/main/resources/application.properties
└── frontend/                      # Angular single-page app
    └── src/app/
        ├── editor-store.ts        # shared edit state (the "select once" model)
        ├── file-selector.*        # upload + preview + media info
        ├── convert-form.*         # format/codec/resolution/fps/size/compression
        ├── trim-form.*            # in/out points
        └── audio-form.*           # keep / select / merge audio tracks

License

MIT © 0xVacent

About

Web-based ffmpeg wrapper (Angular + Spring Boot): select once, stack edits and run them in a single ffmpeg pass with GPU-accelerated encoding. Vibecoded with Claude Code.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors