streamd – HTTP on-demand VOD transcoding API

2026–present Status: Active Category: AI

Your video library,
streamed on demand.

streamd turns a folder of video files — anything ffmpeg can read, from mp4 and mkv to mov, webm and ts — into adaptive HLS. It transcodes only the segments someone is watching, the moment they ask for them, and cleans up when they stop.

Still from a recorded stream
streamd
Twelve hours in, and this is the last checkpoint.
/
GET audio subs

# Nothing is transcoded until someone presses play

The playlist lists every segment of the file from the start, so each one has an address before it exists. streamd makes a segment when it’s requested and throws it away once nobody needs it.

source vods/2026-03-14_marathon.mkvh264 · 2 audio · 1 srt ·
↓ seek → segment
hls /index.m3u8 segments listed · on disk
Not on disk Recently served Playing Ready Transcoding
01

# Request

The player asks for the segment under the playhead — at the start, or eleven hours in. The address is already in the playlist.

GET …//seg_.ts
02

# Transcode that segment

streamd starts ffmpeg at that segment’s timestamp and encodes just that range, then keeps pace with playback. Seams line up to 0.0 ms.

ffmpeg -ss -t -i marathon.mkv …
03

# Stream, then clean up

The segment goes out as ordinary HLS. When the last viewer leaves, the working files are removed after the idle timeout.

viewers 0 → idle cleanup

# What it does

# On-demand transcoding

Starts instantly and seeks anywhere, even 12 hours into a VOD. Nothing is prepared ahead of time; any format ffmpeg reads is playable as soon as it lands in the folder.

0 bytes pre-transcoded

# Quality profiles

Define a ladder — 1080p, 720p, 480p or your own. The master playlist lets the player switch as bandwidth changes.

master.m3u8

# Multi-audio

Each audio track is its own switchable rendition, delivered as stereo AAC. Surround is downmixed; stereo AAC at or below the configured bitrate is copied untouched.

5.1 → aac 2.0

# Subtitles

SRT and ASS tracks are converted to WebVTT and offered to the browser’s own captions.

srt, ass → vtt

# Sample-accurate seams

Audio/video gap at segment boundaries measures 0.0 ms. No clicks at the joins, no drift after hours.

0.0 ms

# Watermarking

Text, a PNG, or an animated transparent WebM, scaled per quality so it sits the same at every rung.

text · png · webm

# Access control

Asks your existing login and permission backend. If it can’t be reached, the request is denied.

fails closed

# Chat replay

Recorded stream chat is served alongside the VOD.

vod + chat

# Operations

One YAML file or env vars. Built-in player page, idle cleanup, a concurrent-transcode cap and a debug status endpoint.

/debug/status

# One command, one file

Point streamd at a folder and start it. The built-in player page is served on the same port, so you can check a file before wiring up your own front end.

terminal
$ streamd serve --config config.yaml
library   /srv/vods
profiles  1080p 720p 480p
player    http://localhost:8080/
Every key in config.yaml can also be set through environment variables — handy in containers. Open the player URL, pick a file, press play.
config.yaml · example
listen: ":8080"
library: /srv/vods

profiles:
  - { name: 1080p, height: 1080, bitrate: 6M }
  - { name: 720p, height: 720, bitrate: 3M }
  - { name: 480p, height: 480, bitrate: 1.2M }

audio:
  bitrate: 160k # stereo aac at or below → copied

watermark:
  image: /etc/streamd/logo.png

auth:
  url: https://auth.example.com/check

limits:
  max_transcodes: 4
  idle_cleanup: 5m

# Runs next to your files

Static binaries for Linux and Windows, or a Docker image. amd64 today; arm64 builds are planned. No database, no job queue, no transcoding farm.

linux/amd64 image

# Docker

Mount your library read-only and the config file. Everything else can come from environment variables.

$ docker run -p 8080:8080 \
  -v /srv/vods:/vods:ro \
  -v ./config.yaml:/config.yaml \
  streamd serve --config /config.yaml
linux-amd64 binary

# Linux

One static amd64 binary, no runtime to install. Drop it on the box that holds the videos and run it under your service manager.

$ chmod +x streamd
$ ./streamd serve --config config.yaml
windows-amd64 .exe

# Windows

The same static binary, built for Windows on amd64. Useful when the archive lives on the machine you stream from.

> .\streamd.exe serve --config config.yaml