@@ -35,13 +35,63 @@ use crate::{
3535} ;
3636
3737const PREFETCH_BUFFER_SIZE : usize = 90 ;
38+ #[ cfg( not( target_os = "windows" ) ) ]
3839const PARALLEL_DECODE_TASKS : usize = 6 ;
40+ #[ cfg( not( target_os = "windows" ) ) ]
3941const INITIAL_PARALLEL_DECODE_TASKS : usize = 8 ;
4042const MAX_PREFETCH_AHEAD : u32 = 90 ;
43+ #[ cfg( not( target_os = "windows" ) ) ]
4144const PREFETCH_BEHIND : u32 = 10 ;
4245const FRAME_CACHE_SIZE : usize = 90 ;
4346const RAMP_UP_FRAME_COUNT : u32 = 15 ;
4447
48+ #[ cfg( target_os = "windows" ) ]
49+ struct WindowsTimerResolution ;
50+
51+ #[ cfg( target_os = "windows" ) ]
52+ impl WindowsTimerResolution {
53+ fn set_high_precision ( ) -> Self {
54+ unsafe {
55+ windows:: Win32 :: Media :: timeBeginPeriod ( 1 ) ;
56+ }
57+ Self
58+ }
59+ }
60+
61+ #[ cfg( target_os = "windows" ) ]
62+ impl Drop for WindowsTimerResolution {
63+ fn drop ( & mut self ) {
64+ unsafe {
65+ windows:: Win32 :: Media :: timeEndPeriod ( 1 ) ;
66+ }
67+ }
68+ }
69+
70+ #[ cfg( target_os = "windows" ) ]
71+ async fn precision_sleep_until ( deadline : Instant , stop_rx : & mut watch:: Receiver < bool > ) -> bool {
72+ let spin_threshold = Duration :: from_millis ( 2 ) ;
73+
74+ let now = Instant :: now ( ) ;
75+ if now >= deadline {
76+ return false ;
77+ }
78+
79+ let remaining = deadline - now;
80+ if remaining > spin_threshold {
81+ let sleep_target = deadline - spin_threshold;
82+ tokio:: select! {
83+ _ = stop_rx. changed( ) => return true ,
84+ _ = tokio:: time:: sleep_until( sleep_target) => { }
85+ }
86+ }
87+
88+ while Instant :: now ( ) < deadline {
89+ tokio:: task:: yield_now ( ) . await ;
90+ }
91+
92+ false
93+ }
94+
4595#[ derive( Debug ) ]
4696pub enum PlaybackStartError {
4797 InvalidFps ,
@@ -181,6 +231,12 @@ impl Playback {
181231 let mut in_flight: FuturesUnordered < PrefetchFuture > = FuturesUnordered :: new ( ) ;
182232 let mut frames_decoded: u32 = 0 ;
183233 let mut prefetched_behind: HashSet < u32 > = HashSet :: new ( ) ;
234+ #[ cfg( target_os = "windows" ) ]
235+ let prefetch_behind = 0u32 ;
236+ #[ cfg( not( target_os = "windows" ) ) ]
237+ let prefetch_behind = PREFETCH_BEHIND ;
238+ #[ cfg( target_os = "windows" ) ]
239+ let prefetch_start = Instant :: now ( ) ;
184240
185241 let mut cached_project = prefetch_project. borrow ( ) . clone ( ) ;
186242
@@ -219,12 +275,29 @@ impl Playback {
219275 }
220276
221277 let current_playback_frame = * playback_position_rx. borrow ( ) ;
222- let max_prefetch_frame = current_playback_frame + MAX_PREFETCH_AHEAD ;
278+ #[ cfg( target_os = "windows" ) ]
279+ let max_prefetch_ahead = if prefetch_start. elapsed ( ) < Duration :: from_secs ( 6 ) {
280+ 45u32
281+ } else {
282+ MAX_PREFETCH_AHEAD
283+ } ;
284+ #[ cfg( not( target_os = "windows" ) ) ]
285+ let max_prefetch_ahead = MAX_PREFETCH_AHEAD ;
286+ let max_prefetch_frame = current_playback_frame + max_prefetch_ahead;
287+
288+ #[ cfg( target_os = "windows" ) ]
289+ let initial_parallel_decode_tasks = 3usize ;
290+ #[ cfg( not( target_os = "windows" ) ) ]
291+ let initial_parallel_decode_tasks = INITIAL_PARALLEL_DECODE_TASKS ;
292+ #[ cfg( target_os = "windows" ) ]
293+ let parallel_decode_tasks = 3usize ;
294+ #[ cfg( not( target_os = "windows" ) ) ]
295+ let parallel_decode_tasks = PARALLEL_DECODE_TASKS ;
223296
224297 let effective_parallel = if frames_decoded < RAMP_UP_FRAME_COUNT {
225- INITIAL_PARALLEL_DECODE_TASKS
298+ initial_parallel_decode_tasks
226299 } else {
227- PARALLEL_DECODE_TASKS
300+ parallel_decode_tasks
228301 } ;
229302
230303 while in_flight. len ( ) < effective_parallel {
@@ -292,7 +365,7 @@ impl Playback {
292365 }
293366
294367 if in_flight. len ( ) < effective_parallel {
295- for behind_offset in 1 ..=PREFETCH_BEHIND {
368+ for behind_offset in 1 ..=prefetch_behind {
296369 if in_flight. len ( ) >= effective_parallel {
297370 break ;
298371 }
@@ -400,7 +473,6 @@ impl Playback {
400473 let mut prefetch_buffer: VecDeque < PrefetchedFrame > =
401474 VecDeque :: with_capacity ( PREFETCH_BUFFER_SIZE ) ;
402475 let mut frame_cache = FrameCache :: new ( FRAME_CACHE_SIZE ) ;
403- let aggressive_skip_threshold = 6u32 ;
404476
405477 let mut total_frames_rendered = 0u64 ;
406478 let mut total_frames_skipped = 0u64 ;
@@ -410,6 +482,9 @@ impl Playback {
410482 let mut last_stats_time = Instant :: now ( ) ;
411483 let stats_interval = Duration :: from_secs ( 2 ) ;
412484
485+ #[ cfg( target_os = "windows" ) ]
486+ let warmup_target_frames = 45usize ;
487+ #[ cfg( not( target_os = "windows" ) ) ]
413488 let warmup_target_frames = 10usize ;
414489 let warmup_after_first_timeout = Duration :: from_millis ( 500 ) ;
415490 let warmup_no_frames_timeout = Duration :: from_secs ( 5 ) ;
@@ -460,6 +535,9 @@ impl Playback {
460535 . make_contiguous ( )
461536 . sort_by_key ( |p| p. frame_number ) ;
462537
538+ #[ cfg( target_os = "windows" ) ]
539+ let _timer_guard = WindowsTimerResolution :: set_high_precision ( ) ;
540+
463541 let start = Instant :: now ( ) ;
464542 let mut cached_project = self . project . borrow ( ) . clone ( ) ;
465543
@@ -491,9 +569,18 @@ impl Playback {
491569 let frame_offset = frame_number. saturating_sub ( self . start_frame_number ) as f64 ;
492570 let next_deadline = start + frame_duration. mul_f64 ( frame_offset) ;
493571
494- tokio:: select! {
495- _ = stop_rx. changed( ) => break ' playback,
496- _ = tokio:: time:: sleep_until( next_deadline) => { }
572+ #[ cfg( target_os = "windows" ) ]
573+ {
574+ if precision_sleep_until ( next_deadline, & mut stop_rx) . await {
575+ break ' playback;
576+ }
577+ }
578+ #[ cfg( not( target_os = "windows" ) ) ]
579+ {
580+ tokio:: select! {
581+ _ = stop_rx. changed( ) => break ' playback,
582+ _ = tokio:: time:: sleep_until( next_deadline) => { }
583+ }
497584 }
498585
499586 if * stop_rx. borrow ( ) {
@@ -505,6 +592,8 @@ impl Playback {
505592 break ;
506593 }
507594
595+ let decode_wait_timeout = Duration :: from_millis ( 100 ) ;
596+
508597 let mut was_cached = false ;
509598
510599 let segment_frames_opt = if let Some ( cached) = frame_cache. get ( frame_number) {
@@ -531,7 +620,7 @@ impl Playback {
531620
532621 if is_in_flight {
533622 let wait_start = Instant :: now ( ) ;
534- let max_wait = Duration :: from_millis ( 100 ) ;
623+ let max_wait = decode_wait_timeout ;
535624 let mut found_frame = None ;
536625
537626 while wait_start. elapsed ( ) < max_wait {
@@ -629,7 +718,7 @@ impl Playback {
629718 guard. insert ( frame_number) ;
630719 }
631720
632- let max_wait = Duration :: from_millis ( 100 ) ;
721+ let max_wait = decode_wait_timeout ;
633722 let data = tokio:: select! {
634723 _ = stop_rx. changed( ) => {
635724 if let Ok ( mut guard) = main_in_flight. write( ) {
@@ -702,13 +791,11 @@ impl Playback {
702791 & zoom_focus_interpolator,
703792 ) ;
704793
705- self . renderer
706- . render_frame (
707- Arc :: unwrap_or_clone ( segment_frames) ,
708- uniforms,
709- segment_media. cursor . clone ( ) ,
710- )
711- . await ;
794+ self . renderer . render_frame (
795+ Arc :: unwrap_or_clone ( segment_frames) ,
796+ uniforms,
797+ segment_media. cursor . clone ( ) ,
798+ ) ;
712799
713800 total_frames_rendered += 1 ;
714801 }
@@ -748,26 +835,25 @@ impl Playback {
748835 if frame_number < expected_frame {
749836 let frames_behind = expected_frame - frame_number;
750837
751- if frames_behind <= aggressive_skip_threshold {
838+ if frames_behind <= 2 {
752839 continue ;
753840 }
754841
755- let skipped = frames_behind. saturating_sub ( 1 ) ;
756- if skipped > 0 {
757- frame_number += skipped;
758- total_frames_skipped += skipped as u64 ;
759-
760- prefetch_buffer. retain ( |p| p. frame_number >= frame_number) ;
761- frame_cache. evict_far_from ( frame_number, MAX_PREFETCH_AHEAD ) ;
762- let _ = frame_request_tx. send ( frame_number) ;
763- let _ = playback_position_tx. send ( frame_number) ;
764- if has_audio
765- && audio_playhead_tx
766- . send ( frame_number as f64 / fps_f64)
767- . is_err ( )
768- {
769- break ' playback;
770- }
842+ let max_skip = 3u32 ;
843+ let skipped = frames_behind. min ( max_skip) ;
844+ frame_number += skipped;
845+ total_frames_skipped += skipped as u64 ;
846+
847+ prefetch_buffer. retain ( |p| p. frame_number >= frame_number) ;
848+ frame_cache. evict_far_from ( frame_number, MAX_PREFETCH_AHEAD ) ;
849+ let _ = frame_request_tx. send ( frame_number) ;
850+ let _ = playback_position_tx. send ( frame_number) ;
851+ if has_audio
852+ && audio_playhead_tx
853+ . send ( frame_number as f64 / fps_f64)
854+ . is_err ( )
855+ {
856+ break ' playback;
771857 }
772858 }
773859 }
0 commit comments