Open-source web video production is the practice of building, encoding, packaging, and delivering time-based media with tools whose source code you can inspect, modify, and self-host. It sits next to adjacent concepts like accessible HTML5 players, live streaming pipelines, per-title encoding, and EU web accessibility compliance. For a European indie creator or a small media team, this matters because it shifts control back to the publisher: no per-seat licenses, no black-box transcoding, and no player that phones home without your knowledge. In this article I will walk through the tools I actually use on webmultimediale.org, with reproducible setup notes and honest tradeoffs.
What Counts as a Web Video Production Stack
Before listing tools, we need a working definition. A production stack for web video usually has four layers:
- Capture and editing — recording, cutting, color, audio cleanup.
- Encoding and packaging — mezzanine to H.264/HEVC/AV1, HLS/DASH, captions.
- Playback and delivery — the player, the CDN or origin, the embed.
- Accessibility and compliance — subtitles, audio description, keyboard support, GDPR-friendly analytics.
Open source is strongest in the middle two layers, but the first and last are catching up quickly. The tools below are field-tested, not just listed from a package manager.
FFmpeg: The Encoding Workhorse
FFmpeg is the first tool I install on any machine that will touch video. It is a command-line suite for decoding, encoding, muxing, filtering, and streaming. The learning curve is real, but the payoff is a reproducible pipeline that does not depend on a vendor’s export dialog.
A typical H.264 ladder for a 1080p source looks like this:
ffmpeg -i input.mov \
-filter_complex \
"[0:v]split=4[v1][v2][v3][v4]; \
[v1]scale=1920:1080[v1out]; \
[v2]scale=1280:720[v2out]; \
[v3]scale=854:480[v3out]; \
[v4]scale=640:360[v4out]" \
-map "[v1out]" -c:v:0 libx264 -b:v:0 5000k -maxrate:v:0 5350k -bufsize:v:0 7500k \
-map "[v2out]" -c:v:1 libx264 -b:v:1 2800k -maxrate:v:1 2996k -bufsize:v:1 4200k \
-map "[v3out]" -c:v:2 libx264 -b:v:2 1400k -maxrate:v:2 1498k -bufsize:v:2 2100k \
-map "[v4out]" -c:v:3 libx264 -b:v:3 800k -maxrate:v:3 856k -bufsize:v:3 1200k \
-map 0:a -c:a aac -b:a 128k -ac 2 \
-f hls -hls_time 4 -hls_playlist_type vod \
-master_pl_name master.m3u8 output_%v/index.m3u8
This is not a copy-paste recipe for every project. Bitrates depend on content type: a talking-head interview needs less than a handheld street scene. I run a short test encode at three bitrates and check the VMAF score before committing to a full ladder. FFmpeg’s libvmaf filter makes that possible without external services.
For AV1, the story has more layers. libaom-av1 is slow but excellent for VOD. libsvtav1 is faster and now my default for 1080p and above. The tradeoff is CPU time: a 10-minute 1080p source can take 20–40 minutes on a mid-range laptop. For live AV1, I would wait unless you have dedicated encoding hardware.
OBS Studio: Capture and Live Switching
OBS Studio is the most mature open-source tool for capture, scene composition, and live streaming. I use it for webinars, conference talks, and occasional live coding sessions. The key is to treat OBS as a switcher, not an editor. It is excellent at real-time compositing, but you should not try to fix a bad recording inside OBS.
My standard OBS setup for a single-speaker stream:
- Scene 1: camera + screen share side by side, with a subtle background.
- Scene 2: full-screen slides, camera as a small overlay.
- Scene 3: full-screen camera for Q&A.
- Audio: one USB microphone, noise suppression filter, compressor, limiter.
For streaming to a self-hosted RTMP server, OBS works with any endpoint that accepts RTMP or SRT. I have used it with nginx-rtmp and with MediaMTX, both open source. The main gotcha is keyframe interval: set it to 2 seconds for HLS compatibility, or viewers will see long buffering when they join.
HandBrake: The Transcoding GUI
HandBrake is a graphical front-end for many of the same libraries FFmpeg uses. I recommend it for people who need a reliable batch transcoder without writing command lines. It is especially good for:
- Converting camera originals to a mezzanine format like ProRes or high-bitrate H.264.
- Creating a first-pass web version before fine-tuning with FFmpeg.
- Batch-processing a folder of recordings with the same settings.
HandBrake’s presets are sensible, but I always check the audio tab. The default AAC bitrate is often 160 kbps, which is fine for speech but low for music. For a music performance video, I use 256 kbps AAC or pass through the original PCM if the player supports it.
Shaka Packager: DASH and HLS Packaging
Shaka Packager is a command-line tool from Google for packaging encoded video into DASH and HLS. It is more focused than FFmpeg’s built-in HLS muxer and gives you finer control over DRM, subtitles, and multiple periods.
I use Shaka Packager when I need both DASH and HLS from the same set of encoded files. A minimal command looks like this:
packager \
in=video_1080p.mp4,stream=video,output=video_1080p.mp4 \
in=video_720p.mp4,stream=video,output=video_720p.mp4 \
in=audio_en.mp4,stream=audio,output=audio_en.mp4 \
--mpd_output manifest.mpd \
--hls_master_playlist_output master.m3u8
The main reason to prefer Shaka Packager over FFmpeg for packaging is subtitle support. WebVTT and TTML handling is more predictable, and you can add DRM later without re-encoding. For a small publisher, DRM is rarely worth the complexity, but the option is there.
Video.js and hls.js: Playback Without Lock-In
On the playback side, two projects dominate open-source web video: Video.js and hls.js. Video.js is a full player framework with skins, plugins, and a large community. hls.js is a JavaScript library that lets Safari, Chrome, and Firefox play HLS natively in the browser via Media Source Extensions.
My default for a self-hosted VOD site is Video.js with the hls.js plugin. The setup is straightforward:
<video-js id="player" class="vjs-default-skin" controls preload="auto" width="640" height="360">
<source src="https://cdn.example.com/video/master.m3u8" type="application/x-mpegURL">
</video-js>
<script>
var player = videojs('player');
player.ready(function() {
player.src({ src: 'https://cdn.example.com/video/master.m3u8', type: 'application/x-mpegURL' });
});
</script>
The tradeoff is that hls.js does not support FairPlay DRM, so if you need DRM on Apple devices, you must use native HLS playback. For most indie publishers, DRM is not worth the cost and user friction. I would rather spend that effort on good captions and a fast CDN.
Accessibility: WebVTT, Subtitle Edit, and the European Angle
Accessible time-based media is not a nice-to-have in the EU. The European Accessibility Act will apply to many e-commerce and media services from June 2025, and the existing Web Accessibility Directive already covers public sector bodies. For a small publisher, the practical steps are:
- Provide captions for all spoken content.
- Provide audio description for key visual information, or at least a descriptive transcript.
- Ensure the player is keyboard-operable and works with screen readers.
- Offer a text alternative for time-based media where possible.
For caption creation, Subtitle Edit is an open-source desktop editor for Windows and Linux. It handles WebVTT, SRT, TTML, and many other formats. I use it to correct automatic transcripts and to adjust timing. The waveform view is especially useful for aligning captions to speech.
For live captions, the open-source options are less mature. Vosk is an offline speech recognition toolkit that can produce real-time transcripts, but accuracy varies with accent and background noise. I have used it for internal testing, not for public-facing live captions. For public events, a human captioner is still the most reliable choice.
Self-Hosted Analytics Without Surveillance
Most commercial video players include analytics that send viewer data to a third party. Under GDPR, that requires a legal basis and clear consent. A self-hosted open-source alternative is Matomo, which can track video plays, pauses, and completion rates without sending data to an external server.
I configure Matomo to track video events via the Video.js plugin. The data stays on my server, and I can set an anonymized IP mask. This is not a perfect solution — Matomo still uses cookies by default — but it is far more transparent than embedding a third-party player with hidden trackers.
Live Streaming: MediaMTX and nginx-rtmp
For live streaming, two open-source servers are worth knowing: MediaMTX and nginx-rtmp. MediaMTX is a modern, single-binary server that supports RTMP, SRT, HLS, and WebRTC. nginx-rtmp is an older module for the nginx web server, still widely used but less actively developed.
My current preference is MediaMTX for new projects. The configuration is simple:
rtmp: yes
hls: yes
hlsAllowOrigin: '*'
paths:
live:
runOnDemand: ffmpeg -i rtmp://localhost/$RTMP_PATH -c:v libx264 -b:v 2500k -c:a aac -f hls /var/www/hls/$RTMP_PATH/index.m3u8
This creates an HLS output that any modern browser can play via hls.js. The main limitation is that MediaMTX does not include a built-in web player, so you still need Video.js or hls.js on the front end.
Encoding Ladders: One Size Does Not Fit All
A common mistake is to use the same encoding ladder for every video. A 1080p talking-head interview does not need a 4K rendition, and a fast-action sports clip needs more bitrate at every rung. I build ladders based on three factors:
- Content type — motion, detail, and grain.
- Target devices — mobile, desktop, TV.
- Bandwidth budget — what your audience can actually stream.
For a typical interview on this blog, I use a four-rung ladder: 1080p at 4.5 Mbps, 720p at 2.5 Mbps, 480p at 1.2 Mbps, and 360p at 700 kbps. For a screen recording with mostly static slides, I can drop the top rung and lower all bitrates by 30–40%. The only way to know is to test with VMAF or SSIM and watch the output on a real device.
Workflow: From Camera to Published Page
Here is the exact workflow I use for a typical video on this site:
- Record with OBS or a camera, capturing a high-quality mezzanine file.
- Edit in Kdenlive or Shotcut, both open-source non-linear editors.
- Export a ProRes or high-bitrate H.264 master.
- Create the encoding ladder with FFmpeg, using VMAF to check quality.
- Package with Shaka Packager or FFmpeg’s HLS muxer.
- Upload to a self-hosted origin or a CDN.
- Embed with Video.js and hls.js, with WebVTT captions.
- Track with Matomo, respecting GDPR settings.
This is not the fastest workflow. A commercial SaaS platform can do steps 4–7 in a few clicks. But the open-source path gives me three things: reproducibility, control over quality, and no per-video fees. For a small publisher, those matter more than saving an hour per video.
Common Pitfalls and How to Avoid Them
After years of running this stack, I have made most of the mistakes. Here are the ones that cost the most time:
- Wrong keyframe interval — HLS needs a consistent keyframe interval, usually 2–4 seconds. If you encode with the default FFmpeg settings, you may get a 10-second interval, which causes slow starts and buffering.
- Ignoring audio loudness — web video should target around -16 LUFS for stereo. Use FFmpeg’s
loudnormfilter or a tool like ffmpeg-normalize to set consistent levels. - Forgetting captions — captions are not just for accessibility; they also improve comprehension for non-native speakers and people watching without sound. Add them from the start, not as an afterthought.
- Overloading the origin server — if you self-host HLS, a single popular video can saturate a small VPS. Use a CDN or at least a caching reverse proxy like nginx.
What About Editing? Kdenlive and Shotcut
For editing, the two open-source options I recommend are Kdenlive and Shotcut. Kdenlive is more feature-rich and closer to a traditional NLE, with a timeline, effects, and keyframes. Shotcut is simpler and more approachable, with a slightly unusual interface based on filters.
Neither is a drop-in replacement for DaVinci Resolve or Premiere Pro, but for cutting interviews, adding titles, and basic color correction, they are more than enough. I use Kdenlive for most projects because its proxy editing feature handles 4K footage smoothly on modest hardware.
Building a Durable Niche Publication
This article is part of a larger effort on webmultimediale.org to document field-tested open-source multimedia engineering for the web. The goal is not to chase every new tool, but to build a reliable reference for indie creators and small teams in Europe who need to publish accessible, high-quality video without vendor lock-in.
If you are following along, the next logical step is to set up a small test pipeline: encode a short clip with FFmpeg, package it with Shaka Packager, and play it back with Video.js. Then add captions and check the result with a screen reader. That single exercise will teach you more than any list of tools.
Frequently Asked Questions
Is FFmpeg really free for commercial use?
FFmpeg is licensed under LGPL/GPL, which means you can use it in commercial projects, but you must comply with the license terms. If you distribute FFmpeg binaries, you need to provide the source code or a written offer. If you only use it internally on your own server, the obligations are minimal. Always check the specific build, because some include non-free codecs like Fraunhofer AAC.
Can I use open-source tools for live streaming to YouTube or Twitch?
Yes. OBS Studio can stream to any RTMP endpoint, including YouTube, Twitch, and self-hosted servers. The open-source part is the encoder and switcher; the platform still controls the player and analytics. For a fully self-hosted live stream, you would use OBS with MediaMTX or nginx-rtmp and a web player like Video.js.
What is the best open-source video player for accessibility?
Video.js has the strongest accessibility story among open-source players. It supports keyboard navigation, ARIA labels, and caption rendering via WebVTT. The Able Player project goes further, with support for audio description and sign language video, but it is less widely used and requires more configuration. For most publishers, Video.js with well-formed WebVTT captions is a solid baseline.
Do I need a CDN if I self-host video?
For a small audience, a single VPS with nginx can serve HLS without major issues. But if a video gets shared widely, a CDN becomes necessary to avoid saturating your server. Many European CDN providers offer GDPR-compliant options, and you can also use a simple setup with BunnyCDN or Cloudflare. The key is to keep the origin server private and let the CDN handle the public traffic.
Next Steps and Reader Question
This article is the first in a planned series on open-source web video production. Future pieces will cover per-title encoding with VMAF, building an accessible player from scratch, and a deep dive into live streaming with SRT. If you have a specific question or a tool you think I should test, leave a comment or send a message through the contact page. I read every note and often turn reader questions into follow-up articles.


