Skip to content

Commit 72a0087

Browse files
committed
refactor goto-functions to draw frame too
1 parent 9e2d9f4 commit 72a0087

File tree

1 file changed

+62
-74
lines changed

1 file changed

+62
-74
lines changed

src/main.rs

Lines changed: 62 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,7 @@ impl FrameIterator {
488488
return view_string;
489489
}
490490

491-
fn skip_some_frames(&mut self, num_frames: u32) {
491+
fn skip_some_frames(&mut self, num_frames: u32) -> String {
492492
// When you only want to advance a few frames,
493493
// without spawning a new ffmpeg process,
494494
// but also without calling chafa.draw each frame as you would in loop { take_frame() }
@@ -498,16 +498,17 @@ impl FrameIterator {
498498
for _ in 0..num_frames {
499499
self.stdout.read_exact(&mut self.pixel_buffer);
500500
}
501+
return self.take_frame();
501502
}
502503

503-
fn goto_timestamp(&mut self, timestamp: SecondsFloat) -> Result<(), Box<dyn Error>> {
504+
fn goto_timestamp(&mut self, timestamp: SecondsFloat) -> Result<String, Box<dyn Error>> {
504505
// Start new process at any position in video.
505506
// This should be faster than reading far ahead in the old process,
506507
// and this enables "backward seeking" too.
507508

508509
let new_stdout = FrameIterator::_create_decoding_process(&self.video_path, timestamp)?;
509510
self.stdout = new_stdout;
510-
Ok(())
511+
Ok(self.take_frame())
511512
}
512513
}
513514

@@ -705,11 +706,9 @@ fn init() -> Result<Model, String> {
705706
// --- UPDATE --- //
706707

707708
fn update(m: &mut Model, terminal_event: Event) -> UpdateResult {
708-
709709
m.needs_to_clear = false;
710710
match terminal_event {
711711
Event::Key(keyevent) => {
712-
713712
if (keyevent.modifiers == KeyModifiers::CONTROL && keyevent.code == KeyCode::Char('c'))
714713
|| keyevent.code == KeyCode::Char('q')
715714
{
@@ -744,7 +743,53 @@ fn update(m: &mut Model, terminal_event: Event) -> UpdateResult {
744743
return UpdateResult::Continue;
745744
}
746745

747-
// --- find the next frame number to render --- //
746+
let whole_elapsed_frames = frames_since_prev_instant(m);
747+
let is_too_fast = whole_elapsed_frames == 0;
748+
match is_too_fast {
749+
true => {
750+
// slow down by not drawing anything during this tick
751+
m.prev_instant = now;
752+
return UpdateResult::Continue;
753+
},
754+
false => {
755+
// now we know the next frame number to render
756+
m.frame = m.frame_iterator.skip_some_frames(whole_elapsed_frames - 1);
757+
m.frame_number += whole_elapsed_frames as u32;
758+
}
759+
}
760+
761+
// --- update stats --- //
762+
763+
let time_to_update_fps =
764+
m.frame_iterator.num_frames_rendered % NUM_FRAMES_TO_TRACK_FPS as u32 == 0;
765+
if time_to_update_fps {
766+
let recent_time_elapsed: SecondsFloat = (now - m.last_fps_check).as_secs_f64();
767+
m.recent_fps = Some(NUM_FRAMES_TO_TRACK_FPS as f64 / recent_time_elapsed);
768+
m.last_fps_check = now;
769+
} else {
770+
// Either too early and not enough recent data,
771+
// or waiting for next moment to check fps.
772+
// No need to constantly update fps every frame.
773+
}
774+
775+
let time_to_log = m.frame_iterator.num_frames_rendered % 100 == 1;
776+
if time_to_log {
777+
log::info!(
778+
"{:?} {:?} {:?} {:?}",
779+
now - m.start,
780+
m.prev_instant,
781+
m.frame_iterator.num_frames_rendered,
782+
m.frame_number
783+
);
784+
}
785+
786+
m.prev_instant = now;
787+
return UpdateResult::Continue;
788+
}
789+
790+
fn frames_since_prev_instant(m: &mut Model) -> u32 {
791+
// find how many frames elapsed since last tick,
792+
// and modify leftover time
748793

749794
// example converting elapsed ms to elapsed frames:
750795
//
@@ -758,6 +803,7 @@ fn update(m: &mut Model, terminal_event: Event) -> UpdateResult {
758803
// rounding_err = ---------- * --------- = 0.007 seconds
759804
// 30 frames
760805
//
806+
let now = std::time::Instant::now();
761807
let elapsed_secs = (now - m.prev_instant).as_secs_f64();
762808

763809
// how many frames should have passed since last tick; sometimes 0, usually 1 or more
@@ -769,6 +815,7 @@ fn update(m: &mut Model, terminal_event: Event) -> UpdateResult {
769815
let rounding_err: SecondsFloat =
770816
elapsed_secs - (whole_elapsed_frames as f64 * m.VIDEO_METADATA.seconds_per_frame);
771817
m.accumulated_time += rounding_err;
818+
772819
let need_leap_frame = m.accumulated_time > m.VIDEO_METADATA.seconds_per_frame;
773820
if need_leap_frame {
774821
whole_elapsed_frames += 1;
@@ -781,57 +828,7 @@ fn update(m: &mut Model, terminal_event: Event) -> UpdateResult {
781828
// extra_time,
782829
// m.accumulated_time);
783830

784-
// TODO:
785-
// cap fps if we're rendering too quickly.
786-
// i think we should choose to save CPU by capping at decent framerate
787-
// than to be faithful to high fps and use extra CPU
788-
// aka
789-
// if < 15 ms elapsed, that means we're getting +60 fps
790-
// so probably better skip rendering at this moment and save some CPU cycles
791-
// and still get smooth 30fps,
792-
// than overuse CPU to get more than is necessary
793-
// aka
794-
// let is_too_fast = immediate_fps > min(m.VIDEO_METADATA.fps, 30fps) || elapsed_frames == 0
795-
796-
let is_too_fast = whole_elapsed_frames == 0;
797-
if is_too_fast {
798-
// slow down by not drawing anything during this tick
799-
m.prev_instant = now;
800-
return UpdateResult::Continue;
801-
}
802-
803-
// now we know the next frame number to render
804-
m.frame_iterator.skip_some_frames(whole_elapsed_frames - 1);
805-
m.frame = m.frame_iterator.take_frame();
806-
m.frame_number += whole_elapsed_frames as u32;
807-
808-
// --- update stats --- //
809-
810-
let time_to_update_fps =
811-
m.frame_iterator.num_frames_rendered % NUM_FRAMES_TO_TRACK_FPS as u32 == 0;
812-
if time_to_update_fps {
813-
let recent_time_elapsed: SecondsFloat = (now - m.last_fps_check).as_secs_f64();
814-
m.recent_fps = Some(NUM_FRAMES_TO_TRACK_FPS as f64 / recent_time_elapsed);
815-
m.last_fps_check = now;
816-
} else {
817-
// Either too early and not enough recent data,
818-
// or waiting for next moment to check fps.
819-
// No need to constantly update fps every frame.
820-
}
821-
822-
let time_to_log = m.frame_iterator.num_frames_rendered % 100 == 1;
823-
if time_to_log {
824-
log::info!(
825-
"{:?} {:?} {:?} {:?}",
826-
now - m.start,
827-
m.prev_instant,
828-
m.frame_iterator.num_frames_rendered,
829-
m.frame_number
830-
);
831-
}
832-
833-
m.prev_instant = now;
834-
return UpdateResult::Continue;
831+
return whole_elapsed_frames;
835832
}
836833

837834
fn toggle_paused(m: &mut Model) {
@@ -847,12 +844,14 @@ fn toggle_controls_visibility(m: &mut Model) {
847844
m.needs_to_clear = true; // controls will still show at bottom unless cleared/drawn over
848845
}
849846

847+
// note: any function that modifies playerhead position aka m.frame_number in Segment mode
848+
// must check if segment number has changed
849+
850850
fn seek_backwards_15s(m: &mut Model) {
851851
let frames_to_backtrack = (m.VIDEO_METADATA.fps * 15.0) as u32;
852852
m.frame_number = std::cmp::max(m.frame_number as i32 - frames_to_backtrack as i32, 0) as u32;
853853
let timestamp = m.frame_number as SecondsFloat / m.VIDEO_METADATA.fps;
854-
m.frame_iterator.goto_timestamp(timestamp).unwrap();
855-
m.frame = m.frame_iterator.take_frame();
854+
m.frame = m.frame_iterator.goto_timestamp(timestamp).unwrap();
856855

857856
// TODO: update current segment
858857
// let old_position = m.hovering.position;
@@ -864,8 +863,7 @@ fn seek_forwards_15s(m: &mut Model) {
864863
let frames_to_skip = (m.VIDEO_METADATA.fps * 15.0) as u32;
865864
m.frame_number += frames_to_skip;
866865
let timestamp = m.frame_number as SecondsFloat / m.VIDEO_METADATA.fps;
867-
m.frame_iterator.goto_timestamp(timestamp).unwrap();
868-
m.frame = m.frame_iterator.take_frame();
866+
m.frame = m.frame_iterator.goto_timestamp(timestamp).unwrap();
869867

870868
// TODO: update current segment
871869
// let upcoming_markers =
@@ -889,8 +887,7 @@ fn goto_prev_marker(m: &mut Model) {
889887
};
890888
let timestamp: SecondsFloat = m.markers[new_position as usize];
891889
m.frame_number = (timestamp * m.VIDEO_METADATA.fps) as u32;
892-
m.frame_iterator.goto_timestamp(timestamp).unwrap();
893-
m.frame = m.frame_iterator.take_frame();
890+
m.frame = m.frame_iterator.goto_timestamp(timestamp).unwrap();
894891
m.paused = true;
895892
}
896893
}
@@ -917,16 +914,14 @@ fn goto_next_marker(m: &mut Model) {
917914
};
918915
let timestamp: SecondsFloat = m.markers[new_position];
919916
m.frame_number = (timestamp * m.VIDEO_METADATA.fps) as u32;
920-
m.frame_iterator.goto_timestamp(timestamp).unwrap();
921-
m.frame = m.frame_iterator.take_frame();
917+
m.frame = m.frame_iterator.goto_timestamp(timestamp).unwrap();
922918
m.paused = true;
923919
}
924920
};
925921
}
926922

927923
fn create_marker(m: &mut Model) {
928924
// create new marker at current timestamp
929-
//
930925
match m.hovering.mode {
931926
HoverMode::Markers => (),
932927
HoverMode::Segments => {
@@ -939,7 +934,6 @@ fn create_marker(m: &mut Model) {
939934

940935
fn delete_marker(m: &mut Model) {
941936
// delete current marker and enter segments mode
942-
//
943937
match m.hovering.mode {
944938
HoverMode::Segments => (),
945939
HoverMode::Markers => {
@@ -953,18 +947,12 @@ fn advance_one_frame(m: &mut Model) {
953947
match m.paused {
954948
false => (),
955949
true => {
956-
m.frame = m.frame_iterator.take_frame();
950+
m.frame = m.frame_iterator.skip_some_frames(1);
957951
m.frame_number += 1;
958952
}
959953
}
960954
}
961955

962-
963-
964-
965-
966-
967-
968956
// --- VIEW --- //
969957

970958
fn format_secs_to_mm_ss(seconds: SecondsFloat) -> String {

0 commit comments

Comments
 (0)