Commit Graph
28 Commits
Author SHA1 Message Date
edde746 4b6533d25b fix(linux): stop the HDR watchdog from firing after synchronous no-op transactions
On a Wayland HDR session, colors flickered between HDR and washed-out SDR every ~5 seconds: the mpv-leg timeout in apply_hdr_state was armed after SetHdrOutput returned, so a synchronous reply (the no-op short-circuit that runs on every playback restart and re-describe) orphaned the timer. Five seconds later it fired against a healthy plane and withdrew the live HDR image description; the next re-apply re-attached it and armed the next orphan.

Arm the timeout only while the reply is genuinely outstanding. An asynchronous reply still removes it, and a genuinely wedged core is still bounded.

Verified in a headless-sway Docker repro against the same PQ/BT.2020 file: 2.15.0 logs the false 'mpv never answered the output colour-space switch' warning 5 s after plane bring-up and again after source recognition; the fixed build logs none across bring-up, HDR playback, and seeks.

close #2016
2026-08-19 06:07:25 +02:00
Aldo BarrerasandGitHub 8383c7b73b chore: bump go server version, run formatter & regenerate podfile lock file checksum (#1944)
* Bump go server and run formatter.

* Regenerate Podfile lock file checksum.
2026-08-15 13:44:56 +02:00
edde746 be863a0c1c fix(linux): remove the Flutter-texture fallback permanently
The display-agnostic texture renderer restored by 9cdfe759 is deleted
again, this time for good: it is a second, SDR-only rendering stack
(isolated EGL context on Flutter's display plus EGL-image handoff) kept
alive solely to host sessions that cannot bring up the Wayland plane -
X11/XWayland or a failed plane bootstrap - and it was the source of the
native lifecycle and EGL state-churn fixes of the 9f2e0507 era. Linux
video now requires a Wayland compositor; a session that cannot host the
plane fails initialization with VIDEO_PLANE_UNSUPPORTED instead of
silently rendering through the second stack.

Reverts the restore commit's machinery: mpv_texture.cc/.h and
mpv_gpu_bootstrap.cc/.h deleted, the plugin's texture-registrar,
bootstrap, and waitForVideoReady paths removed, MpvPlayer's texture-mode
render-context API dropped, and the Dart-side renderMode setting, its
settings tile, translation keys, and the Player textureId member
withdrawn. The #1874 HDR diagnostic work is unaffected.
2026-08-15 01:20:44 +02:00
edde746 fe3460ad12 fix(linux): drop the unreachable 8-bit render-context retry
The retry added while chasing the 2.13.0 hwdec regression never fires:
mpv probes hwdec interop lazily at the first decode attempt, and its
failure does not fail mpv_render_context_create, so the deep config never
gets rejected and the 8-bit tier is never reached. The actual regression
was the libmpv build losing the DRM providers, fixed in the previous
commit. Remove the dead retry and its prefer_deep plumbing, and correct
the pre-flight comment that claimed the interop probe runs at context
creation.
2026-08-14 21:49:46 +02:00
edde746 18c9f710bb style(linux): clang-format the native rendering changes 2026-08-14 19:50:28 +02:00
edde746 991184b451 fix(linux): repair native compile errors caught by the CI build
The first GitHub Actions build of the Linux path failed on six issues the
macOS host could not catch:

- HandleFrameDone is a static handler; CancelFrameAckWatchdog() needed the
  explicit self-> qualification.
- handle_texture_ready_result/handle_ready_timeout call
  release_video_resources before its definition; forward-declared.
- finish_leg captured self without using it (Werror).
- CanCommandOutputProperties was private; made public for the kUnknown
  live-core check.
- MPV_ERROR_UNKNOWN does not exist in libmpv; the timeout now reports
  MPV_ERROR_UNSUPPORTED (any non-success serves the latch; the log line
  names the reason).
- The hdr-tone-mapping error path referenced the handler's FlValue value
  inside an async lambda; an owned std::string copy is captured instead.
- The texture register-failure response used a heap string freed before the
  handler responded; use a literal.
2026-08-14 19:29:39 +02:00
edde746 9cdfe7591e feat(linux): restore the Flutter-texture path as the SDR fallback
2.13.0 deleted the display-agnostic EGL/Flutter-texture renderer and made
the native Wayland plane the only path, hard-rejecting every session that
cannot host one - X11, XWayland (SteamOS Gaming Mode runs native apps
through Gamescope's XWayland), or a plane whose EGL bootstrap failed. This
restores the 2.11.0 texture path from git history as the fallback:

- Re-add mpv_texture.cc/.h and mpv_gpu_bootstrap.cc/.h (2.11.0 verbatim):
  an FlTextureGL whose populate renders mpv into an offscreen FBO sampled
  by Flutter via an EGL image.
- MpvPlayer gains the texture-mode render-context API (InitRenderContext,
  HasRenderContext, GetEglDisplay/Context, Render(w,h,fbo)) beside the
  plane's InitRenderContextForSurface/RenderToSurface. The isolated ES 2.0
  context on Flutter's display and the X11 display param are exactly the
  2.11.0 configuration hardware decode demonstrably worked in.
- initialize now tries the plane first and falls back to the texture path
  when it cannot be brought up, returning the texture id (Dart's 2.11.0
  'result is int' contract) with waitForVideoReady gating playback until
  the GPU bootstrap settles. Both paths share one mpv core, so the
  plane/texture decision precedes render-context creation.
- hdr-enabled/hdr-tone-mapping are intercepted in texture mode (no plane,
  no HDR); the HDR toggle hides itself via isHDRSupported.
- New Linux setting 'Video rendering mode' (Automatic / Texture) forces
  the fallback - the user-visible workaround for plane-only trouble and
  for the hwdec interop regression, plus translations in all locales.

SDR only on the fallback, matching 2.11.0; the plane path is unchanged.
2026-08-14 18:16:32 +02:00
edde746 093109ae09 fix(linux): bound plane presentation against unacknowledged frames
Present() arms wl_surface.frame and frame_pending_ is cleared only by the
frame callback. Compositors are entitled to stop acknowledging frames for
occluded or minimized surfaces - wlroots-lineage compositors (Hyprland) do
exactly that - and nothing bounded the wait: one missed callback froze the
plane on its last buffer forever, because every later render bailed on
frame_pending(). That is the 2.13.0 black-video report on Hyprland: the
first commit is the pre-allocated 1x1 (or pre-video black) buffer, fully
occluded by the opaque Flutter surface, and the callback it armed never
arrives.

Two changes, one stall:

- A 500 ms frame-acknowledgement watchdog in Present(): on expiry the dead
  callback is withdrawn and a fresh present is asked for, so the plane
  re-commits instead of sitting on the latch. A miss budget (5) stops
  poking a surface the compositor is still ignoring; a real
  acknowledgement resets it.

- The very first present is refused until mpv actually has a frame: the
  first forced render happens at setVideoRect time, before anything is
  decoded, and committing that empty buffer is exactly the commit an
  occluded surface ignores. The sticky plane_needs_render flag keeps the
  owed resize refresh pending until content exists, so the first present
  still happens at the right size the moment the first frame lands.
2026-08-14 18:11:06 +02:00
edde746 9090ad6283 fix(linux): name refused property writes and surface the hwdec path
The SET_PROPERTY_FAILED error surfaced to Dart carries only mpv's own text
("unsupported format for accessing property"), which names the failure
mode, never the property. Every report of a refused write is therefore a
guessing game. Include name=value in the error description on all three
setProperty branches (generic, hdr-enabled, hdr-tone-mapping) and warn with
the same pair from MpvPlayer::SetPropertyAsync so the HDR transaction's
target-* writes — which never reach the channel — are attributable too.

mpv_request_log_messages is a single global level, and the vaapi probe and
"Using software decoding" fallback are MSGL_INFO, so at "warn" a silently
software-decoding session leaves no trace in the app log. Raise the request
level to "info" and observe hwdec-current natively, logging every decode
path transition from the player instead of relying on an overlay readout.
2026-08-14 18:07:09 +02:00
edde746 bcd6fe9906 feat(linux): HDR video on a native Wayland plane
Video on Linux went through a Flutter texture: 8-bit sRGB, which cannot carry
HDR at all, and which forced a whole-window Flutter recomposite for every video
frame. This moves it onto a wl_subsurface stacked below the Flutter surface, with
mpv rendering into an EGL window surface on it through the libmpv render API. The
subsurface is desynchronized, so video and UI now present independently.

With the plane in place HDR follows: the surface is described to the compositor
through wp_color_manager_v1 as the source's own curve and gamut - PQ or HLG,
BT.2020 - carrying whatever HDR10 static metadata the stream actually declares.
The description and the buffer it describes land on the same commit, staged and
validated before mpv is switched, so a PQ frame is never presented labelled sRGB.
A five-second watchdog bounds the one wait a compositor could otherwise leave
hanging. A session that cannot host the plane - X11, or a compositor without
wl_subcompositor - fails initialize with VIDEO_PLANE_UNSUPPORTED naming the
reason: the texture path is gone, and refusing by name beats degrading to
something the user cannot see. An SDR output, a missing capability or an 8-bit
config keep the plane and simply leave it undescribed.

The output's colour state is trusted only when it has been earned. Every landed
property step records itself as it lands; a reset or sequence that cannot
finish downgrades its result to unknown and marks the applied-output cache
untrusted until a clean apply earns it back. A plane whose output state cannot
be named is quarantined - hidden, its description withdrawn - and the
quarantine is recorded state: an unrelated visibility change cannot put a
mislabelled plane back on screen, and only a commit that resolves to a nameable
outcome lifts it. A rect collapsing to zero detaches the buffer exactly as
hiding does, a refused setVideoRect drops the Dart-side sent-rect cache so the
next layout pass retries for free, and a refused tone-mapping pick tells the
user instead of dying in a log.

NVIDIA's Wayland EGL (through at least 610.xx) offers no 10-bit unorm window
configs, so the plane takes half-float as the tier between 10-bit unorm and
8-bit, declares the whole surface opaque so the compositor never reads the
alpha those configs carry, and states GL_RGBA16F rather than a 10-bit lie.
Whether the output is in HDR is read from luminance headroom above its own
reference white rather than from the preferred transfer function, which current
KWin no longer answers PQ for; the margin is half a stop, because KWin reports
an undimmed maximum over a software-dimmed SDR white. Validated on an RTX 4090
(driver 610.57.04) under KWin 6.7.4 with locked-exposure photographs.

Who tone-maps is a user choice. The default is the compositor: photographed on a
400-nit HDR output against a PQ chart it keeps 400 -> 1000 nits monotonic and
separated where the player leg flattens them, because the player path drives
mpv's legacy vo_gpu, whose own standalone output scores the same. The gap is the
renderer, not the wiring.

The decision itself - what the source carries, what the output supports, what to
tell mpv and what to tell the compositor - lives in hdr_metadata.h, free of
Wayland and GTK so its luminance validation can be tested without a display
server. Sending an incoherent luminance set is a protocol error that disconnects
the client, so the rules are worth a unit test.

The deb, rpm and pacman packages now declare wayland-client, wayland-egl and EGL:
the plane links them directly and bundle-libs.sh deliberately never bundles them,
since they are coupled to the running compositor and GPU driver.

lib/dev/harness_main.dart is a second entrypoint for measuring this on hardware -
it drives one clip with scripted mpv properties and reports the colour state mpv
actually settled on. Nothing imports it, so it is tree-shaken out of the app.

Verified on a Steam Deck against an external 400-nit HDR display: the compositor
reports PQ / BT.2020, the connector carries HDR_OUTPUT_METADATA, and against mpv
vo=gpu-next on the same frame the shipped build sits 4.90 counts away overall -
closer to the reference HDR player than to its own SDR fallback.
2026-08-10 08:48:13 +02:00
edde746 f8f366a513 fix(native): harden player teardown and shelf recovery 2026-07-25 16:16:24 +02:00
edde746 9f2e050797 fix(native): bound cross-platform lifecycle ownership 2026-07-24 03:56:40 +02:00
edde746 e0bf66eea8 fix(runtime): harden application service boundaries 2026-07-24 03:46:46 +02:00
edde746 422db75b5b feat(music): mpv audio playback engine with gapless queue service
Audio-only mpv core on every platform (dedicated
com.plezy/mpv_audio_player channels): parameterized android/windows/
linux mpv plugins and a new apple MpvAudioPlayerCore, all skipping
video/window paths (vid=no, audio-display=no, gapless-audio=weak).
MusicPlaybackService drives an in-memory queue with shuffle/repeat,
file-loaded-event gapless arming (property edges coalesce and the
android bridge drops them), per-track progress reporting, OS media
controls, audio focus, sleep timer, and error auto-skip.
PlaybackCoordinator enforces one live native player: starting video
disposes the audio core first.
2026-07-05 19:26:28 +02:00
edde746 5010833da9 fix(mpv): avoid blocking runtime calls 2026-05-03 08:23:44 +02:00
edde746 024af35bf5 chore: add native formatting checks 2026-05-01 05:56:49 +02:00
edde746 b193a23524 fix: video stuck on still frame after long pause
close #536
2026-02-25 08:17:14 +01:00
edde746 a1a030a130 fix: create render context before file load 2026-02-24 00:07:09 +01:00
edde746 3d9c6b203f fix: isolated EGL context for mpv rendering 2026-02-23 18:20:08 +01:00
edde746 ad4b23b18b fix: mpv dispose deadlock on wayland 2026-02-19 22:32:32 +01:00
edde746 582809427e fix: linux mpv dispose deadlock on wayland 2026-02-19 21:50:29 +01:00
edde746 2bc2c0a0ec feat: use FlTextureGL for Linux mpv video rendering 2026-02-17 08:55:29 +01:00
edde746 c98add8065 fix: resolve UI freezes during video playback on Steam Deck
- Default MPV native log level to "warn" instead of "v" (Linux/Windows),
  add setLogLevel method channel to raise it when debug logging is enabled
- Coalesce MPV render requests via atomic compare_exchange on needs_redraw_
- Clear redraw flag before render so new redraws queue during current frame
2026-02-17 03:11:52 +01:00
edde746 a61fca0588 perf: compact [propId, value] wire format for property events 2026-02-16 15:40:52 +01:00
edde746 9721e6bf3f fix: async MPV commands to prevent ANR 2026-01-20 01:14:45 +01:00
edde746 562b54d1cb fix(linux): GL threading, state management, and animation fixes 2026-01-05 19:40:04 +01:00
edde746 7c6a121752 refactor: clean up 2025-12-02 17:41:06 +01:00
edde746 ae4673bde7 linux 2025-12-02 15:46:19 +01:00