playdate_rs/
video.rs

1use crate::error::Error;
2
3use alloc::{borrow::ToOwned, ffi::CString, string::String};
4
5use crate::{graphics::Bitmap, util::Ref, PLAYDATE};
6
7pub struct PlaydateVideo {
8    handle: *const sys::playdate_video,
9}
10
11impl PlaydateVideo {
12    pub(crate) fn new(handle: *const sys::playdate_video) -> Self {
13        Self { handle }
14    }
15
16    /// Sets the rendering destination for the video player to the screen.
17    pub fn use_screen_context(&self, player: &VideoPlayer) {
18        unsafe { (*self.handle).useScreenContext.unwrap()(player.handle) }
19    }
20}
21
22#[derive(PartialEq, Debug, Clone, Default)]
23pub struct VideoPlayerInfo {
24    pub width: i32,
25    pub height: i32,
26    pub frame_rate: f32,
27    pub frame_count: i32,
28    pub current_frame: i32,
29}
30
31#[derive(PartialEq, Eq, Debug)]
32pub struct VideoPlayer {
33    handle: *mut sys::LCDVideoPlayer,
34}
35
36unsafe impl Send for VideoPlayer {}
37unsafe impl Sync for VideoPlayer {}
38
39impl VideoPlayer {
40    /// Opens the pdv file at path and returns a new video player object for rendering its frames.
41    pub fn load(&self, path: impl AsRef<str>) -> Result<Self, Error> {
42        let c_string = CString::new(path.as_ref()).unwrap();
43        let handle =
44            unsafe { (*PLAYDATE.graphics.video.handle).loadVideo.unwrap()(c_string.as_ptr()) };
45        if handle.is_null() {
46            Err(Error::FileNotExists("Failed to load video".to_owned()))
47        } else {
48            Ok(Self { handle })
49        }
50    }
51
52    /// Sets the rendering destination for the video player to the given bitmap.
53    pub fn set_context<'a, 'b: 'a>(&'a self, context: &'b Bitmap) -> Result<(), Error> {
54        let result = unsafe {
55            (*PLAYDATE.graphics.video.handle).setContext.unwrap()(self.handle, context.handle)
56        };
57        if result != 0 {
58            Ok(())
59        } else {
60            Err(Error::Unknown(self.get_error().unwrap()))
61        }
62    }
63
64    /// Gets the rendering destination for the video player. If no rendering context has been setallocates a context bitmap with the same dimensions as the vieo will be allocated.
65    pub fn get_context(&self) -> Ref<Bitmap> {
66        let ptr = unsafe { (*PLAYDATE.graphics.video.handle).getContext.unwrap()(self.handle) };
67        // FIXME: ptr maybe malloced
68        Bitmap::from_ref(ptr)
69    }
70
71    /// Renders frame number n into the current context.
72    pub fn render_frame(&self, n: usize) -> Result<(), Error> {
73        let result =
74            unsafe { (*PLAYDATE.graphics.video.handle).renderFrame.unwrap()(self.handle, n as _) };
75        if result != 0 {
76            Ok(())
77        } else {
78            let err = self.get_error().unwrap();
79            Err(Error::Unknown(err.to_owned()))
80        }
81    }
82
83    /// Returns text describing the most recent error.
84    pub fn get_error(&self) -> Option<String> {
85        let c_string = unsafe { (*PLAYDATE.graphics.video.handle).getError.unwrap()(self.handle) };
86        if c_string.is_null() {
87            None
88        } else {
89            let c_str = unsafe { ::core::ffi::CStr::from_ptr(c_string) };
90            Some(c_str.to_str().unwrap().to_owned())
91        }
92    }
93
94    /// Retrieves information about the video, by passing in (possibly NULL) value pointers.
95    pub fn get_info(&self) -> VideoPlayerInfo {
96        let mut info = VideoPlayerInfo::default();
97        unsafe {
98            (*PLAYDATE.graphics.video.handle).getInfo.unwrap()(
99                self.handle,
100                &mut info.width,
101                &mut info.height,
102                &mut info.frame_rate,
103                &mut info.frame_count,
104                &mut info.current_frame,
105            )
106        };
107        info
108    }
109}
110
111impl Drop for VideoPlayer {
112    fn drop(&mut self) {
113        unsafe { (*PLAYDATE.graphics.video.handle).freePlayer.unwrap()(self.handle) }
114    }
115}