audrey/src/mpv.rs

206 lines
5.7 KiB
Rust
Raw Normal View History

2024-10-30 07:41:17 +00:00
mod ffi;
2024-11-02 14:43:43 +00:00
use std::ffi::{c_int, c_void, CStr, CString};
2024-10-30 07:44:25 +00:00
#[link(name = "mpv")]
extern "C" {}
2024-10-30 07:41:17 +00:00
2024-11-02 14:43:43 +00:00
pub struct Error(c_int);
2024-10-30 07:41:17 +00:00
impl Error {
2024-11-02 14:43:43 +00:00
fn from_return_code(rc: c_int) -> Result<(), Self> {
2024-10-30 07:41:17 +00:00
if rc == 0 {
Ok(())
} else {
Err(Self(rc))
}
}
}
2024-11-02 15:21:13 +00:00
use std::fmt;
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
fmt::Display::fmt(
2024-11-02 16:05:26 +00:00
unsafe { CStr::from_ptr(ffi::mpv_error_string(self.0 as c_int)) }
2024-11-02 15:21:13 +00:00
.to_str()
.unwrap(),
f,
)
}
}
impl fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
2024-10-30 07:41:17 +00:00
f.debug_tuple("Error")
2024-11-02 15:21:13 +00:00
.field(
2024-11-02 16:05:26 +00:00
&unsafe { CStr::from_ptr(ffi::mpv_error_string(self.0 as c_int)) }
2024-11-02 15:21:13 +00:00
.to_str()
.unwrap(),
)
2024-10-30 07:41:17 +00:00
.finish()
}
}
2024-11-02 15:21:13 +00:00
impl std::error::Error for Error {}
2024-11-02 16:05:26 +00:00
use event_listener::{Event, IntoNotification};
2024-11-02 16:29:53 +00:00
use std::cell::RefCell;
2024-11-02 14:43:43 +00:00
use std::pin::Pin;
2024-10-30 07:41:17 +00:00
use std::ptr::NonNull;
2024-11-02 14:43:43 +00:00
pub struct Handle {
inner: NonNull<ffi::mpv_handle>,
2024-11-02 15:50:10 +00:00
wakeup: Pin<Box<Event>>, // the wakeup callback holds a pointer to this
2024-11-02 16:29:53 +00:00
wait_event_cell: RefCell<()>,
2024-11-02 14:43:43 +00:00
}
// The client API is generally fully thread-safe, unless otherwise noted.
2024-11-02 15:22:57 +00:00
//unsafe impl Send for Handle {}
//unsafe impl Sync for Handle {}
// ........but we'd rather keep this in a single thread to play better with gtk
2024-11-02 14:43:43 +00:00
impl Default for Handle {
fn default() -> Self {
2024-11-02 15:50:10 +00:00
Self::new()
2024-11-02 14:43:43 +00:00
}
}
2024-10-30 07:41:17 +00:00
impl Handle {
2024-11-02 15:50:10 +00:00
pub fn new() -> Self {
2024-11-02 14:43:43 +00:00
let inner =
NonNull::new(unsafe { ffi::mpv_create() }).expect("could not create mpv handle");
2024-11-02 15:50:10 +00:00
let wakeup = Box::pin(Event::new());
2024-11-02 14:43:43 +00:00
extern "C" fn wakeup_callback(d: *mut c_void) {
2024-11-02 15:50:10 +00:00
let d = d as *const Event;
let wakeup = unsafe { &*d };
wakeup.notify(1_u32.relaxed()); // mpv has its own synchronization, trust it
2024-11-02 14:43:43 +00:00
}
unsafe {
ffi::mpv_set_wakeup_callback(
inner.as_ptr(),
Some(wakeup_callback),
2024-11-02 15:50:10 +00:00
std::ptr::from_ref::<Event>(&wakeup) as *mut c_void,
2024-11-02 14:43:43 +00:00
);
}
2024-11-02 15:50:10 +00:00
// TODO: maybe we need to set something before initialization, but idk
// also wed need a builder, since "Note that you should avoid doing concurrent accesses on the uninitialized client handle."
2024-11-02 16:05:26 +00:00
Error::from_return_code(unsafe { ffi::mpv_initialize(inner.as_ptr()) })
.expect("could not initialize mpv handle");
2024-11-02 14:43:43 +00:00
2024-11-02 16:29:53 +00:00
Self {
inner,
wakeup,
wait_event_cell: RefCell::new(()),
}
2024-10-30 07:41:17 +00:00
}
2024-11-02 16:05:26 +00:00
pub fn set_property(&self, name: &str, value: impl FormatValue) -> Result<(), Error> {
2024-11-02 14:43:43 +00:00
// need to add zero terminator
let name = CString::new(name).expect("null bytes in property name");
value.into_data(|format, data| {
Error::from_return_code(unsafe {
ffi::mpv_set_property(self.inner.as_ptr(), name.as_ptr(), format, data)
})
})
}
2024-11-02 16:05:26 +00:00
fn drain_event_queue(&self) {
2024-11-02 14:43:43 +00:00
loop {
2024-11-02 16:29:53 +00:00
let borrowed = self.wait_event_cell.borrow_mut();
2024-11-02 14:43:43 +00:00
let event = unsafe { &*ffi::mpv_wait_event(self.inner.as_ptr(), 0.0) };
2024-11-02 16:29:53 +00:00
2024-11-02 14:43:43 +00:00
match event.event_id {
ffi::mpv_event_id_MPV_EVENT_NONE => break,
11 => { /* deprecated, ignore */ }
_ => todo!("event {}", event.event_id),
2024-10-30 07:41:17 +00:00
}
2024-11-02 16:29:53 +00:00
drop(borrowed); // make sure the borrow is held until here
2024-10-30 07:41:17 +00:00
}
2024-11-02 16:05:26 +00:00
}
2024-11-02 15:50:10 +00:00
2024-11-02 16:29:53 +00:00
pub fn tick(&self) -> impl std::future::Future<Output = ()> {
2024-11-02 16:05:26 +00:00
// take listener before we drain the event queue, so we don't miss any notifications
let listener = self.wakeup.listen();
self.drain_event_queue();
2024-11-02 16:29:53 +00:00
listener
2024-10-30 07:41:17 +00:00
}
}
2024-11-02 14:43:43 +00:00
impl Drop for Handle {
fn drop(&mut self) {
// destroy? terminate_destroy??
todo!()
}
2024-10-30 07:41:17 +00:00
}
2024-11-02 14:43:43 +00:00
pub trait FormatValue: Sized {
const FORMAT: ffi::mpv_format;
fn into_data<T>(self, f: impl FnOnce(ffi::mpv_format, *mut c_void) -> T) -> T;
fn from_data<T>(
format: ffi::mpv_format,
data: *mut c_void,
f: impl FnOnce(Option<Self>) -> T,
) -> T;
2024-10-30 07:41:17 +00:00
}
2024-11-02 14:43:43 +00:00
impl<'a> FormatValue for &'a str {
const FORMAT: ffi::mpv_format = ffi::mpv_format_MPV_FORMAT_STRING;
2024-10-30 07:41:17 +00:00
2024-11-02 14:43:43 +00:00
fn into_data<T>(self, f: impl FnOnce(ffi::mpv_format, *mut c_void) -> T) -> T {
let str = CString::new(self).expect("null bytes in string");
let str_ptr = str.as_ptr();
f(Self::FORMAT, (&str_ptr) as *const _ as *mut c_void)
}
2024-10-30 07:41:17 +00:00
2024-11-02 14:43:43 +00:00
fn from_data<T>(
_format: ffi::mpv_format,
_data: *mut c_void,
_f: impl FnOnce(Option<Self>) -> T,
) -> T {
todo!()
}
2024-10-30 07:41:17 +00:00
}
2024-11-02 14:43:43 +00:00
impl FormatValue for bool {
const FORMAT: ffi::mpv_format = ffi::mpv_format_MPV_FORMAT_FLAG;
2024-10-30 07:41:17 +00:00
2024-11-02 14:43:43 +00:00
fn into_data<T>(self, f: impl FnOnce(ffi::mpv_format, *mut c_void) -> T) -> T {
let flag: c_int = if self { 1 } else { 0 };
f(Self::FORMAT, (&flag) as *const c_int as *mut c_void)
}
2024-10-30 07:41:17 +00:00
2024-11-02 14:43:43 +00:00
fn from_data<T>(
_format: ffi::mpv_format,
_data: *mut c_void,
_f: impl FnOnce(Option<Self>) -> T,
) -> T {
todo!()
}
2024-10-30 07:41:17 +00:00
}
2024-11-02 14:43:43 +00:00
impl FormatValue for f64 {
const FORMAT: ffi::mpv_format = ffi::mpv_format_MPV_FORMAT_DOUBLE;
fn into_data<T>(self, f: impl FnOnce(ffi::mpv_format, *mut c_void) -> T) -> T {
f(Self::FORMAT, (&self) as *const f64 as *mut c_void)
}
fn from_data<T>(
format: ffi::mpv_format,
data: *mut c_void,
f: impl FnOnce(Option<Self>) -> T,
) -> T {
match format {
ffi::mpv_format_MPV_FORMAT_NONE => f(None),
ffi::mpv_format_MPV_FORMAT_DOUBLE => f(Some(unsafe { *(data as *mut f64) })),
_ => panic!(),
}
2024-10-30 07:41:17 +00:00
}
}