aboutsummaryrefslogtreecommitdiffstats
path: root/libmpv2/examples
diff options
context:
space:
mode:
authorBenedikt Peetz <benedikt.peetz@b-peetz.de>2024-08-21 10:49:23 +0200
committerBenedikt Peetz <benedikt.peetz@b-peetz.de>2024-08-21 11:28:43 +0200
commit1debeb77f7986de1b659dcfdc442de6415e1d9f5 (patch)
tree4df3e7c3f6a2d1ec116e4088c5ace7f143a8b05f /libmpv2/examples
downloadyt-1debeb77f7986de1b659dcfdc442de6415e1d9f5.zip
chore: Initial Commit
This repository was migrated out of my nixos-config.
Diffstat (limited to 'libmpv2/examples')
-rw-r--r--libmpv2/examples/events.rs93
-rw-r--r--libmpv2/examples/opengl.rs139
-rw-r--r--libmpv2/examples/protocol.rs87
3 files changed, 319 insertions, 0 deletions
diff --git a/libmpv2/examples/events.rs b/libmpv2/examples/events.rs
new file mode 100644
index 0000000..8f7c79f
--- /dev/null
+++ b/libmpv2/examples/events.rs
@@ -0,0 +1,93 @@
+// yt - A fully featured command line YouTube client
+//
+// Copyright (C) 2024 Benedikt Peetz <benedikt.peetz@b-peetz.de>
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+// This file is part of Yt.
+//
+// You should have received a copy of the License along with this program.
+// If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
+
+use libmpv2::{events::*, mpv_node::MpvNode, *};
+
+use std::{collections::HashMap, env, thread, time::Duration};
+
+const VIDEO_URL: &str = "https://www.youtube.com/watch?v=VLnWf1sQkjY";
+
+fn main() -> Result<()> {
+ let path = env::args()
+ .nth(1)
+ .unwrap_or_else(|| String::from(VIDEO_URL));
+
+ // Create an `Mpv` and set some properties.
+ let mpv = Mpv::with_initializer(|init| {
+ init.set_property("vo", "null")?;
+ Ok(())
+ })
+ .unwrap();
+ mpv.set_property("volume", 15)?;
+
+ let mut ev_ctx = EventContext::new(mpv.ctx);
+ ev_ctx.disable_deprecated_events()?;
+ ev_ctx.observe_property("volume", Format::Int64, 0)?;
+ ev_ctx.observe_property("demuxer-cache-state", Format::Node, 0)?;
+
+ crossbeam::scope(|scope| {
+ scope.spawn(|_| {
+ mpv.command("loadfile", &[&path, "append-play"]).unwrap();
+
+ thread::sleep(Duration::from_secs(3));
+
+ mpv.set_property("volume", 25).unwrap();
+
+ thread::sleep(Duration::from_secs(5));
+
+ // Trigger `Event::EndFile`.
+ mpv.command("playlist-next", &["force"]).unwrap();
+ });
+ scope.spawn(move |_| loop {
+ let ev = ev_ctx.wait_event(600.).unwrap_or(Err(Error::Null));
+
+ match ev {
+ Ok(Event::EndFile(r)) => {
+ println!("Exiting! Reason: {:?}", r);
+ break;
+ }
+
+ Ok(Event::PropertyChange {
+ name: "demuxer-cache-state",
+ change: PropertyData::Node(mpv_node),
+ ..
+ }) => {
+ let ranges = seekable_ranges(mpv_node);
+ println!("Seekable ranges updated: {:?}", ranges);
+ }
+ Ok(e) => println!("Event triggered: {:?}", e),
+ Err(e) => println!("Event errored: {:?}", e),
+ }
+ });
+ })
+ .unwrap();
+ Ok(())
+}
+
+fn seekable_ranges(demuxer_cache_state: MpvNode) -> Vec<(f64, f64)> {
+ let mut res = Vec::new();
+ let props = demuxer_cache_state
+ .map()
+ .unwrap()
+ .collect::<HashMap<_, _>>();
+ let ranges = props
+ .get("seekable-ranges")
+ .unwrap()
+ .clone()
+ .array()
+ .unwrap();
+ for node in ranges {
+ let range = node.map().unwrap().collect::<HashMap<_, _>>();
+ let start = range.get("start").unwrap().f64().unwrap();
+ let end = range.get("end").unwrap().f64().unwrap();
+ res.push((start, end));
+ }
+ res
+}
diff --git a/libmpv2/examples/opengl.rs b/libmpv2/examples/opengl.rs
new file mode 100644
index 0000000..1de307f
--- /dev/null
+++ b/libmpv2/examples/opengl.rs
@@ -0,0 +1,139 @@
+// yt - A fully featured command line YouTube client
+//
+// Copyright (C) 2024 Benedikt Peetz <benedikt.peetz@b-peetz.de>
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+// This file is part of Yt.
+//
+// You should have received a copy of the License along with this program.
+// If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
+
+use libmpv2::{
+ render::{OpenGLInitParams, RenderContext, RenderParam, RenderParamApiType},
+ Mpv,
+};
+use std::{env, ffi::c_void};
+
+fn get_proc_address(display: &sdl2::VideoSubsystem, name: &str) -> *mut c_void {
+ display.gl_get_proc_address(name) as *mut c_void
+}
+
+const VIDEO_URL: &str = "test-data/jellyfish.mp4";
+
+#[derive(Debug)]
+enum UserEvent {
+ MpvEventAvailable,
+ RedrawRequested,
+}
+
+fn main() {
+ let (window, mut events_loop, event_subsystem, video, _context) = create_sdl2_context();
+
+ let path = env::args()
+ .nth(1)
+ .unwrap_or_else(|| String::from(VIDEO_URL));
+
+ let mut mpv = Mpv::with_initializer(|init| {
+ init.set_property("vo", "libmpv")?;
+ Ok(())
+ })
+ .unwrap();
+ let mut render_context = RenderContext::new(
+ unsafe { mpv.ctx.as_mut() },
+ vec![
+ RenderParam::ApiType(RenderParamApiType::OpenGl),
+ RenderParam::InitParams(OpenGLInitParams {
+ get_proc_address,
+ ctx: video,
+ }),
+ ],
+ )
+ .expect("Failed creating render context");
+
+ event_subsystem
+ .register_custom_event::<UserEvent>()
+ .unwrap();
+
+ mpv.event_context_mut().disable_deprecated_events().unwrap();
+
+ let event_sender = event_subsystem.event_sender();
+ render_context.set_update_callback(move || {
+ event_sender
+ .push_custom_event(UserEvent::RedrawRequested)
+ .unwrap();
+ });
+
+ let event_sender = event_subsystem.event_sender();
+ mpv.event_context_mut().set_wakeup_callback(move || {
+ event_sender
+ .push_custom_event(UserEvent::MpvEventAvailable)
+ .unwrap();
+ });
+ mpv.command("loadfile", &[&path, "replace"]).unwrap();
+
+ 'render: loop {
+ for event in events_loop.poll_iter() {
+ use sdl2::event::Event;
+
+ if event.is_user_event() {
+ match event.as_user_event_type::<UserEvent>().unwrap() {
+ UserEvent::RedrawRequested => {
+ let (width, height) = window.drawable_size();
+ render_context
+ .render::<sdl2::VideoSubsystem>(0, width as _, height as _, true)
+ .expect("Failed to draw on sdl2 window");
+ window.gl_swap_window();
+ }
+ UserEvent::MpvEventAvailable => loop {
+ match mpv.event_context_mut().wait_event(0.0) {
+ Some(Ok(libmpv2::events::Event::EndFile(_))) => {
+ break 'render;
+ }
+ Some(Ok(mpv_event)) => {
+ eprintln!("MPV event: {:?}", mpv_event);
+ }
+ Some(Err(err)) => {
+ eprintln!("MPV Error: {}", err);
+ break 'render;
+ }
+ None => break,
+ }
+ },
+ }
+ }
+
+ match event {
+ Event::Quit { .. } => {
+ break 'render;
+ }
+ _ => (),
+ }
+ }
+ }
+}
+
+fn create_sdl2_context() -> (
+ sdl2::video::Window,
+ sdl2::EventPump,
+ sdl2::EventSubsystem,
+ sdl2::VideoSubsystem,
+ sdl2::video::GLContext,
+) {
+ let sdl = sdl2::init().unwrap();
+ let video = sdl.video().unwrap();
+ let event_subsystem = sdl.event().unwrap();
+ let gl_attr = video.gl_attr();
+ gl_attr.set_context_profile(sdl2::video::GLProfile::Core);
+ gl_attr.set_context_version(3, 3);
+ gl_attr.set_context_flags().forward_compatible().set();
+ let window = video
+ .window("OpenGL mpv", 960, 540)
+ .opengl()
+ .resizable()
+ .build()
+ .unwrap();
+ let gl_context = window.gl_create_context().unwrap();
+ let event_loop = sdl.event_pump().unwrap();
+
+ (window, event_loop, event_subsystem, video, gl_context)
+}
diff --git a/libmpv2/examples/protocol.rs b/libmpv2/examples/protocol.rs
new file mode 100644
index 0000000..46702d6
--- /dev/null
+++ b/libmpv2/examples/protocol.rs
@@ -0,0 +1,87 @@
+// yt - A fully featured command line YouTube client
+//
+// Copyright (C) 2024 Benedikt Peetz <benedikt.peetz@b-peetz.de>
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+// This file is part of Yt.
+//
+// You should have received a copy of the License along with this program.
+// If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
+
+use std::{
+ env,
+ fs::File,
+ io::{Read, Seek, SeekFrom},
+ mem, thread,
+ time::Duration,
+};
+
+#[cfg(all(not(test), not(feature = "protocols")))]
+compile_error!("The feature `protocols` needs to be enabled for this example`");
+
+#[cfg(feature = "protocols")]
+fn main() {
+ use libmpv2::{protocol::*, *};
+
+ let path = format!(
+ "filereader://{}",
+ env::args()
+ .nth(1)
+ .expect("Expected path to local media as argument, found nil.")
+ );
+
+ let protocol = unsafe {
+ Protocol::new(
+ "filereader".into(),
+ (),
+ open,
+ close,
+ read,
+ Some(seek),
+ Some(size),
+ )
+ };
+
+ let mpv = Mpv::new().unwrap();
+ mpv.set_property("volume", 25).unwrap();
+
+ let proto_ctx = mpv.create_protocol_context();
+ proto_ctx.register(protocol).unwrap();
+
+ mpv.command("loadfile", &[&path, "append-play"]).unwrap();
+
+ thread::sleep(Duration::from_secs(10));
+
+ mpv.command("seek", &["15"]).unwrap();
+
+ thread::sleep(Duration::from_secs(5));
+}
+
+fn open(_: &mut (), uri: &str) -> File {
+ // Open the file, and strip the `filereader://` part
+ let ret = File::open(&uri[13..]).unwrap();
+
+ println!("Opened file[{}], ready for orders o7", &uri[13..]);
+ ret
+}
+
+fn close(_: Box<File>) {
+ println!("Closing file, bye bye~~");
+}
+
+fn read(cookie: &mut File, buf: &mut [i8]) -> i64 {
+ unsafe {
+ let forbidden_magic = mem::transmute::<&mut [i8], &mut [u8]>(buf);
+
+ cookie.read(forbidden_magic).unwrap() as _
+ }
+}
+
+fn seek(cookie: &mut File, offset: i64) -> i64 {
+ println!("Seeking to byte {}", offset);
+ cookie.seek(SeekFrom::Start(offset as u64)).unwrap() as _
+}
+
+fn size(cookie: &mut File) -> i64 {
+ cookie.metadata().unwrap().len() as _
+}