# microduck-gst-plugins Prebuilt aarch64 GStreamer plugins for the micro duck robot, built in CI from pinned upstream sources and attached to a release. Two plugins, for two unrelated reasons. Neither is packaged anywhere we can install from. | plugin | provides | why it is here | |---|---|---| | `libgstrockchipmpp.so` | `mpph264enc`, `mpph265enc`, `mppjpegenc`, `mppvp8enc`, `mppvideodec`, `mppjpegdec` | Debian ships no Rockchip encoder in any suite. Radxa's own `gstreamer1.0-rockchip1_1.14-4` does contain them, so this build is about the pin, dropping `libx11-6`, and riding along with the plugin below — see [below](#the-permission-trap-that-hid-all-of-this). Patched; see [`patches/`](patches/). | | `libgstrswebrtc.so`, `libgstrsrtp.so` | `webrtcsink`, `webrtcsrc`, `rsrtp*` | `gstreamer1.0-plugins-rs` does not exist in **any** Debian suite — not trixie, backports, sid or experimental. Patched; see [`patches/`](patches/). | `webrtcbin` is **not** here: it comes from `gstreamer1.0-plugins-bad` in Debian and needs no build. ## Why a repository of its own The robot's daemon is cross-compiled from a developer's machine with `cargo-zigbuild`, and its one C dependency is already the documented cost of doing that. GStreamer would be a much larger second one — a cross sysroot or x86 multiarch, either of which links against an approximation of the target. So these are built **natively on an arm64 runner, in a `debian:trixie` container**, which is the robot's own userland. Nothing is cross-compiled and nothing is approximated. arm64 runners are free on public repositories, which is one reason this repository is public. The other reason matters more: a release asset here is fetched by a robot during provisioning and by the updater's `preinstall` hook, and that hook runs with a cleared environment and no token. A private repository would break it. This is the same arrangement the daemon already relies on for ONNX Runtime, which comes from a public `microsoft/onnxruntime` release. Building rather than taking a third-party binary also buys one concrete thing beyond provenance: `rkximage` and `kmssrc`, the X11 and KMS *sinks* in the same source tree, are **disabled**. A headless robot has no use for either, and they are why the prebuilt Radxa deb depends on `libx11-6`. ## The permission trap that hid all of this `/dev/mpp_service` arrives as `0600 root:root`, and **an MPP GStreamer plugin registers its decoders unconditionally but probes MPP before registering its encoders.** With the node unreadable the probe fails and the encoders are silently omitted — no error, no log line. That one cause produced four separate misleading results while this was being worked out: - `mpi_enc_test` wrote an empty file and **exited 0**. - Radxa's `1.14-4` looked decode-only. It is not; `strings` on its `.so` lists every encoder. - A third-party `1.14-8` deb installed cleanly and still showed no `mpph264enc`. - This repository's own CI build shows only `mppjpegdec` and `mppvideodec`, because a container has no `/dev/mpp_service` either. **That is expected, not a failed build.** So: a plugin that lists only decoders is evidence about the *device node*, not about the plugin. A non-root process needs a udev rule giving the node a group — mode `0660`, group `video` — and only then does `gst-inspect-1.0 mpph264enc` mean anything. ## Consuming a release ``` tar -xzf microduck-gst-plugins--aarch64.tar.gz ``` Put the `.so` files anywhere and point `GST_PLUGIN_PATH` at it — `/usr/local/lib/gstreamer-1.0` on a robot, which is deliberately **not** the distro's plugin directory, so an `apt` operation can never quietly replace or remove them. ``` GST_PLUGIN_PATH=/usr/local/lib/gstreamer-1.0 gst-inspect-1.0 mpph264enc ``` Verify the tarball against the `.sha256` beside it before unpacking. **Pin a version**; do not follow "latest". Two provisioning runs a day apart that produce different plugins, with nothing recording which, is an unreproducible media bug waiting to happen. ### Runtime dependencies The plugins link against libraries a robot needs installed: - `librockchip-mpp1` and `librga2` — from Radxa's pool, at the versions in [`pins.env`](pins.env). Not in Debian. - `libgstreamer1.0-0`, `libgstreamer-plugins-base1.0-0`, `libglib2.0-0`, `libdrm2` — Debian. `mpph264enc` also needs **read/write access to `/dev/mpp_service`** — see [the permission trap](#the-permission-trap-that-hid-all-of-this), which is the single most misleading thing about this stack. ## Bumping a pin Edit [`pins.env`](pins.env), commit, tag `vN`, push the tag. The release workflow builds and attaches the tarball, with the manifest as the release notes so a release always says which upstream commits it came from. `workflow_dispatch` builds without cutting a release — worth using, because a workflow that only ever runs on a tag is one you discover is broken at the moment you need it. ## Licences and source These are binaries built from other people's source, so where that source is matters: - **`gstreamer-rockchip`** is LGPL. Built from [`JeffyCN/mirrors`](https://github.com/JeffyCN/mirrors) on the `gstreamer-rockchip` branch, at the commit in `pins.env` and recorded in every release's `MANIFEST`. `rockchip-linux/gstreamer-rockchip`, which every published deb names as its homepage, is a 404; `JeffyCN/mirrors` is the live mirror under the same maintainer. - **`gst-plugins-rs`** is MPL-2.0. Built from [the upstream repository](https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs) at the tag in `pins.env`. **Both upstreams are patched, and that matters for more than tidiness.** MPL-2.0 asks that modifications be identifiable, so they are stated here, listed in [`patches/`](patches/) with what each one buys and how it ends, and recorded in every release's `MANIFEST` — a release names each upstream ref *and* every patch applied over it. Two patches today, both about getting hardware H.264 to a browser: - **`gst-plugins-rs`** — `webrtcsink` inserts a software `videoconvert ! videoscale` in front of any encoder it does not recognise, and `mpph264enc` converts on the SoC's 2D accelerator instead, so a CPU pass over every frame is added to work the hardware was going to do anyway, on cores the robot's control loop shares. - **`gstreamer-rockchip`** — `mpph264enc`'s pad template omitted `constrained-baseline` from its profile list, which is the one profile WebRTC asks for. Without this, `webrtcsink` cannot offer H.264 on an RK3566 at all, and the only trace is a `videorate` complaining about NV12. [`patches/README.md`](patches/README.md) has the reasoning for each, the trade-off it accepts, and the route upstream that would delete it. Together the ref and the patch list are both the licence answer and the reason a media bug found on a robot can be traced to a specific build. This repository's own build scripts are Apache-2.0, matching the daemon.