Skip to content

viewer: embed libmpv in AnthiasWebview to eliminate two-process DRM-master contention #2904

Description

@vpetersson

Background

The viewer currently runs as two processes on the same framebuffer:

  • AnthiasWebview (C++/Qt6, holds the framebuffer for web + image rendering)
  • mpv (subprocess.Popen'd by MPVMediaPlayer, takes --vo=drm and does its own DRM-master juggling for video assets)

When the operator's board has a 4K-EDID-reporting display, the contention between these two processes for /dev/fb0 / DRM master drops frames during video playback even when the HW decode path is engaged. Measured on a real Pi 4 with the BBB test bed during PR #2885 validation: 600-2800 vo drops per 60 s clip on H.264 (v4l2m2m-copy) and HEVC (drm-copy) variants.

The same mpv flags, on the same hardware, with no Qt webview competing for the framebuffer, get 0 drops. The drops are infrastructure contention, not a mpv configuration issue.

Proposed fix (Option A from the PR review)

Embed libmpv directly inside AnthiasWebview so a single Qt process owns the framebuffer and renders both web pages and video into the same Qt window.

Concrete changes

  1. src/anthias_webview/ — C++ side:

    • Add libmpv-dev + libqt6openglwidgets6-dev build deps (apt — see the Conan discussion below).
    • New VideoView : QOpenGLWidget class wrapping an mpv_render_context (reference: mpv-examples/libmpv/qt_opengl/). ~200 LOC.
    • Add playVideo(QString uri) + stopVideo() D-Bus slots on MainWindow.
    • View switches its central widget between QWebEngineView (web), QLabel (image), and VideoView (video) based on which slot was invoked.
    • mpv properties (hwdec, video-sync, audio-device, drm-mode, etc.) set via mpv_set_property_string, replicating today's per-codec dispatch logic.
  2. docker/Dockerfile.viewer.j2 — Pi 4 specifically:

    • Change QT_QPA_PLATFORM=linuxfb to eglfs so Qt has the OpenGL context libmpv needs to render into.
    • Pi 5 / x86 / arm64 stay on cage+wayland (already have GL inside cage).
  3. src/anthias_viewer/media_player.py — Python side:

    • MPVMediaPlayer replaces subprocess.Popen with a QDBusConnection call to the anthias.webview service's playVideo slot.
    • Per-codec hwdec probe (_pi_hwdec_for_uri) sends its result alongside the URI or via a prior setPlaybackOptions slot.
    • stop() calls stopVideo() D-Bus.
  4. Startup ordering — Python already waits for Anthias service start on the webview stdout (current D-Bus readiness signal). Same pattern works for video readiness.

Package management note

The right libmpv build per board comes from each board's apt repo:

  • Pi 4 / Pi 5 / Rock Pi 4 → archive.raspberrypi.com (+rpt1) ships libmpv with --enable-v4l2-request for the HW decoders the viewer mpv binary already uses.
  • x86 → Debian apt ships libmpv with --enable-vaapi.

Each board's per-board viewer image already does apt install from the correct source, so linking against libmpv-dev from the same apt run gets the byte-identical backend as the system mpv binary. Conan was considered but adds machinery to pin a single libmpv version across boards, when we genuinely want per-board variance (v4l2_request on arm, vaapi on x86). qmake → CMake migration is worth doing eventually but is a separate scope.

Why this isn't fixed in PR #2885

Acceptance criteria

  • AnthiasWebview builds with libmpv linked; image stays per-board.
  • Video playback on each of Pi 4, Pi 5, Rock Pi 4, x86 with the BBB test bed produces:
    • The same hwdec banner as today (v4l2m2m-copy / drm-copy / vaapi-copy per board+codec).
    • < 10 vo drops per 60 s clip at 1080p30 H.264 / HEVC and 1080p60 H.264 / HEVC on every board.
  • Pi 4 specifically: QT_QPA_PLATFORM=eglfs confirmed working with V3D 6.0; no regression in image / web-page rendering.
  • The codec gate from feat(viewer,server): per-board HW decode dispatch + codec gate on upload #2885 still functions — rejected codecs surface the same banner + recipe in the Edit Asset modal.

Estimated effort

~2-4 days including per-board perf retest. C++ work is ~300-500 LOC; the rest is build wiring and Python D-Bus glue.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions