Skip to content

About

Simple web API for extracting images/audio from video and converting audio/video/image files with ffmpeg.

Resources

Stars

78 stars

Watchers

0 watching

Forks

 
 

Repository files navigation

FFMPEG API

REST API for converting audio, video and image files with FFmpeg. One container, one curl command, no FFmpeg installation on your machine.

docker run -d --name ffmpeg-api -p 3000:3000 kazhar/ffmpeg-api
curl -F "file=@input.wav" 127.0.0.1:3000/convert/audio/to/mp3 > output.mp3
  • Convert audio to MP3 and WAV, video to MP4, images to JPG.
  • Extract the audio track or frames (PNG, optionally zipped) from a video.
  • Probe any media file and get its metadata as JSON.
  • Full OpenAPI 3.1 description with an interactive Swagger UI at /docs and the machine readable document at /openapi.json. Generate clients in any language from it.
  • Built on Red Hat UBI, Python and FastAPI. FFmpeg is the latest release, compiled in the image build.
  • Self-contained: the running container makes no external calls, and the API docs work offline.
  • Runs as a non-root user, works on Kubernetes and OpenShift.

Note: There is no authentication. Run it in a trusted network or behind a reverse proxy.

Quick start

docker run -d --name ffmpeg-api -p 3000:3000 kazhar/ffmpeg-api

Open http://127.0.0.1:3000/docs to try the API in the browser.

API

The OpenAPI document at /openapi.json (and Swagger UI at /docs) is the reference for all request and response details. Summary:

Method Path Description
GET / Landing page with links to the docs.
GET /docs Interactive API documentation (Swagger UI).
GET /openapi.json OpenAPI document.
GET /endpoints Service endpoints as JSON.
GET /health Health check, returns {"status": "ok"}.
POST /convert/audio/to/mp3 Convert audio to MP3. Returns the MP3 file.
POST /convert/audio/to/wav Convert audio to WAV (16-bit PCM). Returns the WAV file.
POST /convert/video/to/mp4 Convert video to a small web friendly MP4 (H.264, AAC). Returns the MP4 file.
POST /convert/image/to/jpg Convert an image to JPG. Returns the JPG file.
POST /video/extract/audio Extract the audio track of a video as WAV. Mono by default. mono=no keeps all channels.
POST /video/extract/images Extract frames of a video as PNG, 1 per second by default. Returns JSON with download links. fps=<number> sets the frame rate. compress=zip|gzip returns a ZIP or tar.gz archive instead.
GET /video/extract/download/{filename} Download an extracted image or archive. The file is deleted from the server after download. delete=no keeps it.
POST /probe Probe a media file, returns JSON metadata (same as ffprobe -of json -show_streams -show_format).

All POST endpoints take a multipart/form-data body with exactly one file in the form field file. The input can be anything FFmpeg supports, see the FFmpeg documentation.

Errors are JSON: {"error": "message"} with status 400 (bad request), 404 (not found), 413 (file too large), 422 (invalid query parameter) or 500 (FFmpeg failed).

Examples

Convert

curl -F "file=@input.wav"  127.0.0.1:3000/convert/audio/to/mp3 > output.mp3
curl -F "file=@input.m4a"  127.0.0.1:3000/convert/audio/to/wav > output.wav
curl -F "file=@input.mov"  127.0.0.1:3000/convert/video/to/mp4 > output.mp4
curl -F "file=@input.mp4"  127.0.0.1:3000/convert/video/to/mp4 > output.mp4
curl -F "file=@input.tiff" 127.0.0.1:3000/convert/image/to/jpg > output.jpg
curl -F "file=@input.png"  127.0.0.1:3000/convert/image/to/jpg > output.jpg

The MP4 conversion produces H.264 (high profile), 15 fps, 640 pixels high, about 500 kbit/s video and AAC 128 kbit/s audio.

Extract images

# JSON with a download URL for each image (1 image per second)
curl -F "file=@input.mov" 127.0.0.1:3000/video/extract/images

# download an image (deleted from the server afterwards)
curl 127.0.0.1:3000/video/extract/download/ba0f565c-0001.png > image.png

# download an image and keep it on the server
curl "127.0.0.1:3000/video/extract/download/ba0f565c-0001.png?delete=no" > image.png

# all images as ZIP or tar.gz
curl -F "file=@input.mov" "127.0.0.1:3000/video/extract/images?compress=zip"  > images.zip
curl -F "file=@input.mov" "127.0.0.1:3000/video/extract/images?compress=gzip" > images.tar.gz

# one image every 2 seconds (fps=0.5), or four images per second (fps=4)
curl -F "file=@input.mov" "127.0.0.1:3000/video/extract/images?fps=0.5"

Example response, see also extracted_images.json:

{
  "totalfiles": 2,
  "description": "Extracted image files and URLs to download them. ...",
  "files": [
    { "name": "ba0f565c-0001.png", "url": "http://127.0.0.1:3000/video/extract/download/ba0f565c-0001.png" },
    { "name": "ba0f565c-0002.png", "url": "http://127.0.0.1:3000/video/extract/download/ba0f565c-0002.png" }
  ]
}

Extract audio

# mono WAV
curl -F "file=@input.mov" 127.0.0.1:3000/video/extract/audio > audio.wav
# WAV with all channels of the video
curl -F "file=@input.mov" "127.0.0.1:3000/video/extract/audio?mono=no" > audio.wav

Probe

curl -F "file=@input.mov" 127.0.0.1:3000/probe

Returns the same JSON as ffprobe -of json -show_streams -show_format input.mov. See probe_metadata.json.

Configuration

Set environment variables with docker run -e NAME=value.

Variable Default Description
LOG_LEVEL info Log level: debug, info, warning, error.
FILE_SIZE_LIMIT_BYTES 536870912 (512 MB) Maximum size of an uploaded file. Larger uploads get HTTP 413.
KEEP_ALL_FILES false Set to true to keep uploaded and generated files in the container's /tmp (for debugging).
EXTERNAL_PORT 3000 Port used in the download URLs returned by the extract images endpoint. Set it when the published port differs from 3000.
docker run -d -p 3001:3000 -e EXTERNAL_PORT=3001 -e LOG_LEVEL=debug kazhar/ffmpeg-api

Uploads and conversions run for as long as FFmpeg needs; connections stay open for up to an hour.

Build the image

git clone https://github.com/samisalkosuo/ffmpeg-api.git
cd ffmpeg-api
docker build -t ffmpeg-api .

The build compiles FFmpeg (with libx264 and libmp3lame) on UBI, so the first build takes several minutes. Use --build-arg BUILD_JOBS=8 to compile faster. Everything is downloaded at build time; the running container needs no network access.

Updating

  • New UBI release: change UBI_IMAGE, UBI_MINIMAL_IMAGE (and PYTHON_VERSION if needed) at the top of the Dockerfile.
  • New FFmpeg release: rebuild. FFMPEG_VERSION=latest (default) looks up the newest release on ffmpeg.org when building. Pin one with --build-arg FFMPEG_VERSION=9.0.2.

Development

python -m venv .venv && . .venv/bin/activate
pip install -r requirements-dev.txt
ruff check . && pytest        # media tests need ffmpeg and ffprobe on PATH

# or run the whole test suite in a container
docker build --target test -t ffmpeg-api-test . && docker run --rm ffmpeg-api-test

Tests generate their input media with FFmpeg, no media files are stored in the repository.

Kubernetes and OpenShift

The container runs as a non-root user and works with arbitrary user IDs. A minimal deployment:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: ffmpeg-api
spec:
  replicas: 1
  selector:
    matchLabels: { app: ffmpeg-api }
  template:
    metadata:
      labels: { app: ffmpeg-api }
    spec:
      containers:
        - name: ffmpeg-api
          image: kazhar/ffmpeg-api
          ports:
            - containerPort: 3000
          readinessProbe:
            httpGet: { path: /health, port: 3000 }
          resources:
            limits: { cpu: "2", memory: 1Gi }

Migrating from version 1 (Node.js)

The API paths, parameters and response formats are unchanged. Differences:

  • MP4 audio is encoded with FFmpeg's native AAC encoder (libfdk_aac is not freely redistributable).
  • Errors are JSON {"error": "..."}.
  • Files above the size limit return 413 (was 500).
  • New: OpenAPI document, Swagger UI, /health.

The Node.js version is kept on a separate legacy branch in this repository. See CHANGES.md.

Background

Originally developed by Paul Visco (docker-ffmpeg-service). Version 2 is a rewrite using Python, FastAPI, Red Hat UBI and a source-built FFmpeg.

Licensed under the MIT License. The image contains FFmpeg built with GPL components (libx264), which are licensed under their own terms.

About

Simple web API for extracting images/audio from video and converting audio/video/image files with ffmpeg.

Resources

Stars

78 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages