Open media only once the video output is up (black video on X11 when joining mid-play)
ci / core (push) Successful in 33s
ci / server (push) Successful in 52s
ci / updater-windows (push) Failing after 7m48s

media_kit sets vo=libmpv before the render context exists; an open in
between failed mpv's video output ("No render context set") and played
black with sound. Seen on X11 joining a server with media already up.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
foxyzandClaude Opus 5.5 committed 2026-10-16 03:32:45 +03:00
1 parent 741b258ac1
commit 9bbc594048
2 files changed
+20 -3

No files matched your search

@@ -185,6 +185,14 @@ class MediaKitHost implements PlayerHost {
// configured), which used to override SYNC_RELAY_HWDEC.
final controller = VideoController(p.mk, configuration: VideoControllerConfiguration(hwdec: hwdec));
final v = _MkVideo(p, controller);
// mpv gets `vo=libmpv` before the output's render context exists; a
// media opened in between fails its video output ("No render context
// set") and plays black. Opens wait for the output (seen on X11, where
// the context comes up later, when joining with media already up).
p._videoReady = controller.platform.future
.then((_) {})
.timeout(const Duration(seconds: 5), onTimeout: () {})
.catchError((Object _) {});
if (probe) unawaited(_probeRender(p, v));
return v;
}
@@ -381,6 +389,7 @@ class _MkPlayer implements HostedPlayer {
StreamSubscription<int?>? _firstFrame;
bool _probing = false;
bool _retired = false;
Future<void>? _videoReady; // set once a video output is attached
dynamic get _mpv => mk.platform;
@@ -426,9 +435,11 @@ class _MkPlayer implements HostedPlayer {
set onUserSeek(void Function(Duration position)? f) => mk.onUserSeek = f;
@override
Future<void> open(String url, {Map<String, String> headers = const {}, bool play = false}) =>
// An empty map, not null: media_kit caches headers per URI.
mk.open(Media(url, httpHeaders: headers), play: play);
Future<void> open(String url, {Map<String, String> headers = const {}, bool play = false}) async {
if (_videoReady case final ready?) await ready;
// An empty map, not null: media_kit caches headers per URI.
await mk.open(Media(url, httpHeaders: headers), play: play);
}
@override
Future<void> play() => mk.play();
+6
View File
@@ -550,6 +550,12 @@ set (M + S). A missing file, a path containing the list separator, a
read-back mismatch, or an mpv `libmpv_render` error while shaders are on
turns shaders off (saved) with a toast.
A player with a video output opens media only once that output is up:
media_kit sets mpv's `vo=libmpv` before the output's render context
exists, and a media opened in between gets no video output ("No render
context set", black picture with sound). On X11 the context comes up
later, which widens that gap (joining with media already up).
Render mode: media_kit's Linux/Windows video output creates mpv's render
context (OpenGL, else its software renderer) when the `VideoController` is
created, and nothing in its API says which. The host therefore requests