From 9b057a0030a3c648268ce5f4aa2d3239a486007b Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 5 May 2026 07:59:26 +0000 Subject: [PATCH] Bump libmpv2 crate from 4.1.0 to 5.0.3 The 4.x -> 5.x release folded `EventContext` into `Mpv` and made `wait_event` take `&mut self`, so the previous design (a single `Arc` shared between the message and event threads, with the event thread constructing its own `EventContext` from `mpv.ctx`) no longer compiles. Migration: - Build the main `Mpv` (with `wid`, `title`, etc.) and use it from the message thread for commands and `set_property`. - `create_client(None)` a sub-client `Mpv`, owned by the event thread, which calls `disable_deprecated_events`/`observe_property`/`wait_event` on itself. Global events (`EndFile`, `Shutdown`) and property changes observed by this client land in its event queue. - Replace the old `MpvExt::wake_up` (which woke the main `Mpv`) with an `EventClientWakeup` holding the sub-client's `mpv_handle` pointer, so the message thread can interrupt the event thread's blocking `wait_event` after pushing a new observe request onto the channel. Also removed the `PropertyData::Node(_)` match arm in `communication.rs`: 5.0.0 dropped `mpv_node` support, so the variant no longer exists and the match is exhaustive without it. https://claude.ai/code/session_01CuGHFREBZFkf8tfaiRV4K6 --- Cargo.lock | 6 +-- Cargo.toml | 2 +- .../stremio_player/communication.rs | 1 - src/stremio_app/stremio_player/player.rs | 52 +++++++++++-------- 4 files changed, 34 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d322459..1ba1a01 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -880,9 +880,9 @@ checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a" [[package]] name = "libmpv2" -version = "4.1.0" +version = "5.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e0c3802b4bb1a18adbf5659b078ce24cb8e16c79ff695557f4e10af2a44722a" +checksum = "88dc8432d3de09ed6e343488d6b208467db6801fb41971a1f726fa2248302fe5" dependencies = [ "libmpv2-sys", ] @@ -1598,7 +1598,7 @@ dependencies = [ [[package]] name = "stremio-shell-ng" -version = "5.0.20" +version = "5.0.21" dependencies = [ "anyhow", "bitflags 2.4.2", diff --git a/Cargo.toml b/Cargo.toml index 2321a28..26a46ba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ winapi = { version = "0.3.9", features = [ ] } webview2 = "0.1.4" webview2-sys = "0.1.1" -libmpv2 = "4.1.0" +libmpv2 = "5.0.3" libmpv2-sys = "4.0.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/src/stremio_app/stremio_player/communication.rs b/src/stremio_app/stremio_player/communication.rs index 9c5d90a..02204d7 100644 --- a/src/stremio_app/stremio_player/communication.rs +++ b/src/stremio_app/stremio_player/communication.rs @@ -30,7 +30,6 @@ impl PlayerProprChange { serde_json::Value::String(s.to_string()) } } - PropertyData::Node(_) => unimplemented!("`PropertyData::Node` is not supported"), } } pub fn from_name_value(name: String, value: PropertyData) -> Self { diff --git a/src/stremio_app/stremio_player/player.rs b/src/stremio_app/stremio_player/player.rs index 06501b5..ee234cd 100644 --- a/src/stremio_app/stremio_player/player.rs +++ b/src/stremio_app/stremio_player/player.rs @@ -1,9 +1,10 @@ use crate::stremio_app::ipc; use crate::stremio_app::RPCResponse; use flume::{Receiver, Sender}; -use libmpv2::{events::Event, events::EventContext, Format, Mpv, SetData}; +use libmpv2::{events::Event, Format, Mpv, SetData}; use native_windows_gui::{self as nwg, PartialUi}; use std::{ + ptr::NonNull, sync::Arc, thread::{self, JoinHandle}, }; @@ -19,6 +20,18 @@ struct ObserveProperty { format: Format, } +// Wakes up the event thread blocked in `mpv_wait_event` on the sub-client. +// `mpv_wakeup` is documented as safe to call from any thread. +#[derive(Clone, Copy)] +struct EventClientWakeup(NonNull); +unsafe impl Send for EventClientWakeup {} +unsafe impl Sync for EventClientWakeup {} +impl EventClientWakeup { + fn wake_up(&self) { + unsafe { libmpv2_sys::mpv_wakeup(self.0.as_ptr()) } + } +} + #[derive(Default)] pub struct Player { pub channel: ipc::Channel, @@ -43,21 +56,26 @@ impl PartialUi for Player { let (observe_property_sender, observe_property_receiver) = flume::unbounded(); data.channel = ipc::Channel::new(Some((in_msg_sender, rpc_response_receiver))); - let mpv = create_shareable_mpv(window_handle); + let mpv = Arc::new(create_mpv(window_handle)); + let mpv_event_client = mpv + .create_client(None) + .expect("cannot create MPV event client"); + let event_wakeup = EventClientWakeup(mpv_event_client.ctx); let _event_thread = create_event_thread( - Arc::clone(&mpv), + mpv_event_client, observe_property_receiver, rpc_response_sender, ); - let _message_thread = create_message_thread(mpv, observe_property_sender, in_msg_receiver); + let _message_thread = + create_message_thread(mpv, event_wakeup, observe_property_sender, in_msg_receiver); // @TODO implement a mechanism to stop threads on `Player` drop if needed Ok(()) } } -fn create_shareable_mpv(window_handle: HWND) -> Arc { +fn create_mpv(window_handle: HWND) -> Mpv { let mpv = Mpv::with_initializer(|initializer| { macro_rules! set_property { ($name:literal, $value:expr) => { @@ -79,17 +97,16 @@ fn create_shareable_mpv(window_handle: HWND) -> Arc { // set_property!("vo", "gpu-next,"); Ok(()) }); - Arc::new(mpv.expect("cannot build MPV")) + mpv.expect("cannot build MPV") } fn create_event_thread( - mpv: Arc, + mut mpv_event_client: Mpv, observe_property_receiver: Receiver, rpc_response_sender: Sender, ) -> JoinHandle<()> { thread::spawn(move || { - let mut event_context = EventContext::new(mpv.ctx); - event_context + mpv_event_client .disable_deprecated_events() .expect("failed to disable deprecated MPV events"); @@ -97,13 +114,13 @@ fn create_event_thread( loop { for ObserveProperty { name, format } in observe_property_receiver.drain() { - event_context + mpv_event_client .observe_property(&name, format, 0) .expect("failed to observer MPV property"); } // -1.0 means to block and wait for an event. - let event = match event_context.wait_event(-1.) { + let event = match mpv_event_client.wait_event(-1.) { Some(Ok(event)) => event, Some(Err(error)) => { eprintln!("Event errored: {error:?}"); @@ -141,6 +158,7 @@ fn create_event_thread( fn create_message_thread( mpv: Arc, + event_wakeup: EventClientWakeup, observe_property_sender: Sender, in_msg_receiver: Receiver, ) -> JoinHandle<()> { @@ -151,7 +169,7 @@ fn create_message_thread( observe_property_sender .send(ObserveProperty { name, format }) .expect("cannot send ObserveProperty"); - mpv.wake_up(); + event_wakeup.wake_up(); }; let send_command = |cmd: CmdVal| { @@ -252,13 +270,3 @@ fn create_message_thread( }) } -trait MpvExt { - fn wake_up(&self); -} - -impl MpvExt for Mpv { - // @TODO create a PR to the `libmpv` crate and then remove `libmpv-sys` from Cargo.toml? - fn wake_up(&self) { - unsafe { libmpv2_sys::mpv_wakeup(self.ctx.as_ptr()) } - } -}