ass_renderer/debug/player/
mod.rs1use crate::{BackendType, Frame, RenderContext, RenderError, Renderer};
2use ass_core::parser::Script;
3
4#[cfg(not(feature = "nostd"))]
5use std::collections::HashMap;
6#[cfg(not(feature = "nostd"))]
7use std::time::Instant;
8
9#[cfg(feature = "nostd")]
10use alloc::collections::BTreeMap as HashMap;
11#[cfg(feature = "nostd")]
12use alloc::string::String;
13
14mod playback;
15mod render;
16mod report;
17mod testing;
18
19pub use report::{PlayerFrame, TestPoint, TestReport};
20
21pub struct DebugPlayer {
23 renderer: Renderer,
24 script_content: Option<String>,
25 #[allow(dead_code)] parsed_script: Option<Script<'static>>,
27 current_time_ms: u32,
28 playback_speed: f32,
29 is_playing: bool,
30 frame_interval_ms: u32,
31 output_dir: String,
32 save_frames: bool,
33 show_stats: bool,
34 loop_playback: bool,
35 start_time_ms: u32,
36 end_time_ms: u32,
37 frame_cache: HashMap<u32, Frame>,
38 cache_enabled: bool,
39 max_cache_size: usize,
40 playback_start_instant: Option<Instant>,
42 playback_start_time_ms: u32,
43 accumulated_time_ms: f32,
44 width: u32,
45 height: u32,
46}
47
48impl DebugPlayer {
49 pub fn new(backend_type: BackendType, width: u32, height: u32) -> Result<Self, RenderError> {
50 let mut context = RenderContext::new(width, height);
51 context.font_database_mut().load_system_fonts();
52
53 let renderer = Renderer::new(backend_type, context)?;
54
55 Ok(Self {
56 renderer,
57 script_content: None,
58 parsed_script: None,
59 current_time_ms: 0,
60 playback_speed: 1.0,
61 is_playing: false,
62 frame_interval_ms: 40, output_dir: "debug_player_output".to_string(),
64 save_frames: false,
65 show_stats: true,
66 loop_playback: false,
67 start_time_ms: 0,
68 end_time_ms: 0, frame_cache: HashMap::new(),
70 cache_enabled: true,
71 max_cache_size: 100, playback_start_instant: None,
73 playback_start_time_ms: 0,
74 accumulated_time_ms: 0.0,
75 width,
76 height,
77 })
78 }
79
80 pub fn width(&self) -> u32 {
81 self.width
82 }
83
84 pub fn height(&self) -> u32 {
85 self.height
86 }
87
88 pub fn has_script(&self) -> bool {
90 self.script_content.is_some()
91 }
92
93 pub fn duration_ms(&self) -> u32 {
95 self.end_time_ms
96 }
97
98 pub fn load_script(&mut self, script_content: &str) -> Result<(), RenderError> {
99 let owned_content = script_content.to_string();
101 let script = Script::parse(&owned_content)
102 .map_err(|e| RenderError::ParseError(format!("Failed to parse script: {e:?}")))?;
103
104 let mut max_time = 0u32;
106 let mut event_count = 0;
107 for section in script.sections() {
108 if let ass_core::parser::Section::Events(events) = section {
109 for event in events.iter() {
110 event_count += 1;
111 if let Ok(end) = event.end_time_cs() {
112 max_time = max_time.max(end * 10); }
114 }
115 }
116 }
117
118 if max_time > 0 {
119 self.end_time_ms = max_time;
120 } else {
121 self.end_time_ms = 10000;
124 }
125
126 self.frame_cache.clear();
128
129 self.script_content = Some(owned_content);
131 println!(
135 "Script loaded. Duration: {duration}ms, Events: {events}",
136 duration = self.end_time_ms,
137 events = event_count
138 );
139
140 Ok(())
141 }
142}