Open-source project
ffplayout/ffplayout avatar
ffplayout/ffplayout

ffplayout: 24/7 playout with a JSON playlist and a web frontend

Rust and ffmpeg based playout

596 stars142 forksRustGPL-3.0

At a glance

What is it?
ffplayout is a Rust and FFmpeg based playout system for continuous broadcasting, with a folder mode, a JSON playlist per day, HLS, RTMP and desktop outputs, and a Vue web frontend for editing. It is GPL-3.0 licensed, and several of its newer capabilities are still marked experimental in the documentation.
Who is it for?
ffplayout fits a small broadcast operation that needs a channel to play on air around the clock from a folder of clips and a daily schedule, and who wants to edit the running playlist from a browser instead of a text editor on the playout machine. It does not fit a team that needs a mature, documented production system today, since the 2.7 line is a beta and the multi output, shared encoding, MoQ playback and reconnection features are documented as experimental.
Can I use it commercially?
Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
Is it still maintained?
Yes. The repository last received commits 4 days ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What ffplayout is for and who runs it

ffplayout is a 24/7 broadcasting solution. It can play out a folder containing video clips, or play a JSON playlist for each day, and the current playlist stays editable while it runs.

The design intent is stated plainly: the application is mostly designed to run as a system service on Linux, and in general it should run on any platform supported by Rust and FFmpeg. That is a small operation, one channel, one machine, running unattended, with someone occasionally adjusting what plays next.

The features list reads like a broadcast engineering checklist, because that is what it is. It can replace a missing playlist or a missing clip with a single filler or multiple fillers from a folder, and if no filler exists it creates a dummy clip, so a broken playlist never puts black on air. It can trim the last clip to reach exactly 24 hours, loop fillers until the day is full, and set a custom day start, for example from 06:00 to 06:00 rather than midnight to midnight.

It also conforms content rather than trusting it. Audio and video are conformed to match the output stream: letterbox or pillarbox to fit the aspect ratio, change the frame rate, fit the target resolution, add silence if the audio is too short, and hold the last frame if the video is too short. That last rule is what keeps a 23 hour and 59 minute playlist from ending in a black frame.

The users are community television stations, house channels, radio style visual channels, and anyone running a continuous video feed for a website or a screen.

The JSON playlist and the dynamic day schedule

The playlist format is JSON, one document per day. It carries a channel name, a date, and a program array where each item has an in point, an out point, a duration and a source path, plus an optional ad flag.

The source can be a local file, and it can also be a remote URL, since the documentation lists a remote source mode and one of the example entries points at an https address for a well known open movie file. An image source is supported too, and it loops until the out duration is reached, which is how you put a still on air for a segment.

The time model is the part that surprises people. If you are in playlist mode and move backwards or forwards in time, that time shift is saved so the playlist stays in sync, but the documentation warns it may make the playlist too short, and that if you do not reset it, it resets automatically the next day.

For continuous multi day operation you configure a day_start value and set length to 24 hours. For shorter scheduled runs the documentation suggests starting ffplayout with a scheduler such as cron or systemd timers, which is the tidier approach if your channel is not truly 24/7.

The playlist can be imported from a text or m3u file through the CLI or the frontend, and it can be generated from a template, so building a week's schedule is a template exercise rather than a hand editing exercise.

Outputs, ingest and the built-in web frontend

There are three output modes: stream, desktop, and HLS. HLS is the default. For production delivery the documentation is direct about it: serve the generated HLS files through nginx, another web server, or a CDN, because the built-in HTTP route is intended for previewing. That is a sensible default and a sensible warning, since a playout server is not where you want your public web traffic.

RTMP live ingest is supported, so ffplayout can take a feed in and play it into the schedule.

The frontend is a Vue application. The package manifest names it frontend and describes it as the Web UI for ffplayout, and the build tooling is Vite with vue-tsc for type checking, ESLint with the Vue config, and Prettier for formatting. The runtime dependencies give a good sense of what the interface does: video.js for the player, pinia for state, vue-router for navigation, vue-i18n for translations, splitpanes for the resizable layout, a date picker for scheduling, and @moq/watch for the built-in MoQ playback.

The system can be started with the web based frontend or run in foreground mode without a frontend, which is the option you want when debugging a channel.

The web frontend also drives the dynamic parts: text overlays are controllable from it, and outputs are configured in Settings to Outputs, where HLS, Stream and MoQ outputs support experimental live configuration and activation changes while program format, desktop and recording changes still require a channel restart.

Filler logic, watched folders, notifications and external tasks

The failure handling is where a playout system earns its keep, and ffplayout has a lot of it.

Missing content is replaced. If the playlist is missing or a clip cannot be found, the system substitutes a single filler or multiple fillers from a folder, and if no filler exists it creates a dummy clip. When the playlist is not 24 hours long, it loops fillers until the time is full.

There is a watched folder mode, described in its own document, in which clips placed in a watched folder are played. There is also the inverse of that problem: the last clip can be trimmed so the total playback reaches a full 24 hours.

Operations are wired in as well. Log alerts can be sent by email and by HTTP push notifications, logging can go to channel log files, to mail queues, or as colour output to the console, and an external task can be run when a clip starts, which is how you trigger a companion action such as a scene change.

Playlist import validates every clip, and can additionally check that the audio track is not completely muted. That last check catches a class of failure that is otherwise invisible until a viewer complains.

On top of that sits a set of overlay and branding features: a logo overlay, and a text overlay controllable from the web frontend.

The experimental features you should treat carefully

A block of the features list is marked experimental, and the project says plainly that experimental features do not guarantee the same stability and may fail under unusual circumstances, and that code and configuration options may change.

What is in that group matters for planning. Multiple channels is experimental. WebVTT subtitles in HLS mode are experimental, with the caveat that builds with libavformat before v61.9.100 can use WebVTT subtitles but may not support custom HLS subtitle display names. Multiple simultaneous outputs per channel, with individual resolutions and a shared program frame rate, are experimental. Explicit encoding sharing between compatible outputs, including using an HLS rendition as the encoding source, is experimental.

There is a built-in MoQ playback in the frontend, where a private publication starts on demand with a three-minute grace period, and an optional public player publishes continuously and is disabled by default. Independent output reconnection is experimental too: automatic retries every 15 seconds for up to three minutes, followed by a manual retry option, with successful media delivery resetting the retry window.

The project's own closing note on the list is worth repeating in your own planning. Multi-output, shared encoding, MoQ playback and reconnection still need sustained testing with real streaming destinations and browser playback before production use. That is an unusually clear instruction from a project about its own edges, and it tells you which features to leave off on day one.

Where ffplayout is the wrong tool

The first limit is scale and shape. This is a single channel playout engine with an experimental multi channel mode, not a transmission management system. If you need to schedule across several channels, insert commercials, handle SCTE or QAM, or manage a network of transmitters, this is not that tool, and the experimental marker on multiple channels is a fair signal of where the boundary sits.

The second is the FFmpeg dependency. FFmpeg v7.0+ development libraries are required, and the maximum supported version follows the ffmpeg-next crate, which is currently FFmpeg 9.0. That is a build-time coupling to a fast moving native library, and the macOS and Windows releases do not include the FFmpeg shared libraries, so those platforms need a separate installation step.

The third is the resource floor and its consequence. At least 4 dedicated threads and 3GB RAM are recommended for 720p, and resource use depends on the video resolution. Everything is CPU based and a GPU is not required, which is friendly to a small station, but a 1080p channel on modest hardware is a different proposition.

The fourth is the HLS delivery path. The built-in HTTP route is for previewing, so a real deployment adds nginx or a CDN in front, which means the playout system is only one of at least two pieces you have to operate.

Compare the alternative of a general purpose media server such as an nginx or Caddy instance driven by a scheduler, or a dedicated playout appliance. The difference in approach is that ffplayout owns the schedule, the fillers and the conformance rules, so a channel can survive a broken playlist without an operator noticing. What it does not give you is the ecosystem, the plugin market or the support contract you get from a commercial playout product.

Licence, build layout and the cost of an upgrade

ffplayout is released under the GPL-3.0 licence, with the text in the LICENSE file at the repository root, and the badge in the project documentation names GPL v3. The strong copyleft terms mean that if you distribute a modified version you have to publish the corresponding source, which is a consideration for anyone building a proprietary product on top of it. Read the LICENSE file yourself and take your own advice on how it applies to your distribution.

The Rust code is a workspace with two members, crates/app and crates/engine, which is a sensible split between the service and the media pipeline:

toml
[workspace]
members = ["crates/app", "crates/engine"]
resolver = "2"

The workspace package metadata gives the version as 2.7.0-beta.4, the edition as 2024, and the licence field as GPL-3.0, with the author listed as Jonathan Baecker. The release profile strips symbols, uses thin LTO, sets opt-level 3, one codegen unit, and aborts on panic.

The lint configuration is strict in a way that signals how the project is maintained. Clippy correctness, style, complexity and perf are all denied, suspicious is a warning, and a set of specific lints are warned on, including redundant_else, explicit_iter_loop and flat_map_option. A codebase with that much lint policy is easier to trust over a long upgrade cycle.

The frontend is a separate npm project with its own package-lock.json, a Vite config, a TypeScript config and a src-level prettier config, and the repository also holds migrations/ for the database, debian/ for packaging, docker/ for containers, docs/ for the per feature documentation, and assets/ and tests_assets/ for media.

On cadence, the recent tags are v2.6.0 on 2026-10-02, v2.6.1-rc.1 on 2026-10-04 and v2.7.0-beta.4 on 2026-10-19. The last push was on 2026-10-19, the same day as the newest tag, so the tree is current, but a beta line means you should read the changelog between the stable and the beta before moving a live channel onto it.

Editorial conclusion

ffplayout fits a small broadcast operation that needs a channel to play on air around the clock from a folder of clips and a daily schedule, and who wants to edit the running playlist from a browser instead of a text editor on the playout machine. It does not fit a team that needs a mature, documented production system today, since the 2.7 line is a beta and the multi output, shared encoding, MoQ playback and reconnection features are documented as experimental. Before deploying it, read the install guide for your platform, serve the generated HLS through nginx or a CDN rather than through the built-in HTTP route, and test the clip validation path with your own media so you know what fails before the channel goes live.

Frequently asked questions

How do I install and start ffplayout?

Install a package from the latest release, start the ffplayout service as the installation guide describes, then open http://<server-address>:8787 and complete the first-time setup, which creates the global settings and the first global admin. HLS is the default output mode.

What does ffplayout need in terms of FFmpeg and hardware?

FFmpeg v7.0 or newer development libraries are required, with the maximum supported version following ffmpeg-next and currently FFmpeg 9.0. At least 4 dedicated threads and 3GB of RAM are recommended for 720p, and processing is CPU based with no GPU required.

What happens when a clip in the playlist is missing?

A missing playlist or clip is replaced with a single filler or multiple fillers from a folder, and if no filler exists a dummy clip is created. When the playlist is not 24 hours long, fillers are looped until the time is full, and the last clip can be trimmed to reach a full 24 hours.

Should I serve ffplayout HLS output directly to viewers?

No. The documentation states that for production delivery you should serve the generated HLS files through nginx, another web server, or a CDN, and that the built-in HTTP route is intended for previewing.

Which ffplayout features are still experimental?

Multiple channels, WebVTT subtitles in HLS mode, multiple simultaneous outputs per channel, explicit encoding sharing, built-in MoQ playback and independent output reconnection are all marked experimental, and the documentation says they still need sustained testing with real streaming destinations before production use.

What licence does ffplayout use?

ffplayout is released under the GPL-3.0 licence, with the full terms in the LICENSE file at the repository root and the same identifier in the Cargo workspace package metadata.

Official sources

  1. ffplayout/ffplayout on GitHub
  2. Issues
  3. License: GPL-3.0
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/ffplayout-ffplayout.svg)](https://hysenlabs.com/projects/ffplayout-ffplayout)

Was this useful?