fix(viewer): pi2/pi3 video via GStreamer HW pipeline (replace VLC) - #2972
Merged
Conversation
There was a problem hiding this comment.
Pull request overview
This PR restores video playback on Qt5/linuxfb Raspberry Pi boards by replacing the prior VLC-based path with an ffmpeg-based player that hardware-decodes via V4L2 M2M and renders directly to /dev/fb0 (fbdev), avoiding DRM-master/compositor requirements that cause black video on Pi 2/3 post-Bookworm.
Changes:
- Add
FFmpegFbdevMediaPlayer(ffprobe codec selection → optional<codec>_v4l2m2mdecode → scale/pad/format/transpose →-f fbdev). - Route linuxfb Pi devices to the new ffmpeg player via
MediaPlayerProxyand update unit tests accordingly. - Update docs and Qt-side comments to reflect the new linuxfb video path.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
src/anthias_viewer/media_player.py |
Introduces FFmpegFbdevMediaPlayer and routes Pi linuxfb playback to it. |
tests/test_media_player.py |
Replaces VLC tests with ffmpeg/fbdev player tests + proxy routing assertions. |
docs/board-enablement.md |
Documents the Pi 2/3 ffmpeg→fbdev playback strategy and rationale. |
src/anthias_webview/src/view.h |
Updates comments describing how Qt5 boards play video. |
src/anthias_webview/src/view.cpp |
Updates comments describing how Qt5 boards play video. |
src/anthias_webview/src/mainwindow.h |
Updates comments about Qt5 boards bypassing Qt video slots. |
src/anthias_webview/AnthiasViewer.pro |
Updates build comments describing the Qt5 video path. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
vpetersson
force-pushed
the
fix/pi3-video-ffmpeg-fbdev
branch
from
June 2, 2026 11:19
a7a6b16 to
010c723
Compare
vpetersson
force-pushed
the
fix/pi3-video-ffmpeg-fbdev
branch
3 times, most recently
from
June 2, 2026 11:56
81f1d4d to
514e62a
Compare
vpetersson
force-pushed
the
fix/pi3-video-ffmpeg-fbdev
branch
from
June 2, 2026 12:03
514e62a to
6dc3dbf
Compare
- Replace VLCMediaPlayer with GstFbdevMediaPlayer: spawn `gst-launch-1.0 playbin` with a fully-hardware video sink — v4l2h264dec (bcm2835 codec) decodes, v4l2convert (bcm2835 ISP) HW-scales + converts YUV to the framebuffer format, fbdevsink paints /dev/fb0. No DRM master / X / Wayland needed, which a bare uid-1000 viewer with no compositor cannot acquire. - Restores hardware video on the Qt5 linuxfb boards after #1980 dropped the Broadcom mmal_vout; drives the same VPU + ISP silicon mmal used. Measured on a Pi 3: 1080p30 -> rgb565 at ~40 fps, zero dropped frames. (An interim ffmpeg -> fbdev approach was abandoned: HW decode worked but CPU YUV->rgb565 convert via swscale managed only ~6 fps — no NEON path — and CPU scaling is unaccelerated. v4l2convert moves that to the ISP.) - playbin gives container-agnostic demux, auto-plugged HW decoder, and graceful optional-audio. Loop the slot via re-launch-on-EOS; kill by process group so no gst-launch orphan keeps the framebuffer. - Rotation rides `videoflip`, inserted only when the panel is rotated. - Add gstreamer1.0-{tools,plugins-base,plugins-good,plugins-bad} to the Qt5 viewer image; drop the now-unused vlc apt package + python-vlc dep (+ its mypy override). Sync the upload-gate comment in processing.py. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
vpetersson
force-pushed
the
fix/pi3-video-ffmpeg-fbdev
branch
from
June 2, 2026 12:10
6dc3dbf to
11bc78f
Compare
|
5 tasks
vpetersson
added a commit
that referenced
this pull request
Jun 2, 2026
- CalVer (YYYY.0M.MICRO); still June 2026, micro 0 -> 1 - Ships the QML VideoOutput presentation path (#2975), the pi2/pi3 GStreamer HW video pipeline (#2972), and the x86 WLR_DRM_NO_ATOMIC display-freeze fix (#2978) - Also picks up Pi 4 eglfs rotation (#2971, #2973), the armv7 viewer spawn retry (#2969), the Writeback-connector headless guard (#2968), and viewer log cleanups (#2977, #2979) Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Issue Fixed
pi2/pi3 (Qt5 linuxfb) video plays black fleet-wide. Reproduced + root-caused on a Pi 3B+ (across every OS version, so not a recent regression in itself):
Showing asset … (video)is logged but nothing reaches the screen. Images/webpages are fine; pi4/pi5/x86 are fine (Qt6 in-process QtMultimedia).Root cause
--vout=mmal_vout(HW decode, HW scale, HW color-convert, HW scanout — no DRM master). The Bookworm upgrade (Upgrade containers to use Bookworm #1980) droppedmmaland nothing replaced the vout.--vout, VLC falls back to outputs that can't drive a bare linuxfb console: the rpidistrodrm_voutwants a compositor DRM lease (Failed to get xlease— there's no X/Wayland), and the KMS/master vouts need DRM master, which a uid-1000 viewer can't acquire (the viewer's python process already holdscard0→EBUSY/EPERM). mpv--vo=drmhits the sameEBUSY.Fix
Replace
VLCMediaPlayerwithGstFbdevMediaPlayerfor the linuxfb boards (pi1/pi2/pi3): spawngst-launch-1.0 playbinwith a fully-hardware video sink that reaches/dev/fb0without any DRM master / compositor:This drives the same VPU + ISP silicon mmal used — decode, scale and color-convert all stay in hardware; only the final framebuffer write is a CPU memcpy.
playbingives container-agnostic demux, auto-plugs the HW decoder (v4l2h264decat PRIMARY rank), and degrades gracefully when a clip has no audio track. Rotation ridesvideoflip, inserted only when the panel is actually rotated.Why not ffmpeg → fbdev
An interim
FFmpegFbdevMediaPlayer(ffmpeg HW-decode → CPU convert →-f fbdev) was built and then abandoned after benchmarking on the Pi 3: HW decode worked (~60 fps), but doing the YUV→RGB convert + scale on the ARM CPU via swscale managed only ~6 fps to rgb565 (no NEON rgb565 path) and ~28 fps to bgra — and any real scaling collapsed it further.v4l2convertmoves that work back onto the ISP, which is what the ~40 fps, 0-drop benchmark above measures. (An earlier "decode hang" scare turned out to be a malformed trimmed test clip that didn't start on an IDR — the strict HW decoder waits for a random-access point; well-formed clips decode fine.)Description
GstFbdevMediaPlayer: builds thegst-launch playbinargv, loops the on-screen slot by re-launching on EOS (breaks on error), and kills by process group so nogst-launchorphan keeps the framebuffer. Reads fb geometry/format from/sys/class/graphics/fb0to pin thev4l2convertoutput caps.MediaPlayerProxyroutes pi1/pi2/pi3 →GstFbdevMediaPlayer; everything else (incl. forcedpi4-64/arm64) stays onMPVMediaPlayer.gstreamer1.0-{tools,plugins-base,plugins-good,plugins-bad}to the Qt5 viewer; drop the now-unusedvlcapt package +python-vlcdep (+ its mypy override).docs/board-enablement.md), the upload-gate comment inprocessing.py, and C++/.procomments updated.On-device validation
Run on a live fleet Pi 3 (HDMI attached). This surfaced — and the PR fixes — two bugs that the headless benchmark could not (it used
file://URIs andfakesinkaudio):playbin'surineeds a scheme;_as_gst_uri()now wraps bare paths asfile://.alsasink— Debian ships the ALSA sink ingstreamer1.0-alsa(not-plugins-base); without it theaudio-sink=alsasink …fails pipeline construction and black-screens all video. Added to the image deps.After both fixes the full pipeline renders correctly on real hardware.
Checklist
v4l2h264dec→v4l2convert→RGB16 →fbdevsink+alsasinkHDMI audio) constructs and writes motion video to the real/dev/fb0with zero pipeline errors (verified by capturing the framebuffer across frames). HW decode + scale + convert benchmarked at ~40 fps / 0 drops.docs/board-enablement.md).🤖 Generated with Claude Code