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 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 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 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 pub fn get_context(&self) -> Ref<Bitmap> {
66 let ptr = unsafe { (*PLAYDATE.graphics.video.handle).getContext.unwrap()(self.handle) };
67 Bitmap::from_ref(ptr)
69 }
70
71 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 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 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}