@@ -17,6 +17,10 @@ use pipewire::{
1717} ;
1818use spa_sys:: { spa_format_video_raw_parse, spa_video_info_raw} ;
1919
20+ use crate :: {
21+ buffer,
22+ wayland:: { CaptureSource , DmabufHelper , Session , WaylandHelper } ,
23+ } ;
2024use std:: {
2125 collections:: HashMap ,
2226 ffi:: c_void,
@@ -30,15 +34,9 @@ use wayland_client::{
3034 protocol:: { wl_buffer, wl_output, wl_shm} ,
3135 WEnum ,
3236} ;
33- use wayland_protocols:: wp:: input_timestamps:: zv1:: client:: zwp_input_timestamps_v1;
34-
35- use crate :: {
36- buffer,
37- wayland:: { CaptureSource , DmabufHelper , Session , WaylandHelper } ,
38- } ;
3937
4038const TIMESPEC_NSEC_PER_SEC : u32 = 1_000_000_000 ;
41- const FPS_MEASURE_PERIOD_SEC : u64 = 5 ;
39+ const FPS_MEASURE_PERIOD_SEC : f64 = 5. ;
4240
4341pub struct ScreencastThread {
4442 node_id : u32 ,
@@ -87,6 +85,7 @@ struct FPSLimit {
8785 frame_last_time : Instant ,
8886 fps_last_time : Instant ,
8987 fps_frame_count : u64 ,
88+ delay_til_next_frame_ns : u64 ,
9089}
9190
9291impl FPSLimit {
@@ -95,40 +94,46 @@ impl FPSLimit {
9594 frame_last_time : Instant :: now ( ) ,
9695 fps_last_time : Instant :: now ( ) ,
9796 fps_frame_count : 0 ,
97+ delay_til_next_frame_ns : 0 ,
9898 }
9999 }
100100
101- fn fps_limit_measure_start ( & mut self ) {
101+ fn fps_limit_measure_start ( & mut self , max_fps : u32 ) {
102+ if max_fps <= 0 {
103+ return ;
104+ }
105+
102106 self . frame_last_time = Instant :: now ( ) ;
103107 }
104108
105109 fn measure_fps ( & mut self ) {
106110 let now = Instant :: now ( ) ;
107111 self . fps_frame_count += 1 ;
108- let elapsed_sec = ( now - self . fps_last_time ) . as_secs ( ) ;
112+ let elapsed_sec = ( now - self . fps_last_time ) . as_secs_f64 ( ) ;
109113 if elapsed_sec < FPS_MEASURE_PERIOD_SEC {
110114 return ;
111115 }
112116
113- let avg_frames_per_sec = self . fps_frame_count / elapsed_sec;
114- println ! (
115- "fps_limit: average FPS in the last {} seconds: {}" ,
116- avg_frames_per_sec, elapsed_sec
117+ let avg_frames_per_sec = self . fps_frame_count as f64 / elapsed_sec;
118+ log:: info!(
119+ "fps_limit: average FPS in the last {:.2} seconds: {:.2}" ,
120+ avg_frames_per_sec,
121+ elapsed_sec
117122 ) ;
118123 self . fps_frame_count = 0 ;
119124 self . fps_last_time = now;
120125 }
121126
122- fn wait_for_next_frame ( & mut self , max_fps : u32 ) {
127+ fn fps_limit_measure_end ( & mut self , max_fps : u32 ) {
128+ if max_fps <= 0 {
129+ self . delay_til_next_frame_ns = 0 ;
130+ return ;
131+ }
123132 self . measure_fps ( ) ;
124133
125134 let elapsed_ns = self . frame_last_time . elapsed ( ) . as_nanos ( ) ;
126135 let target_ns = ( TIMESPEC_NSEC_PER_SEC / max_fps) as u128 ;
127- if target_ns > elapsed_ns {
128- let delay_ns = ( target_ns - elapsed_ns) as u64 ;
129- // println!("Time til next: {}ns", delay_ns);
130- std:: thread:: sleep ( Duration :: from_nanos ( delay_ns) ) ;
131- }
136+ self . delay_til_next_frame_ns = target_ns. saturating_sub ( elapsed_ns) as u64 ;
132137 }
133138}
134139
@@ -359,12 +364,14 @@ impl StreamData {
359364 fn process ( & mut self , stream : & StreamRef ) {
360365 let buffer = unsafe { stream. dequeue_raw_buffer ( ) } ;
361366 if !buffer. is_null ( ) {
362- // Only wait if it not the first frame
363- if self . seq > 0 {
364- // Maybe there's a better way, e.g., using an event loop to wait and get a new frame
365- self . fps_limit . wait_for_next_frame ( self . framerate ) ;
367+ if self . fps_limit . delay_til_next_frame_ns != 0 {
368+ // log::info!(
369+ // "fps_limit: wait {}ns til next frame",
370+ // self.fps_limit.delay_til_next_frame_ns
371+ // );
372+ std:: thread:: sleep ( Duration :: from_nanos ( self . fps_limit . delay_til_next_frame_ns ) ) ;
366373 }
367-
374+ self . fps_limit . fps_limit_measure_start ( self . framerate ) ;
368375 let wl_buffer = unsafe { & * ( ( * buffer) . user_data as * const wl_buffer:: WlBuffer ) } ;
369376 let full_damage = & [ Rect {
370377 x : 0 ,
@@ -403,7 +410,7 @@ impl StreamData {
403410 }
404411 }
405412 unsafe { stream. queue_raw_buffer ( buffer) } ;
406- self . fps_limit . fps_limit_measure_start ( ) ;
413+ self . fps_limit . fps_limit_measure_end ( self . framerate ) ;
407414 self . seq += 1 ;
408415 }
409416 }
@@ -429,14 +436,25 @@ fn start_stream(
429436
430437 let ( node_id_tx, node_id_rx) = oneshot:: channel ( ) ;
431438
439+ // Gets framerate from screen's frame rate, and default to 0 if not available
440+ let framerate = match & capture_source {
441+ CaptureSource :: Output ( output) => wayland_helper
442+ . output_info ( output)
443+ . and_then ( |info| info. modes . into_iter ( ) . find ( |mode| mode. current ) )
444+ . map_or ( 0 , |mode| mode. refresh_rate as u32 / 1000 ) ,
445+ CaptureSource :: Toplevel ( foreign_toplevel) => wayland_helper
446+ . output_info_toplevel ( foreign_toplevel)
447+ . and_then ( |info| info. modes . into_iter ( ) . find ( |mode| mode. current ) )
448+ . map_or ( 0 , |mode| mode. refresh_rate as u32 / 1000 ) ,
449+ _ => 0 ,
450+ } ;
451+
432452 let ( width, height) =
433453 match block_on ( wayland_helper. capture_source_shm ( capture_source. clone ( ) , overlay_cursor) ) {
434454 Some ( frame) => ( frame. width , frame. height ) ,
435455 None => return Err ( anyhow:: anyhow!( "failed to use shm capture to get size" ) ) ,
436456 } ;
437457
438- let framerate = 60 ; // Default framerate. XXX is there a better way?
439-
440458 let dmabuf_helper = wayland_helper. dmabuf ( ) ;
441459
442460 let stream = pipewire:: stream:: Stream :: new (
0 commit comments