From 2c5b15960530f6545be21da3a0ccbd22cc77cbe2 Mon Sep 17 00:00:00 2001 From: KhooLy <73142442+KhooLy@users.noreply.github.com> Date: Mon, 13 Jul 2026 02:24:24 +0300 Subject: [PATCH] fix(player): wait for rendered video before handoff --- src-tauri/src/mpv_render.rs | 18 ++++--- src/App.tsx | 19 +++++++ src/components/ReactPlayerOverlay.tsx | 18 +++++-- src/components/detail/EpisodePanel.tsx | 3 ++ src/components/detail/ModernDetailLayout.tsx | 7 +-- src/components/detail/SourcePanel.tsx | 15 ++++++ src/hooks/usePlayer.ts | 57 +++++++++++++++----- src/hooks/usePlayerNativeEvents.ts | 16 +++--- src/screens/DetailScreen.tsx | 11 ++-- 9 files changed, 129 insertions(+), 35 deletions(-) diff --git a/src-tauri/src/mpv_render.rs b/src-tauri/src/mpv_render.rs index 1fbef5d..19e2b24 100644 --- a/src-tauri/src/mpv_render.rs +++ b/src-tauri/src/mpv_render.rs @@ -30,6 +30,7 @@ const MPV_RENDER_PARAM_SW_SIZE: c_int = 17; const MPV_RENDER_PARAM_SW_FORMAT: c_int = 18; const MPV_RENDER_PARAM_SW_STRIDE: c_int = 19; const MPV_RENDER_PARAM_SW_POINTER: c_int = 20; +const MPV_RENDER_UPDATE_FRAME: u64 = 1 << 0; const MPV_EVENT_NONE: c_int = 0; const MPV_EVENT_LOG_MESSAGE: c_int = 2; @@ -405,6 +406,8 @@ impl MpvRenderer { renderer.set_option("terminal", "no")?; renderer.set_option("config", "no")?; renderer.set_option("vo", "libmpv")?; + #[cfg(target_os = "windows")] + renderer.set_option("gpu-api", "opengl")?; renderer.set_option("idle", "yes")?; renderer.set_option("keep-open", "yes")?; if let Err(error) = renderer.set_option("osc", "no") { @@ -433,7 +436,6 @@ impl MpvRenderer { renderer.set_option("cache-secs", "30")?; renderer.set_option("demuxer-max-bytes", "150MiB")?; renderer.set_option("demuxer-readahead-secs", "10")?; - renderer.set_option("ytdl", "no")?; // Lower audio latency and proper app name for PulseAudio/PipeWire renderer.set_option("audio-buffer", "0.2")?; @@ -652,7 +654,7 @@ impl MpvRenderer { let height = height.clamp(2, 1080); self.ensure_buffer(width, height); - unsafe { (self.api.mpv_render_context_update)(self.render_context) }; + let update_flags = unsafe { (self.api.mpv_render_context_update)(self.render_context) }; let mut size = [width, height]; let format = CString::new("rgb0").unwrap(); @@ -694,7 +696,9 @@ impl MpvRenderer { *alpha = 255; } - self.frames_rendered = self.frames_rendered.saturating_add(1); + if update_flags & MPV_RENDER_UPDATE_FRAME != 0 { + self.frames_rendered = self.frames_rendered.saturating_add(1); + } Ok(PlayerFrame { width, @@ -719,7 +723,7 @@ impl MpvRenderer { self.create_opengl_context()?; } - unsafe { (self.api.mpv_render_context_update)(self.render_context) }; + let update_flags = unsafe { (self.api.mpv_render_context_update)(self.render_context) }; // Linux/GTK: query the offscreen FBO that GTK's GLArea binds. // Windows/macOS: render into the default framebuffer (FBO 0). @@ -759,7 +763,9 @@ impl MpvRenderer { self.api.error_string(result) )); } - self.frames_rendered = self.frames_rendered.saturating_add(1); + if update_flags & MPV_RENDER_UPDATE_FRAME != 0 { + self.frames_rendered = self.frames_rendered.saturating_add(1); + } Ok(()) } @@ -909,7 +915,7 @@ impl MpvRenderer { } } MPV_EVENT_COMMAND_REPLY if event.error < 0 => { - log::warn!( + log::debug!( "mpv async command failed: {}", self.api.error_string(event.error) ); diff --git a/src/App.tsx b/src/App.tsx index 61ae964..eebba7d 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -102,6 +102,7 @@ export default function App() { const [detailInitialEpisode, setDetailInitialEpisode] = useState