Player: open again once when mpv's video output was not up yet (Windows join with media up)

Fun Maker joined on Windows while a video played: the open landed before
mpv's render context existed (media_kit reports the controller ready
first there), the video output failed and the media stayed unopened.
The host now opens the same media again once, 500 ms later.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
foxyzandClaude Opus 5.5 committed 2026-10-17 03:54:58 +03:00
1 parent 81b9d05de6
commit 5e3834e6ba
2 files changed
+25 -1

No files matched your search

@@ -203,6 +203,20 @@ class MediaKitHost implements PlayerHost {
// refused request makes ffmpeg retry and warn on every try); ffmpeg's // refused request makes ffmpeg retry and warn on every try); ffmpeg's
// HTTP status to [httpErrors]; the GL init lines while probing. // HTTP status to [httpErrors]; the GL init lines while probing.
void _route(_MkPlayer p, PlayerLogLine log) { void _route(_MkPlayer p, PlayerLogLine log) {
// Windows: the controller can be "ready" before mpv's render context
// exists, and an open in that gap fails its video output ("No render
// context set"). Open the same media again once, a moment later.
if (log.prefix == 'cplayer' && log.text.contains('initializing the selected video_out')) {
final last = p._lastOpen;
if (last != null && !p._voRetried && !p._retired) {
p._voRetried = true;
_mpvLog.info('render: the video output was not up for the open; opening it again');
unawaited(Future.delayed(const Duration(milliseconds: 500), () async {
if (p._retired || !identical(p._lastOpen, last)) return;
await p.mk.open(Media(last.url, httpHeaders: last.headers), play: last.play);
}).catchError((Object e) => _mpvLog.warning('render: opening again failed: $e')));
}
}
if (log.prefix == 'ffmpeg') { if (log.prefix == 'ffmpeg') {
final http = RegExp(r'HTTP error \d{3}.*').firstMatch(log.text); final http = RegExp(r'HTTP error \d{3}.*').firstMatch(log.text);
if (http != null) _http.add(http[0]!.trim()); if (http != null) _http.add(http[0]!.trim());
@@ -390,6 +404,9 @@ class _MkPlayer implements HostedPlayer {
bool _probing = false; bool _probing = false;
bool _retired = false; bool _retired = false;
Future<void>? _videoReady; // set once a video output is attached Future<void>? _videoReady; // set once a video output is attached
// The last open, for one retry when mpv's video output was not up yet.
({String url, Map<String, String> headers, bool play})? _lastOpen;
bool _voRetried = false;
dynamic get _mpv => mk.platform; dynamic get _mpv => mk.platform;
@@ -437,6 +454,8 @@ class _MkPlayer implements HostedPlayer {
@override @override
Future<void> open(String url, {Map<String, String> headers = const {}, bool play = false}) async { Future<void> open(String url, {Map<String, String> headers = const {}, bool play = false}) async {
if (_videoReady case final ready?) await ready; if (_videoReady case final ready?) await ready;
_lastOpen = (url: url, headers: headers, play: play);
_voRetried = false;
// An empty map, not null: media_kit caches headers per URI. // An empty map, not null: media_kit caches headers per URI.
await mk.open(Media(url, httpHeaders: headers), play: play); await mk.open(Media(url, httpHeaders: headers), play: play);
} }
+6 -1
View File
@@ -554,7 +554,12 @@ 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 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 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 context set", black picture with sound). On X11 the context comes up
later, which widens that gap (joining with media already up). later, which widens that gap (joining with media already up). On Windows
the controller can report ready before mpv's render context exists, so
an open that still fails its video output that way (`cplayer`: "Error
opening/initializing the selected video_out") is opened again once,
500 ms later (`render: the video output was not up for the open`); the
player error it raised clears when the media loads.
Render mode: media_kit's Linux/Windows video output creates mpv's render Render mode: media_kit's Linux/Windows video output creates mpv's render
context (OpenGL, else its software renderer) when the `VideoController` is context (OpenGL, else its software renderer) when the `VideoController` is