Skip to content

Commit d2743ad

Browse files
authored
remove hardcoded min update interval (#1040)
* remove hardcoded min update interval * manual fps limiter
1 parent d130069 commit d2743ad

File tree

2 files changed

+47
-37
lines changed

2 files changed

+47
-37
lines changed

crates/recording/examples/recording-cli.rs

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -25,20 +25,20 @@ pub async fn main() {
2525

2626
info!("Recording to directory '{}'", dir.path().display());
2727

28-
let camera_info = cap_camera::list_cameras()
29-
.find(|c| c.display_name().contains("NVIDIA"))
30-
.unwrap();
28+
// let camera_info = cap_camera::list_cameras()
29+
// .find(|c| c.display_name().contains("NVIDIA"))
30+
// .unwrap();
3131

32-
let camera_feed = CameraFeed::spawn(CameraFeed::default());
32+
// let camera_feed = CameraFeed::spawn(CameraFeed::default());
3333

34-
camera_feed
35-
.ask(feeds::camera::SetInput {
36-
id: feeds::camera::DeviceOrModelID::from_info(&camera_info),
37-
})
38-
.await
39-
.unwrap()
40-
.await
41-
.unwrap();
34+
// camera_feed
35+
// .ask(feeds::camera::SetInput {
36+
// id: feeds::camera::DeviceOrModelID::from_info(&camera_info),
37+
// })
38+
// .await
39+
// .unwrap()
40+
// .await
41+
// .unwrap();
4242

4343
// let (error_tx, _) = flume::bounded(1);
4444
// let mic_feed = MicrophoneFeed::spawn(MicrophoneFeed::new(error_tx));
@@ -60,16 +60,16 @@ pub async fn main() {
6060

6161
tokio::time::sleep(Duration::from_millis(10)).await;
6262

63-
let (handle, _ready_rx) = studio_recording::Actor::builder(
63+
let (handle, _ready_rx) = instant_recording::Actor::builder(
6464
dir.path().into(),
6565
ScreenCaptureTarget::Display {
6666
id: Display::primary().id(),
6767
},
6868
)
69-
.with_system_audio(true)
70-
.with_camera_feed(std::sync::Arc::new(
71-
camera_feed.ask(feeds::camera::Lock).await.unwrap(),
72-
))
69+
// .with_system_audio(true)
70+
// .with_camera_feed(std::sync::Arc::new(
71+
// camera_feed.ask(feeds::camera::Lock).await.unwrap(),
72+
// ))
7373
.build()
7474
.await
7575
.unwrap();

crates/recording/src/sources/screen_capture/windows.rs

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use ::windows::{
44
Win32::Graphics::Direct3D11::{D3D11_BOX, ID3D11Device},
55
};
66
use cap_fail::fail_err;
7-
use cap_timestamp::PerformanceCounterTimestamp;
7+
use cap_timestamp::{PerformanceCounterTimestamp, Timestamps};
88
use cpal::traits::{DeviceTrait, HostTrait};
99
use kameo::prelude::*;
1010
use scap_ffmpeg::*;
@@ -52,6 +52,9 @@ struct FrameHandler {
5252
last_log: Instant,
5353
frame_events: VecDeque<(Instant, bool)>,
5454
video_tx: Sender<(scap_direct3d::Frame, Timestamp)>,
55+
target_fps: u32,
56+
last_timestamp: Option<Timestamp>,
57+
timestamps: Timestamps,
5558
}
5659

5760
impl Actor for FrameHandler {
@@ -126,14 +129,30 @@ impl Message<NewFrame> for FrameHandler {
126129
msg: NewFrame,
127130
ctx: &mut kameo::prelude::Context<Self, Self::Reply>,
128131
) -> Self::Reply {
129-
let Ok(timestamp) = msg.frame.inner().SystemRelativeTime() else {
132+
let Ok(timestamp) = msg.0.inner().SystemRelativeTime() else {
130133
return;
131134
};
132135

133-
let frame_dropped = match self.video_tx.try_send((
134-
msg.frame,
135-
Timestamp::PerformanceCounter(PerformanceCounterTimestamp::new(timestamp.Duration)),
136-
)) {
136+
let timestamp =
137+
Timestamp::PerformanceCounter(PerformanceCounterTimestamp::new(timestamp.Duration));
138+
139+
// manual FPS limiter
140+
if let Some(last_timestamp) = self.last_timestamp
141+
&& let Some(time_since_last) = timestamp
142+
.duration_since(self.timestamps)
143+
.checked_sub(last_timestamp.duration_since(self.timestamps))
144+
{
145+
let target_interval = 1.0 / self.target_fps as f32;
146+
let tolerance = target_interval * 0.8; // Allow 20% early arrival
147+
148+
if time_since_last.as_secs_f32() < tolerance {
149+
return;
150+
}
151+
}
152+
153+
self.last_timestamp = Some(timestamp);
154+
155+
let frame_dropped = match self.video_tx.try_send((msg.0, timestamp)) {
137156
Err(flume::TrySendError::Disconnected(_)) => {
138157
warn!("Pipeline disconnected");
139158
let _ = ctx.actor_ref().stop_gracefully().await;
@@ -232,6 +251,9 @@ impl PipelineSourceTask for ScreenCaptureSource<Direct3DCapture> {
232251
frames_dropped: Default::default(),
233252
last_cleanup: Instant::now(),
234253
last_log: Instant::now(),
254+
target_fps: config.fps,
255+
last_timestamp: None,
256+
timestamps: Timestamps::now(),
235257
});
236258

237259
let mut settings = scap_direct3d::Settings {
@@ -249,7 +271,6 @@ impl PipelineSourceTask for ScreenCaptureSource<Direct3DCapture> {
249271
back: 1,
250272
}
251273
}),
252-
min_update_interval: Some(Duration::from_millis(16)),
253274
..Default::default()
254275
};
255276

@@ -380,10 +401,7 @@ pub enum StartCapturingError {
380401
StartCapturer(::windows::core::Error),
381402
}
382403

383-
pub struct NewFrame {
384-
pub frame: scap_direct3d::Frame,
385-
pub display_time: SystemTime,
386-
}
404+
pub struct NewFrame(pub scap_direct3d::Frame);
387405

388406
impl Message<StartCapturing> for ScreenCaptureActor {
389407
type Reply = Result<(), StartCapturingError>;
@@ -410,15 +428,7 @@ impl Message<StartCapturing> for ScreenCaptureActor {
410428
msg.target,
411429
msg.settings,
412430
move |frame| {
413-
let display_time = SystemTime::now();
414-
415-
let _ = msg
416-
.frame_handler
417-
.tell(NewFrame {
418-
frame,
419-
display_time,
420-
})
421-
.try_send();
431+
let _ = msg.frame_handler.tell(NewFrame(frame)).try_send();
422432

423433
Ok(())
424434
},

0 commit comments

Comments
 (0)