Each of these was invisible while Linux video played in the webview, and each became reachable the moment mpv started rendering. DR-238 — a transcoded seek re-negotiates the stream on every renderer, not just the webview. `determine_video_seek_strategy` treated `is_hls` as a proxy for "seekable in place", which held only because hls.js was always the HLS renderer: it seeks within the VOD playlist it is handed and lets the server catch up. mpv's HLS demuxer cannot make Jellyfin transcode from a new offset, so with native video on, every transcoded seek became a backend seek that silently did nothing. One cell of the truth table changes; all four webview cells are byte-identical. DR-239 — properties the mpv event loop handles are now observed. libmpv delivers PropertyChange only for properties registered with observe_property, so the `pause` arm was unreachable code that read as implemented: StateChanged was never emitted and the play/pause control never moved. UT-218 asserts the two lists agree, so the class cannot recur. DR-240 — fullscreen moves whatever owns the pixels. requestFullscreen() fullscreens the *document*, which sufficed while the <video> element lived inside it and WebKit scaled it. A native surface is drawn behind the webview at window size, so a document-only fullscreen expanded the page and left the picture at its old size — on WebKitGTK, a maximised window with decorations still holding a strip of the screen. Measured on a 3440x1440 panel: 1361 tall before, 1440 after. DR-241 — a seek issued before mpv has a file to seek in is honoured rather than dropped. loadfile returns as soon as the command is queued, so `time-pos` does not resolve yet and setting it fails. The two callers that always hit that window are resume and a transcoded seek, both of which re-open the stream and then ask for a position; the failed seek was discarded and playback began at zero. Also adds the instrumentation that made the diagnosis possible rather than speculative: an entry log on player_stop, a render-size log that re-fires on change instead of latching once, and decoded-vs-display video geometry on file load. The last of those retired a wrong theory — a picture that does not fill an ultrawide turned out to be a 16:9 source with its letterbox baked in, not a rendering fault.
36 lines
1.5 KiB
TypeScript
36 lines
1.5 KiB
TypeScript
/**
|
|
* Which surfaces a fullscreen toggle has to move.
|
|
*
|
|
* `requestFullscreen()` only ever fullscreens the *document*. That was
|
|
* sufficient while every renderer lived inside it: the HTML5 `<video>` element
|
|
* is part of the document, so WebKit scaled it to the screen and the OS
|
|
* window's real size never mattered.
|
|
*
|
|
* A native video surface is drawn *behind* the webview at **window** size, so a
|
|
* document-only fullscreen leaves the picture exactly where it was while the
|
|
* page around it goes fullscreen. On WebKitGTK the observed result is a
|
|
* maximised window with decorations still taking a strip of the screen — the
|
|
* video renders correctly, at the wrong size, which reads as "fullscreen is
|
|
* broken" rather than as a windowing problem.
|
|
*
|
|
* Android already needed its own answer here for the system bars (DR-157); this
|
|
* is the desktop equivalent of the same rule: whoever actually owns the pixels
|
|
* has to be the thing that goes fullscreen.
|
|
*
|
|
* TRACES: UR-066 | DR-240 | UT-219
|
|
*/
|
|
export interface FullscreenPlan {
|
|
/** Ask the document to go fullscreen (harmless everywhere, needed for CSS). */
|
|
document: boolean;
|
|
/** Resize the OS window itself. Required when a native surface owns the picture. */
|
|
osWindow: boolean;
|
|
}
|
|
|
|
/**
|
|
* @param rendersNatively true when a native surface (mpv/ExoPlayer) draws the
|
|
* picture rather than an in-document `<video>` element.
|
|
*/
|
|
export function planFullscreen(rendersNatively: boolean): FullscreenPlan {
|
|
return { document: true, osWindow: rendersNatively };
|
|
}
|