diff --git a/apps/desktop/lib/src/platform/desktop/media_kit_host.dart b/apps/desktop/lib/src/platform/desktop/media_kit_host.dart index df163ab..e8d0419 100644 --- a/apps/desktop/lib/src/platform/desktop/media_kit_host.dart +++ b/apps/desktop/lib/src/platform/desktop/media_kit_host.dart @@ -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? _firstFrame; bool _probing = false; bool _retired = false; + Future? _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 open(String url, {Map 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 open(String url, {Map 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 play() => mk.play(); diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index a35fb2a..668ff77 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -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