A Rust worker that turns uploaded drone video into streamable video-on-demand. It consumes jobs from a RabbitMQ queue, pulls the source file from S3-compatible object storage, and writes back an HLS rendition, a subtitle track and a thumbnail.
Part of the ARU drone data platform — see Aru-Server, which publishes the jobs this worker consumes.
Transcoding is done with GStreamer through
the gstreamer-rs
bindings, writing directly to object storage via awss3hlssink rather than
staging the output on local disk.
- Declare a durable request queue (
vod.transcode.req) and a durable response queue (vod.transcode.res). - Consume with prefetch 1 and manual acknowledgement, so one worker handles one job at a time and more replicas means more throughput.
- For each job, build a GStreamer pipeline that decodes the source and tees it
into several branches:
- video — scaled and H.264-encoded into an HLS rendition
- audio — encoded and muxed
- subtitles — extracted to an
.srt - thumbnail — a single frame to
thumb.png
- Publish a JSON response carrying the original metadata unchanged, a
successflag, and the output paths. - Acknowledge the message only after the response is published, so a crash mid-job returns the work to the queue rather than losing it.
Output paths are derived from the input key: a job for vod/clip.mp4 produces
vod/clip/index.m3u8, vod/clip/subtitle.srt and vod/clip/thumb.png.
Request:
{ "file": "vod/clip.mp4", "metadata": { "...": "opaque, echoed back" } }Response:
{
"metadata": { "...": "as sent" },
"video": { "hls": "vod/clip", "srt": "vod/clip/subtitle.srt", "thumb": "vod/clip/thumb.png" },
"success": true
}metadata is passed through untouched so the caller can correlate a response
with its request.
- Rust 2021, stable toolchain
- GStreamer development libraries, including the
badplugin set —awss3hlssinklives ingst-plugins-bad - A RabbitMQ instance and an S3-compatible object store
# macOS
brew install gstreamer gst-plugins-base gst-plugins-good gst-plugins-bad
# Debian / Ubuntu
sudo apt install libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev \
gstreamer1.0-plugins-badcp .env.example .env # adjust for your setup
docker compose up # MinIO, RabbitMQ and the worker togetherOr against your own infrastructure:
set -a && source .env && set +a
cargo run --releasetest/ holds a small Node harness for publishing a job onto the queue and
inspecting the response, which is the quickest way to exercise the worker by
hand.
| Variable | Required | Purpose |
|---|---|---|
S3_BUCKET |
yes | bucket to read from and write to |
S3_ENDPOINT |
yes | object store endpoint URL |
AWS_ACCESS_KEY_ID |
no | defaults to minioadmin — see below |
AWS_SECRET_ACCESS_KEY |
no | defaults to minioadmin — see below |
S3_PATH_STYLE |
no | true for MinIO, false for AWS S3. Defaults to false |
S3_REGION |
no | defaults to ap-south-1 |
AMQP_ADDR |
no | defaults to amqp://172.17.0.1:5672/%2f, the Docker bridge gateway |
RUST_LOG |
no | tracing filter. Defaults to info |
S3_BUCKET and S3_ENDPOINT are read with .expect(), so the worker fails at
startup if either is missing rather than running misconfigured.
The two AWS variables fall back to minioadmin / minioadmin, MinIO's
documented defaults, so docker compose up works with no configuration. They
are not Kesowa credentials and there is nothing to rotate.
But a silent fallback to a well-known credential is worth being deliberate about: a production deployment that forgets to set these does not fail, it quietly tries to authenticate with a public default. The bucket and endpoint fail loudly when unset; the credentials do not. Treat that asymmetry as a bug to fix rather than a feature — see CONTRIBUTING.md.
A standalone gst-launch-1.0 pipeline kept for debugging — it transcodes a
fixed /video.mp4 with hardcoded MinIO development credentials. It is not used
by the worker and is not part of the deployed path. Useful for checking whether
a GStreamer plugin problem is in the pipeline or in the Rust code around it.
See CONTRIBUTING.md. Security reports go through SECURITY.md, not public issues.
Released under the MIT License. © Kesowa Infinite Ventures.
Note that GStreamer is LGPL, and the plugin sets vary: gst-plugins-bad
and gst-plugins-ugly contain plugins under other licences, and some codecs
carry patent obligations in some jurisdictions. x264enc, which this worker
uses, is GPL. Linking dynamically keeps LGPL obligations satisfiable, but
the plugin set you ship determines your actual obligations — audit it
before distributing binaries. See
CONTRIBUTING.md.