mpph264enc could not say constrained-baseline, so H.264 was never offered

webrtcsink's codec discovery builds its encoding chain with no output caps, so `force_profile` is
true and it inserts a capsfilter demanding `profile=constrained-baseline` — WebRTC's interoperable
floor. h264parse strips `alignment`, `stream-format` and `parsed` from a caps query but not
`profile`, so that demand reaches mpph264enc's src pad, whose template listed only
`{ baseline, main, high }`. Empty intersection, GstVideoEncoder's sink getcaps returns nothing,
and the failure surfaces upstream as videorate reporting it "could not transform NV12 ... in
anything we support". Discovery then drops H.264 with a warning nobody was reading, VP8 wins by
default, and the session dies in rtpvp8pay.

The element could always produce constrained-baseline; only its static template denied it.
Measured on an RK3566: `mpph264enc profile=baseline ! h264parse` negotiates
`profile=(string)constrained-baseline` on the parser's src pad, because baseline mode turns CABAC
and 8x8 transform off and MPP emits no FMO, ASO or redundant slices. So this widens the template
by one word rather than claiming something new.

Patches now live in a directory per upstream, applied by an `apply_patches` helper and recorded in
the MANIFEST as `patch <project>/<file>`. Two reasons: a patch aimed at the wrong tree failed the
same way a stale one does, and the MANIFEST's flat `patch <file>` line landed next to whichever
.so happened to precede it, which read as provenance for the wrong plugin.

Assisted-by: Claude:claude-opus-5[1m]
This commit is contained in:
Pierre Rouanet
2026-08-25 11:29:02 +02:00
parent b81b50199a
commit a9a839f274
5 changed files with 102 additions and 27 deletions
+17 -10
View File
@@ -7,7 +7,7 @@ Two plugins, for two unrelated reasons. Neither is packaged anywhere we can inst
| 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). |
| `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
@@ -104,16 +104,23 @@ These are binaries built from other people's source, so where that source is mat
[the upstream repository](https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs) at the tag in
`pins.env`.
**`gst-plugins-rs` is patched, and that matters for more than tidiness.** MPL-2.0 asks that
modifications be identifiable, so it is 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 the
upstream ref *and* every patch applied over it. `gstreamer-rockchip` is unmodified.
**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.
There is one patch today: `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. [`patches/README.md`](patches/README.md) has the reasoning, the
trade-off it accepts, and the route upstream that would delete 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.