1#![allow(dead_code)]
8
9use alloc::vec::Vec;
10
11use spin::Mutex;
12
13use super::{decode, VideoFrame, VideoInfo};
14use crate::error::KernelError;
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub(crate) enum PlaybackState {
23 Stopped,
24 Playing,
25 Paused,
26 Finished,
27}
28
29pub(crate) struct RawVideoStream {
38 frames: Vec<VideoFrame>,
39 current_frame: usize,
40 info: VideoInfo,
41 state: PlaybackState,
42 frames_displayed: u64,
43 start_tick: u64,
45}
46
47impl RawVideoStream {
48 pub(crate) fn new(info: VideoInfo) -> Self {
50 Self {
51 frames: Vec::new(),
52 current_frame: 0,
53 info,
54 state: PlaybackState::Stopped,
55 frames_displayed: 0,
56 start_tick: 0,
57 }
58 }
59
60 pub(crate) fn add_frame(&mut self, frame: VideoFrame) {
62 self.frames.push(frame);
63 }
64
65 pub(crate) fn play(&mut self) {
67 match self.state {
68 PlaybackState::Stopped | PlaybackState::Finished => {
69 self.current_frame = 0;
70 self.frames_displayed = 0;
71 self.start_tick = get_tick();
72 self.state = PlaybackState::Playing;
73 }
74 PlaybackState::Paused => {
75 self.start_tick = get_tick();
77 self.state = PlaybackState::Playing;
78 }
79 PlaybackState::Playing => {} }
81 }
82
83 pub(crate) fn pause(&mut self) {
85 if self.state == PlaybackState::Playing {
86 self.state = PlaybackState::Paused;
87 }
88 }
89
90 pub(crate) fn stop(&mut self) {
92 self.state = PlaybackState::Stopped;
93 self.current_frame = 0;
94 self.frames_displayed = 0;
95 self.start_tick = 0;
96 }
97
98 pub(crate) fn seek(&mut self, frame_index: usize) {
100 if frame_index < self.frames.len() {
101 self.current_frame = frame_index;
102 }
103 }
104
105 pub(crate) fn next_frame(&mut self) -> Option<&VideoFrame> {
110 if self.state != PlaybackState::Playing {
111 return if self.state == PlaybackState::Paused {
113 self.frames.get(self.current_frame)
114 } else {
115 None
116 };
117 }
118
119 if self.frames.is_empty() {
120 self.state = PlaybackState::Finished;
121 return None;
122 }
123
124 let elapsed_ms = get_tick().saturating_sub(self.start_tick);
127
128 let frame_dur_ms = if self.info.frame_rate_num > 0 {
130 (1000u64 * self.info.frame_rate_den as u64) / self.info.frame_rate_num as u64
131 } else {
132 33
134 };
135
136 let target_frame = if frame_dur_ms > 0 {
137 (elapsed_ms / frame_dur_ms) as usize
138 } else {
139 0
140 };
141
142 if target_frame >= self.frames.len() {
143 self.state = PlaybackState::Finished;
144 self.current_frame = self.frames.len() - 1;
145 return self.frames.last();
146 }
147
148 self.current_frame = target_frame;
149 self.frames_displayed += 1;
150
151 self.frames.get(self.current_frame)
152 }
153
154 pub(crate) fn current_position_ms(&self) -> u64 {
156 if self.info.frame_rate_num == 0 || self.frames.is_empty() {
157 return 0;
158 }
159 let frame_dur_ms =
160 (1000u64 * self.info.frame_rate_den as u64) / self.info.frame_rate_num as u64;
161 (self.current_frame as u64) * frame_dur_ms
162 }
163
164 pub(crate) fn duration_ms(&self) -> u64 {
166 if self.info.frame_rate_num == 0 || self.frames.is_empty() {
167 return 0;
168 }
169 let frame_dur_ms =
170 (1000u64 * self.info.frame_rate_den as u64) / self.info.frame_rate_num as u64;
171 (self.frames.len() as u64) * frame_dur_ms
172 }
173
174 pub(crate) fn is_finished(&self) -> bool {
176 self.state == PlaybackState::Finished
177 }
178
179 pub(crate) fn state(&self) -> PlaybackState {
181 self.state
182 }
183
184 pub(crate) fn frame_count(&self) -> usize {
186 self.frames.len()
187 }
188
189 pub(crate) fn info(&self) -> &VideoInfo {
191 &self.info
192 }
193}
194
195pub(crate) struct MediaPlayer {
202 video_stream: Option<RawVideoStream>,
203 audio_stream_id: Option<u32>,
204 display_x: u32,
205 display_y: u32,
206 display_width: u32,
207 display_height: u32,
208}
209
210impl MediaPlayer {
211 pub(crate) fn new() -> Self {
213 Self {
214 video_stream: None,
215 audio_stream_id: None,
216 display_x: 0,
217 display_y: 0,
218 display_width: 0,
219 display_height: 0,
220 }
221 }
222
223 pub(crate) fn load_image(&mut self, data: &[u8]) -> Result<(), KernelError> {
225 let frame = decode::decode_image(data)?;
226
227 let info = VideoInfo {
228 width: frame.width,
229 height: frame.height,
230 format: frame.format,
231 frame_rate_num: 1,
232 frame_rate_den: 1,
233 };
234
235 let mut stream = RawVideoStream::new(info);
236 stream.add_frame(frame);
237
238 self.video_stream = Some(stream);
239 Ok(())
240 }
241
242 pub(crate) fn load_video(
244 &mut self,
245 frames: Vec<VideoFrame>,
246 info: VideoInfo,
247 ) -> Result<(), KernelError> {
248 if frames.is_empty() {
249 return Err(KernelError::InvalidArgument {
250 name: "frames",
251 value: "empty frame list",
252 });
253 }
254
255 let mut stream = RawVideoStream::new(info);
256 for frame in frames {
257 stream.add_frame(frame);
258 }
259
260 self.video_stream = Some(stream);
261 Ok(())
262 }
263
264 pub(crate) fn play(&mut self) -> Result<(), KernelError> {
266 match self.video_stream.as_mut() {
267 Some(stream) => {
268 stream.play();
269 Ok(())
270 }
271 None => Err(KernelError::InvalidState {
272 expected: "loaded",
273 actual: "no video loaded",
274 }),
275 }
276 }
277
278 pub(crate) fn pause(&mut self) {
280 if let Some(stream) = self.video_stream.as_mut() {
281 stream.pause();
282 }
283 }
284
285 pub(crate) fn stop(&mut self) {
287 if let Some(stream) = self.video_stream.as_mut() {
288 stream.stop();
289 }
290 }
291
292 pub(crate) fn render_current_frame(&self) -> Option<&VideoFrame> {
294 self.video_stream
295 .as_ref()
296 .and_then(|stream| stream.frames.get(stream.current_frame))
297 }
298
299 pub(crate) fn set_display_rect(&mut self, x: u32, y: u32, width: u32, height: u32) {
301 self.display_x = x;
302 self.display_y = y;
303 self.display_width = width;
304 self.display_height = height;
305 }
306
307 pub(crate) fn display_rect(&self) -> (u32, u32, u32, u32) {
309 (
310 self.display_x,
311 self.display_y,
312 self.display_width,
313 self.display_height,
314 )
315 }
316
317 pub(crate) fn is_loaded(&self) -> bool {
319 self.video_stream.is_some()
320 }
321
322 pub(crate) fn playback_state(&self) -> Option<PlaybackState> {
324 self.video_stream.as_ref().map(|s| s.state())
325 }
326}
327
328impl Default for MediaPlayer {
329 fn default() -> Self {
330 Self::new()
331 }
332}
333
334static PLAYER: Mutex<Option<MediaPlayer>> = Mutex::new(None);
339
340pub(crate) fn init() -> Result<(), KernelError> {
342 let mut guard = PLAYER.lock();
343 if guard.is_none() {
344 *guard = Some(MediaPlayer::new());
345 }
346 Ok(())
347}
348
349pub(crate) fn with_player<R, F: FnOnce(&mut MediaPlayer) -> R>(f: F) -> Result<R, KernelError> {
351 let mut guard = PLAYER.lock();
352 match guard.as_mut() {
353 Some(player) => Ok(f(player)),
354 None => Err(KernelError::NotInitialized {
355 subsystem: "video player",
356 }),
357 }
358}
359
360static TICK_COUNTER: core::sync::atomic::AtomicU64 = core::sync::atomic::AtomicU64::new(0);
369
370fn get_tick() -> u64 {
372 TICK_COUNTER.load(core::sync::atomic::Ordering::Relaxed)
373}
374
375pub(crate) fn advance_tick(ms: u64) {
377 TICK_COUNTER.fetch_add(ms, core::sync::atomic::Ordering::Relaxed);
378}
379
380pub(crate) fn set_tick(ms: u64) {
382 TICK_COUNTER.store(ms, core::sync::atomic::Ordering::Relaxed);
383}
384
385#[cfg(test)]
390mod tests {
391 use super::*;
392 use crate::graphics::PixelFormat;
393
394 fn make_info(fps: u32) -> VideoInfo {
395 VideoInfo {
396 width: 4,
397 height: 4,
398 format: PixelFormat::Argb8888,
399 frame_rate_num: fps,
400 frame_rate_den: 1,
401 }
402 }
403
404 fn make_frame(r: u8) -> VideoFrame {
405 let mut f = VideoFrame::new(4, 4, PixelFormat::Argb8888);
406 f.set_pixel(0, 0, r, 0, 0, 255);
407 f
408 }
409
410 #[test]
411 fn test_stream_lifecycle() {
412 set_tick(0);
413 let mut stream = RawVideoStream::new(make_info(10)); stream.add_frame(make_frame(10));
415 stream.add_frame(make_frame(20));
416 stream.add_frame(make_frame(30));
417
418 assert_eq!(stream.state(), PlaybackState::Stopped);
419 assert_eq!(stream.duration_ms(), 300); stream.play();
422 assert_eq!(stream.state(), PlaybackState::Playing);
423
424 let f = stream.next_frame().unwrap();
426 assert_eq!(f.get_pixel(0, 0).0, 10);
427
428 advance_tick(150);
430 let f = stream.next_frame().unwrap();
431 assert_eq!(f.get_pixel(0, 0).0, 20);
432
433 stream.pause();
435 assert_eq!(stream.state(), PlaybackState::Paused);
436
437 let f = stream.next_frame().unwrap();
439 assert_eq!(f.get_pixel(0, 0).0, 20);
440
441 stream.stop();
443 assert_eq!(stream.state(), PlaybackState::Stopped);
444 assert!(stream.next_frame().is_none());
445
446 set_tick(0);
448 }
449
450 #[test]
451 fn test_stream_finished() {
452 set_tick(0);
453 let mut stream = RawVideoStream::new(make_info(10));
454 stream.add_frame(make_frame(10));
455
456 stream.play();
457 advance_tick(500);
459 let _f = stream.next_frame();
460 assert!(stream.is_finished());
461
462 set_tick(0);
463 }
464
465 #[test]
466 fn test_media_player_load_video() {
467 let info = make_info(30);
468 let frames = alloc::vec![make_frame(1), make_frame(2)];
469 let mut player = MediaPlayer::new();
470
471 player.load_video(frames, info).expect("load should work");
472 assert!(player.is_loaded());
473
474 let frame = player.render_current_frame().unwrap();
475 assert_eq!(frame.width, 4);
476 }
477
478 #[test]
479 fn test_media_player_display_rect() {
480 let mut player = MediaPlayer::new();
481 player.set_display_rect(10, 20, 640, 480);
482 assert_eq!(player.display_rect(), (10, 20, 640, 480));
483 }
484
485 #[test]
486 fn test_media_player_play_without_load() {
487 let mut player = MediaPlayer::new();
488 let result = player.play();
489 assert!(result.is_err());
490 }
491
492 #[test]
493 fn test_seek() {
494 let mut stream = RawVideoStream::new(make_info(30));
495 stream.add_frame(make_frame(10));
496 stream.add_frame(make_frame(20));
497 stream.add_frame(make_frame(30));
498
499 stream.seek(2);
500 assert_eq!(stream.current_frame, 2);
501
502 stream.seek(100);
504 assert_eq!(stream.current_frame, 2);
505 }
506}