Ceracoder - live video encoder with dynamic bitrate control and SRT support
Ceracoder is a fork of irlserver/belacoder, which itself is a fork of the original BELABOX/belacoder project.
This is a GStreamer-based encoder with support for SRT and dynamic bitrate control depending on the network capacity. This means that if needed, the video bitrate is automatically reduced on-the-fly to match the speed of the network connection. The intended application is live video streaming over bonded 4G modems by using it on a single board computer together with a HDMI capture card and srtla.
Ceracoder is developed on an NVIDIA Jetson Nano (Amazon.com / Amazon.co.uk / NVIDIA), and we provide GStreamer pipelines for using its hardware video encoding. However it can also be used on other platforms as long as the correct GStreamer pipeline is provided.
Ceracoder reads a GStreamer pipeline from a file, constructs it, and streams the output over SRT:
┌──────────────┐ ┌─────────────┐ ┌───────────┐
│ GStreamer │ ──▶ │ appsink │ ──▶ │ SRT send │ ──▶ Network
│ Pipeline │ │ (callback) │ │ (libsrt) │
└──────────────┘ └─────────────┘ └───────────┘
▲
┌────────────────────┘
│ Periodic stats polling
▼
┌───────────────────┐
│ Bitrate Controller│ ──▶ Adjusts encoder bitrate
└───────────────────┘
The bitrate controller polls SRT statistics (RTT, send buffer) every 20 ms and adjusts the encoder's bitrate to avoid congestion. See docs/bitrate-control.md for the algorithm details.
Ceracoder is designed to work with srtla (SRT Link Aggregation) for bonding multiple network connections. This is the primary use case for live streaming over cellular networks.
┌──────────────┐
│ ceracoder │
│ (encoder + │──SRT──▶┌─────────┐ ┌─────────┐
│ SRT sender) │ │ srtla │ │ Modem 1 │──┐
└──────────────┘ │ (local) │────▶│ (4G/5G) │ │
│ │ └─────────┘ │
│ │ ┌─────────┐ │ ┌─────────────┐
│ │────▶│ Modem 2 │──┼───▶│ srtla_rec │──SRT──▶ Server
│ │ │ (4G/5G) │ │ │ (receiver) │
│ │ └─────────┘ │ └─────────────┘
│ │ ┌─────────┐ │
│ │────▶│ Modem 3 │──┘
└─────────┘ │ (WiFi) │
└─────────┘
- ceracoder encodes video and sends SRT to localhost (where srtla runs)
- srtla splits the SRT stream across multiple network interfaces (modems, WiFi, etc.)
- srtla_rec on the receiving end reassembles the stream and forwards to the SRT server
# Terminal 1: Start srtla (bonding agent)
srtla_send 127.0.0.1 5000 receiver.example.com 5000
# Terminal 2: Start ceracoder pointing to local srtla
./ceracoder pipeline/h264_camlink_1080p 127.0.0.1 5000 -s mystreamid -l 2000 -b bitrate.confWhen using multiple networks:
- Aggregate bandwidth can exceed any single connection
- Packet loss on one link doesn't drop the stream (redundancy)
- Variable capacity as modems enter/exit coverage areas
Ceracoder's adaptive bitrate algorithm adjusts to the combined capacity of all bonded links as reported by SRT. When a modem drops out, SRT's buffer grows and RTT increases, triggering bitrate reduction. When capacity increases, ceracoder gradually ramps up.
| Scenario | Recommended Settings |
|---|---|
| 2x 4G modems | -l 2000 (2s latency), max 8-12 Mbps |
| 3+ modems (aggressive) | -l 1500, max 15-20 Mbps |
| Single modem (no srtla) | -l 3000, conservative max bitrate |
| Stable network (fiber) | Higher max bitrate, can use fixed mode |
For srtla setup instructions, see CERALIVE/srtla.
| Dependency | Minimum | Notes |
|---|---|---|
| GStreamer | 1.14+ | Core + app library |
| GLib | 2.40+ | (bundled with GStreamer) |
| libsrt | 1.4.0+ | Enforced at compile time; recommend CERALIVE/srt fork |
| GCC/Clang | 4.9/3.5 | C99 support |
Note: ceracoder includes a compile-time check for SRT 1.4.0+. If you see an error like
#error "SRT 1.4.0 or later required", upgrade your libsrt installation.
# Build tools + GStreamer
sudo apt-get install build-essential git pkg-config cmake \
libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev \
gstreamer1.0-plugins-base gstreamer1.0-plugins-good \
gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-libav
# SRT (CERALIVE fork with BELABOX patches)
git clone https://github.com/CERALIVE/srt.git
cd srt
mkdir build && cd build
cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local
make -j$(nproc)
sudo make install
sudo ldconfigFor a complete dependency list including pipeline-specific plugins, see docs/dependencies.md.
git clone https://github.com/CERALIVE/ceracoder.git
cd ceracoder
makeThe Makefile uses pkg-config to locate GStreamer and libsrt. Ensure both are installed and discoverable:
pkg-config --modversion gstreamer-1.0 gstreamer-app-1.0 srtCeracoder includes comprehensive integration tests that verify module behavior without requiring actual hardware:
# Install test dependencies
sudo apt-get install libcmocka-dev
# Basic tests (balancer algorithms, module integration)
make test
# Full test suite (includes SRT network integration tests)
make test_allTests verify:
- Balancer algorithm behavior (adaptive, fixed, AIMD) - 16 tests
- Config loading and reload - 8 tests
- SRT network operations (in-process and external listener) - 13 tests
- Bitrate bounds enforcement
- Network condition responses
The test suite includes both unit-style tests with fakes and real SRT network integration tests.
The project uses clang-tidy for static analysis:
# Run static analysis locally
make lintStatic analysis runs automatically in CI on every push/PR. The configuration is tuned for C code with GStreamer patterns.
Syntax: ceracoder PIPELINE_FILE ADDR PORT [options]
Options:
-v Print the version and exit
-c <config file> Configuration file (INI format, recommended)
-d <delay> Audio-video delay in milliseconds
-s <streamid> SRT stream ID
-l <latency> SRT latency in milliseconds (default: 2000)
-r Reduced SRT packet size (6 TS packets instead of 7)
-b <bitrate file> Bitrate settings file (legacy, use -c instead)
-a <algorithm> Bitrate balancer algorithm (overrides config)
Config file example (ceracoder.conf):
[general]
min_bitrate = 500 # Kbps
max_bitrate = 6000 # Kbps (6 Mbps)
balancer = adaptive # Algorithm: adaptive, fixed, aimd
[srt]
latency = 2000 # ms
[adaptive]
incr_step = 30 # Bitrate increase step (Kbps)
decr_step = 100 # Bitrate decrease step (Kbps)
incr_interval = 500 # Min interval between increases (ms)
decr_interval = 200 # Min interval between decreases (ms)
---
Send SIGHUP to reload configuration while running:
kill -HUP $(pidof ceracoder)
Where:
PIPELINE_FILEis a text file containing the GStreamer pipeline to use. See thepipelinedirectory for ready-made pipelines.ADDRis the hostname or IP address of the SRT listener to stream to.PORTis the port of the SRT listener to stream to.-c <config file>is the recommended way to configure bitrate bounds and algorithm settings. Seeceracoder.conf.examplefor a full example.-d <delay>is the optional delay in milliseconds to add to the audio stream relative to the video.-b <bitrate file>is the legacy way to set bitrate bounds (use-cinstead for new deployments).
Ceracoder supports multiple bitrate control algorithms:
| Algorithm | Description | Best For |
|---|---|---|
| adaptive (default) | RTT and buffer-based control with graduated response | Most use cases, variable networks |
| fixed | Constant bitrate, no adaptation | Stable networks, testing |
| aimd | TCP-style Additive Increase Multiplicative Decrease | Fair bandwidth sharing |
Select via config file or override with -a <algorithm>.
The GStreamer pipelines are available in the pipeline directory, organised in machine-specific directories (for pipelines using hardware-accelerated features) or generic (for software-only pipelines). The filename format is CODEC_CAPTUREDEV_[RES[FPS]]:
CODECish265orh264(for system-specific hw encoders), orx264_superfast/x264_veryfastfor x264 software encodingCAPTUREDEVis eithercamlinkfor Elgato Cam Link 4K (Amazon.com / Amazon.co.uk) or other uncompressed YUY2 capture cards orv4l_mjpegfor low cost USB2.0 MJPEG capture cards (Amazon.com / Amazon.co.uk)REScan be blank - capturing at the highest available resolution,720p,1080p,1440p, or4k_2160pFPScan be blank - capturing at the highest available refresh rate,29.97, or30FPS
Note that to encode 4k / 2160p video captured by a camlink you must specifically use h265_camlink_4k_2160p rather than h265_camlink, as the preset-level quality setting of the encoder must be set to a lower value to allow the encoder to maintain 30 FPS in all conditions.
For ceracoder features to work, pipelines must include specific named elements:
| Element | Required | Purpose |
|---|---|---|
appsink name=appsink |
Yes (for SRT output) | Hands buffers to ceracoder for SRT transmission |
name=venc_bps or name=venc_kbps |
For dynamic bitrate | Video encoder with runtime-settable bitrate property |
name=overlay |
Optional | Text overlay for on-screen bitrate/stats display |
name=a_delay / name=v_delay |
Optional | Identity elements for A/V sync adjustment |
name=ptsfixup |
Optional | PTS jitter smoothing (helps with OBS compatibility) |
- The Jetson Nano hardware encoders seem biased towards allocating most of the bitrate budget to I-frames, while heavily compressing P-frames, especially on lower bitrates. This can heavily affect image quality when most of the image is moving and this is why we limit the quantization range in our pipelines using
qp-range. This range makes a big improvement over the defaults, however in some cases results can probably be further improved with different parameters. identity name=a_delay signal-handoffs=TRUEandidentity name=v_delay signal-handoffs=TRUEelements can be used to adjust the PTS (presentation timestamp) of the audio and video streams respectively by the delay specified with-d. Use them to synchronise the audio and video if needed (e.g. audio delay of around 900 for a GoPro Hero7 with stabilisation enabled).
| Error | Cause | Fix |
|---|---|---|
| "connection timed out" | Server unreachable or port blocked | Check firewall, verify host/port |
| "streamid already in use" | Duplicate stream ID on server | Use unique -s <streamid> |
| "invalid streamid" | Server rejected stream ID | Check server's access control config |
| "failed to resolve address" | DNS failure | Use IP address or fix DNS |
- "Failed to get an encoder element": Pipeline doesn't have
name=venc_bpsorname=venc_kbps. Dynamic bitrate control disabled. - "Pipeline stall detected": Capture device stopped providing frames. Check V4L2 device, resolution, or cable.
- GStreamer element not found: Missing plugin package. Run
gst-inspect-1.0 <element>to check, install the required package (see docs/dependencies.md).
The negotiated SRT latency is printed on connect:
SRT connected to example.com:4000. Negotiated latency: 2000 ms
If the receiver requests higher latency, ceracoder will use the higher value. Adjust with -l <ms> if needed.
A Dockerfile is provided that builds ceracoder with the CERALIVE/srt fork:
# Build the image
docker build -t ceracoder .
# Extract the binary
docker create --name cc ceracoder
docker cp cc:/usr/bin/ceracoder ./ceracoder
docker rm ccThe container build installs SRT from CERALIVE/srt to /usr, so pkg-config srt works correctly inside the build.
- Architecture – System overview and dataflow
- Dependencies – Full dependency list with versions
- Bitrate Control – Adaptive bitrate algorithm details
- Versioning – CalVer versioning scheme with beta release support
If you find Ceracoder useful, consider supporting CeraLive development:
Ceracoder is licensed under the GNU General Public License v3.0. See LICENSE for details.