use log::{debug, info};
use std::sync::mpsc;
use std::time::Instant;
use crate::cache::{Cache, CacheMessage};
use crate::frame::Frame;
const FPS_PRESETS: &[f32] = &[1.0, 2.0, 4.0, 8.0, 12.0, 24.0, 30.0, 60.0, 120.0, 240.0];
pub struct Player {
pub cache: Cache,
pub is_playing: bool,
pub fps: f32,
pub loop_enabled: bool,
pub play_direction: f32, last_frame_time: Option<Instant>,
pub selected_seq_idx: Option<usize>, }
impl Player {
pub fn new() -> (Self, mpsc::Receiver<CacheMessage>) {
Self::new_with_config(0.75, None)
}
pub fn new_with_config(max_mem_fraction: f64, workers: Option<usize>) -> (Self, mpsc::Receiver<CacheMessage>) {
info!("Player initialized with new architecture");
let (cache, ui_rx) = Cache::new(max_mem_fraction, workers);
let player = Self {
cache,
is_playing: false,
fps: 24.0,
loop_enabled: true,
play_direction: 1.0,
last_frame_time: None,
selected_seq_idx: None,
};
(player, ui_rx)
}
pub fn get_current_frame(&mut self) -> Option<&Frame> {
let frame_idx = self.cache.frame();
self.cache.get_frame(frame_idx)
}
pub fn update(&mut self) {
if !self.is_playing || self.cache.total_frames() == 0 {
return;
}
let now = Instant::now();
if let Some(last_time) = self.last_frame_time {
let elapsed = now.duration_since(last_time).as_secs_f32();
let frame_duration = 1.0 / self.fps;
if elapsed >= frame_duration {
self.advance_frame();
self.last_frame_time = Some(now);
}
} else {
self.last_frame_time = Some(now);
}
}
fn advance_frame(&mut self) {
let total_frames = self.cache.total_frames();
if total_frames == 0 {
return;
}
let current = self.cache.frame();
let (play_start, play_end) = self.cache.get_play_range();
if self.play_direction > 0.0 {
let next = current + 1;
if next > play_end {
if self.loop_enabled {
debug!("Frame loop: {} -> {}", current, play_start);
self.cache.set_frame(play_start);
} else {
debug!("Reached play range end, stopping");
self.cache.set_frame(play_end);
self.is_playing = false;
}
} else {
self.cache.set_frame(next);
}
} else {
if current <= play_start {
if self.loop_enabled {
debug!("Frame loop: {} -> {}", current, play_end);
self.cache.set_frame(play_end);
} else {
debug!("Reached play range start, stopping");
self.is_playing = false;
}
} else {
self.cache.set_frame(current - 1);
}
}
}
pub fn toggle_play_pause(&mut self) {
self.is_playing = !self.is_playing;
if self.is_playing {
debug!("Playback started at frame {}", self.cache.frame());
self.last_frame_time = Some(Instant::now());
self.cache.signal_preload();
} else {
debug!("Playback paused at frame {}", self.cache.frame());
self.last_frame_time = None;
}
}
pub fn to_start(&mut self) {
debug!("Rewinding to frame 0");
self.cache.set_frame(0);
self.last_frame_time = None;
self.cache.signal_preload();
}
pub fn to_end(&mut self) {
let (_, global_end) = self.cache.range();
debug!("Skipping to end: frame {}", global_end);
self.cache.set_frame(global_end);
self.last_frame_time = None;
self.cache.signal_preload();
}
pub fn set_frame(&mut self, frame: usize) {
let (_, global_end) = self.cache.range();
let clamped = frame.min(global_end);
self.cache.set_frame(clamped);
self.last_frame_time = None;
self.cache.signal_preload();
}
#[inline]
pub fn current_frame(&self) -> usize {
self.cache.frame()
}
pub fn total_frames(&self) -> usize {
self.cache.total_frames()
}
pub fn jog_forward(&mut self) {
if !self.is_playing {
self.play_direction = 1.0;
self.is_playing = true;
self.last_frame_time = Some(Instant::now());
} else if self.play_direction < 0.0 {
self.play_direction = 1.0;
} else {
self.increase_fps();
}
}
pub fn jog_backward(&mut self) {
if !self.is_playing {
self.play_direction = -1.0;
self.is_playing = true;
self.last_frame_time = Some(Instant::now());
} else if self.play_direction > 0.0 {
self.play_direction = -1.0;
} else {
self.increase_fps();
}
}
fn increase_fps(&mut self) {
if let Some(idx) = FPS_PRESETS.iter().position(|&f| f >= self.fps) {
if idx + 1 < FPS_PRESETS.len() {
self.fps = FPS_PRESETS[idx + 1];
}
}
}
fn decrease_fps(&mut self) {
if let Some(idx) = FPS_PRESETS.iter().rposition(|&f| f < self.fps) {
self.fps = FPS_PRESETS[idx];
} else {
self.fps = FPS_PRESETS[0];
}
}
pub fn stop_or_decrease_fps(&mut self) {
if self.is_playing {
debug!("Playback stopped at frame {}", self.cache.frame());
self.is_playing = false;
self.last_frame_time = None;
} else {
self.decrease_fps();
debug!("FPS decreased to {}", self.fps);
}
}
pub fn reset_settings(&mut self) {
self.fps = 24.0;
self.loop_enabled = true;
info!("Player settings reset");
}
}
impl Default for Player {
fn default() -> Self {
let (player, _rx) = Self::new();
player
}
}