Files
jellytau/src-tauri/src/player/native_video.rs
T
dtourolle 1677f5f299 refactor(player): delete the webview video path; mpv selects its own tracks
DR-235 phase 3. Every video renderer is native now: mpv on Linux and
Windows, ExoPlayer on Android, all drawing behind the transparent
webview. The HTML5 <video> path is gone, not bypassed:

- Frontend: hls.js, Html5PlayerAdapter and its compatibility shim, the
  createAdapter factory, streamTransport, hlsRecovery, timeTracking,
  videoFit, the <video>/<track> markup and every element handler in
  VideoPlayer (3277 -> 2144 lines), the experimentalNativeVideo store
  and its Settings toggle, webviewVideoFallback/supportsNativeVideo, and
  the setHtml5VideoState PiP bridge call. NativePlayerAdapter is the one
  video adapter; webview audio gets its own adapter kind.
- Rust: use_html5 dropped from player_seek_video,
  player_switch_audio_track and player_set_stream_quality with the
  Html5* strategies and ReloadStream responses; use_html5_element and
  VideoBackend dropped from PlayerStatus; player_play_item always loads
  the backend (set_current_item removed); Capabilities::webview removed;
  the WebKitGTK GStreamer/VAAPI setup (and its gst-inspect spawn) removed.
- Android: the HTML5 video state in PictureInPictureManager and
  ScreenWakeManager, and the bridge method feeding it.
- CSP: connect-src loses http:/https: and worker-src loses blob: -
  both existed for hls.js; with it gone they were only an exfiltration
  channel and a blob worker for injected script. A test now keeps them
  out.

mpv takes over what the <video> element did (mpv_tracks, UT-275):
subtitles are the WebVTT list the play request carries, queued on
sub-files and selected by position in that list, starting off; audio
tracks are selected by position in the file; sid/aid are reset before
each load. Without this, Linux video had no subtitle selection and a
direct-play audio switch failed since mpv became its renderer.

Verified: Rust 948 passing, and the same 948 cross-compiled for Windows
under wine against the shipped DLL (track tests included); frontend
1111 passing; aarch64 debug APK builds. Lint warnings 158 -> 146, CI
ratchet tightened to match. Not yet seen on Windows hardware.
2026-09-24 23:11:17 -04:00

62 lines
2.5 KiB
Rust

//! Whether this process renders video natively, answered once.
//!
//! Three things need this and must agree: the mpv backend (which has to be
//! configured for video *at construction*, before anything plays), the video
//! surface (which has nothing to draw otherwise), and the device profile.
//!
//! It is a function rather than three `env::var` checks for the reason this
//! codebase keeps rediscovering: a capability answered in several places is a
//! capability whose answers drift. Four separate bugs this cycle came from
//! exactly that shape — a webview's decode limits applied to ExoPlayer, a
//! transcode target contradicting a direct-play claim, a codec list hardcoded in
//! a URL builder. One source, read by everyone.
//!
//! TRACES: UR-080 | DR-231, DR-235
/// Whether mpv should decode and draw video in this process.
///
/// 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!(any(target_os = "linux", target_os = "windows"))
}
#[cfg(test)]
mod tests {
use super::*;
/// 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, DR-237 | UT-271
#[test]
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")] {
match value {
Some(v) => std::env::set_var("JELLYTAU_NATIVE_VIDEO", v),
None => std::env::remove_var("JELLYTAU_NATIVE_VIDEO"),
}
assert_eq!(
enabled(),
cfg!(any(target_os = "linux", target_os = "windows")),
"JELLYTAU_NATIVE_VIDEO={value:?} must not decide the renderer"
);
}
match restore {
Some(v) => std::env::set_var("JELLYTAU_NATIVE_VIDEO", v),
None => std::env::remove_var("JELLYTAU_NATIVE_VIDEO"),
}
}
}