Skip to main content

mpv_engine/
lib.rs

1//! # mpv-engine
2//!
3//! Toolkit-agnostic core for embedding libmpv: handle lifecycle, commands,
4//! properties, typed playback events, and render seams. Extracted from two
5//! independent embedders — a GTK4 app (GLArea direct-to-FBO) and an iced
6//! widget (side-context + readback/GPU export) — after their engine layers
7//! converged on the same shape.
8//!
9//! What belongs here is decided by one rule: **a quirk lives in this crate
10//! if its consumer-facing interface survives the upstream fix**; anything
11//! whose shape would change with a toolkit's API belongs in that toolkit's
12//! adapter crate. See README for the seam map and roadmap.
13//!
14//! The playback surface covers what a player UI consumes: transport
15//! (load — immediate, paused, or deferred until a render context
16//! attaches ([`Engine::load_when_ready`]) — pause/seek/stop), the mixer
17//! set (volume/mute/speed), typed
18//! lifecycle events ([`PlaybackEvent`] — including seek-completion for
19//! scrubber snap and end reasons for playlist logic), and push-based
20//! property observation ([`Engine::observe`]) for state that polling
21//! can't track well (duration becoming known, external pause flips, buffering,
22//! video dimensions). Everything else goes through the property/command
23//! escape hatches — which speak crate-owned types ([`PropertyValue`],
24//! the sealed [`PropertyGet`]), so the underlying binding's traits never
25//! enter this crate's public API.
26//!
27//! Two render backends share one attach slot: OpenGL
28//! ([`Engine::attach_gl_render`] / [`Engine::render_gl`]) and software
29//! ([`Engine::attach_sw_render`] / [`Engine::render_sw`], RGBA into a
30//! caller buffer, no GL anywhere). [`Engine::attached_render`] reports
31//! which one is live ([`RenderKind`]), and the render-update callback
32//! fixed at attach can be replaced afterwards
33//! ([`Engine::set_render_update_callback`]) for shells whose real
34//! closure only exists once the engine is shared. GL attach takes
35//! [`GlRenderOptions`]
36//! to fix the shell's render-loop discipline: whether `render_gl` blocks
37//! until the frame's target time (right for a toolkit paint handler,
38//! wrong on a compositor thread), and mpv's advanced control (which
39//! obligates [`Engine::render_update`] after every update callback). Event delivery is pull-based
40//! ([`Engine::pump_events`]) with an optional push signal
41//! ([`Engine::set_wakeup_callback`]) for shells that don't want a
42//! polling timer.
43//!
44//! Quirks this crate owns so consumers don't have to rediscover them:
45//! - `LC_NUMERIC=C` forced before `mpv_create` (toolkits setlocale behind
46//!   your back; mpv's number parsing breaks under comma-decimal locales).
47//! - Render context freed strictly before the mpv handle — structural
48//!   since rsmpv 0.2 (the context co-owns the core) — and, for OpenGL,
49//!   only with the GL context current: an obligation
50//!   [`Engine::attach_gl_render`] carries as its `unsafe` contract (see
51//!   [`Engine::detach_render`]).
52//! - Commands pass pre-tokenized argument arrays (`mpv_command`), so paths
53//!   with spaces/quotes need no escaping — pinned by a regression test.
54//! - Errored end-of-file surfaces as a typed
55//!   [`PlaybackEvent::Failed`] carrying the raw `mpv_error` code (for
56//!   integrators mapping to their own error copy) and a diagnostic
57//!   message (mpv's `mpv_error_string` text plus the numeric code).
58//! - The update callback's threading contract (mpv render thread, plus one
59//!   synchronous call at registration) is documented at the seam.
60//!
61//! No toolkit dependencies, no git dependencies, no main-loop opinions:
62//! events are *pumped*, and the update callback is `Send + Sync` —
63//! bridging to a main loop is the shell's job, because that part is
64//! toolkit-shaped.
65
66#![warn(missing_docs)]
67
68mod engine;
69mod error;
70mod render;
71
72pub use engine::{
73    EndReason, Engine, EngineBuilder, ObserveId, PlaybackEvent, PropertyFormat, PropertyGet,
74    PropertyValue,
75};
76pub use error::{Error, Result};
77pub use render::{GlRenderOptions, ProcAddressFn, RenderKind};