feat(windows): mpv draws Windows video into the app window

DR-237's video half. mpv now renders Windows video the way
tauri-plugin-libmpv does on Windows: MpvBackend is handed the main
window's HWND and sets it as `wid` before mpv initialises, so mpv draws
as a child of the app window beneath the transparent WebView2, with
vo=gpu-next,gpu. osc, default bindings, VO keyboard and cursor handling
are off, so the Svelte controls drawn over the picture are the only ones.

- video_output() decides per platform (UT-274): Window(hwnd) on Windows,
  RenderApi on Linux, Off without native video. Windows with no handle
  draws nothing rather than letting mpv open a top-level window.
- native_video::enabled() is true on Windows as well, so the frontend
  takes the native path there: NativePlayerAdapter, and the page clears
  its background while video is on screen.
- enableNativeVideoCompositing() no longer logs a missing Android bridge
  as an error on the desktop, where there is no bridge to have.

Verified: every option, wid included, is accepted by the real libmpv on
Linux and by the shipped Windows DLL under wine; the Windows unit suite
passes under wine (949). Not yet seen on real Windows hardware.
This commit is contained in:
2026-09-24 22:42:42 -04:00
parent 4daf172834
commit bb3ab1edd7
7 changed files with 240 additions and 31 deletions
+11 -12
View File
@@ -16,31 +16,30 @@
/// Whether mpv should decode and draw video in this process.
///
/// True wherever mpv is the desktop video renderer — Linux, since DR-235
/// phase 1. There is no opt-out: the webview `<video>` path is no longer a Linux
/// video renderer, so "off" would leave nothing drawing the picture. It was the
/// `JELLYTAU_NATIVE_VIDEO` opt-in while the render path was being proven; the
/// variable is now ignored. Windows joins in DR-237, and only then does the
/// webview path go (phase 3).
/// True wherever mpv is the desktop video renderer: Linux since DR-235 phase 1,
/// Windows since DR-237. There is no opt-out and no webview fallback — the
/// webview `<video>` path is gone, so "off" would leave nothing drawing the
/// picture. It was the `JELLYTAU_NATIVE_VIDEO` opt-in while the render path was
/// being proven; the variable is ignored.
///
/// TRACES: UR-080 | DR-231, DR-235
pub fn enabled() -> bool {
// On Android ExoPlayer draws video and `use_html5_element` is false for
// entirely separate reasons.
cfg!(all(target_os = "linux", not(target_os = "android")))
cfg!(any(target_os = "linux", target_os = "windows"))
}
#[cfg(test)]
mod tests {
use super::*;
/// mpv draws video on Linux with nothing to opt into, and the retired
/// variable cannot opt back out: with the webview path gone from Linux, "off"
/// mpv draws video on Linux and Windows with nothing to opt into, and the retired
/// variable cannot opt back out: with the webview path gone, "off"
/// would configure mpv for audio only with nothing else to draw the picture.
///
/// TRACES: UR-080 | DR-235 | UT-271
/// TRACES: UR-080 | DR-235, DR-237 | UT-271
#[test]
fn linux_always_renders_video_natively() {
fn desktop_always_renders_video_natively() {
let restore = std::env::var("JELLYTAU_NATIVE_VIDEO").ok();
for value in [None, Some("0"), Some("false"), Some("1")] {
@@ -50,7 +49,7 @@ mod tests {
}
assert_eq!(
enabled(),
cfg!(all(target_os = "linux", not(target_os = "android"))),
cfg!(any(target_os = "linux", target_os = "windows")),
"JELLYTAU_NATIVE_VIDEO={value:?} must not decide the renderer"
);
}