audrey/src/mpv.rs

203 lines
5.4 KiB
Rust
Raw Normal View History

2024-10-30 07:41:17 +00:00
#[allow(dead_code)]
#[allow(non_camel_case_types)]
#[allow(non_upper_case_globals)]
#[allow(unreachable_code)]
mod ffi;
#[link(name = "mpv")] extern "C" {}
pub struct Error(std::ffi::c_int);
impl Error {
fn from_return_code(rc: std::ffi::c_int) -> Result<(), Self> {
if rc == 0 {
Ok(())
} else {
Err(Self(rc))
}
}
}
impl std::fmt::Debug for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
f.debug_tuple("Error")
.field(unsafe {
&std::ffi::CStr::from_ptr(ffi::mpv_error_string(self.0 as std::ffi::c_int))
})
.finish()
}
}
use std::borrow::Cow;
use std::ptr::NonNull;
pub struct Handle(NonNull<ffi::mpv_handle>);
impl Handle {
pub fn create() -> Self {
Self(NonNull::new(unsafe { ffi::mpv_create() }).expect("could not create mpv handle"))
}
pub fn initialize(&self) -> Result<(), Error> {
Error::from_return_code(unsafe { ffi::mpv_initialize(self.0.as_ptr()) })
}
pub fn wait_event<'a>(&'a mut self, timeout: f64) -> Option<Event<'a>> {
let event = unsafe { &*ffi::mpv_wait_event(self.0.as_ptr(), timeout) };
match event.event_id {
0 => None,
1 => Some(Event::Shutdown),
2 => todo!("Event::LogMessage"),
3 => Some(Event::GetPropertyReply(
event.reply_userdata,
Error::from_return_code(event.error).map(|()| {
let data = unsafe { &*(event.data as *mut ffi::mpv_event_property) };
EventProperty {
name: unsafe { std::ffi::CStr::from_ptr(data.name) }
.to_str()
.unwrap(),
value: unsafe { FormatData::new(data.format, data.data)},
}
}),
)),
4 => todo!("Event::SetPropertyReply"),
5 => todo!("Event::CommandReply"),
6 => todo!("Event::StartFile"),
7 => todo!("Event::EndFile"),
8 => todo!("Event::FileLoaded"),
16 => todo!("Event::ClientMessage"),
17 => todo!("Event::VideoReconfig"),
18 => todo!("Event::AudioReconfig"),
20 => todo!("Event::Seek"),
21 => todo!("Event::PlaybackRestart"),
22 => todo!("Event::PropertyChange"),
24 => todo!("Event::QueueOverflow"),
25 => todo!("Event::Hook"),
_ => Event::Ignore(event.event_id),
}
}
}
pub enum FormatData<'a> {
None,
String(Cow<'a, str>),
OsdString(&'a str),
Flag(bool),
Int64(i64),
Double(f64),
//Node(Node<'a>),
}
impl<'a> FormatData<'a> {
unsafe fn new(format: ffi::mpv_format, data: *mut std::ffi::c_void) -> Self {
match format {
0 => Self::None,
1 => {
let data = data as *mut *mut std::ffi::c_char;
Self::String(String::from_utf8_lossy(
std::ffi::CStr::from_ptr(*data).to_bytes(),
))
}
2 => {
let data = data as *mut *mut std::ffi::c_char;
Self::OsdString(
std::ffi::CStr::from_ptr(*data)
.to_str()
.expect("OSD string wasn't UTF-8"),
)
}
3 => {
let data = data as *mut std::ffi::c_int;
Self::Flag(match *data {
0 => false,
1 => true,
_ => panic!("invalid mpv flag value"),
})
}
4 => {
let data = data as *mut i64;
Self::Int64(*data)
}
5 => {
let data = data as *mut f64;
Self::Double(*data)
}
6 => todo!(),
7 => todo!(),
8 => todo!(),
9 => todo!(),
_ => panic!("invalid mpv format"),
}
}
}
pub struct EventProperty<'a> {
name: &'a str,
value: FormatData<'a>,
}
pub struct EventLogMessage<'a> {
prefix: &'a str,
level: &'a str,
text: &'a str,
log_level: i32,
}
pub enum EndFileReason {
Eof,
Stop,
Quit,
Error(Error),
Redirect,
}
pub struct EventStartFile {
pub playlist_entry_id: i64,
}
pub struct EventEndFile {
pub reason: EndFileReason,
pub playlist_entry_id: i64,
pub playlist_insert_id: i64,
pub playlist_insert_num_entries: i32,
}
pub struct EventClientMessage<'a> {
pub num_args: i32,
pub args: &'a [&'a str],
}
pub struct EventHook<'a> {
pub name: &'a str,
pub id: u64,
}
pub enum Event<'a> {
Shutdown,
LogMessage(EventLogMessage<'a>),
GetPropertyReply(u64, Result<EventProperty<'a>, Error>),
SetPropertyReply(u64, Result<(), Error>),
//CommandReply(u64, Result<Node<'a>, Error>),
StartFile(EventStartFile),
EndFile(EventEndFile),
FileLoaded,
ClientMessage(EventClientMessage<'a>),
VideoReconfig,
AudioReconfig,
Seek,
PlaybackRestart,
PropertyChange(u64, EventProperty<'a>),
QueueOverflow,
Hook(u64, EventHook<'a>),
// "Keep in mind that later ABI compatible releases might add new event
// types. These should be ignored by the API user."
Ignore(u32),
}
impl Drop for Handle {
fn drop(&mut self) {
// destroy? terminate_destroy??
todo!()
}
}