Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 17 additions & 17 deletions crates/recording/examples/recording-cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,20 @@ pub async fn main() {

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

let camera_info = cap_camera::list_cameras()
.find(|c| c.display_name().contains("NVIDIA"))
.unwrap();
// let camera_info = cap_camera::list_cameras()
// .find(|c| c.display_name().contains("NVIDIA"))
// .unwrap();

let camera_feed = CameraFeed::spawn(CameraFeed::default());
// let camera_feed = CameraFeed::spawn(CameraFeed::default());

camera_feed
.ask(feeds::camera::SetInput {
id: feeds::camera::DeviceOrModelID::from_info(&camera_info),
})
.await
.unwrap()
.await
.unwrap();
// camera_feed
// .ask(feeds::camera::SetInput {
// id: feeds::camera::DeviceOrModelID::from_info(&camera_info),
// })
// .await
// .unwrap()
// .await
// .unwrap();

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

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

let (handle, _ready_rx) = studio_recording::Actor::builder(
let (handle, _ready_rx) = instant_recording::Actor::builder(
dir.path().into(),
ScreenCaptureTarget::Display {
id: Display::primary().id(),
},
)
.with_system_audio(true)
.with_camera_feed(std::sync::Arc::new(
camera_feed.ask(feeds::camera::Lock).await.unwrap(),
))
// .with_system_audio(true)
// .with_camera_feed(std::sync::Arc::new(
// camera_feed.ask(feeds::camera::Lock).await.unwrap(),
// ))
.build()
.await
.unwrap();
Expand Down
50 changes: 30 additions & 20 deletions crates/recording/src/sources/screen_capture/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use ::windows::{
Win32::Graphics::Direct3D11::{D3D11_BOX, ID3D11Device},
};
use cap_fail::fail_err;
use cap_timestamp::PerformanceCounterTimestamp;
use cap_timestamp::{PerformanceCounterTimestamp, Timestamps};
use cpal::traits::{DeviceTrait, HostTrait};
use kameo::prelude::*;
use scap_ffmpeg::*;
Expand Down Expand Up @@ -52,6 +52,9 @@ struct FrameHandler {
last_log: Instant,
frame_events: VecDeque<(Instant, bool)>,
video_tx: Sender<(scap_direct3d::Frame, Timestamp)>,
target_fps: u32,
last_timestamp: Option<Timestamp>,
timestamps: Timestamps,
}

impl Actor for FrameHandler {
Expand Down Expand Up @@ -126,14 +129,30 @@ impl Message<NewFrame> for FrameHandler {
msg: NewFrame,
ctx: &mut kameo::prelude::Context<Self, Self::Reply>,
) -> Self::Reply {
let Ok(timestamp) = msg.frame.inner().SystemRelativeTime() else {
let Ok(timestamp) = msg.0.inner().SystemRelativeTime() else {
return;
};

let frame_dropped = match self.video_tx.try_send((
msg.frame,
Timestamp::PerformanceCounter(PerformanceCounterTimestamp::new(timestamp.Duration)),
)) {
let timestamp =
Timestamp::PerformanceCounter(PerformanceCounterTimestamp::new(timestamp.Duration));

// manual FPS limiter
if let Some(last_timestamp) = self.last_timestamp
&& let Some(time_since_last) = timestamp
.duration_since(self.timestamps)
.checked_sub(last_timestamp.duration_since(self.timestamps))
{
let target_interval = 1.0 / self.target_fps as f32;
let tolerance = target_interval * 0.8; // Allow 20% early arrival

if time_since_last.as_secs_f32() < tolerance {
return;
}
}

self.last_timestamp = Some(timestamp);

let frame_dropped = match self.video_tx.try_send((msg.0, timestamp)) {
Err(flume::TrySendError::Disconnected(_)) => {
warn!("Pipeline disconnected");
let _ = ctx.actor_ref().stop_gracefully().await;
Expand Down Expand Up @@ -232,6 +251,9 @@ impl PipelineSourceTask for ScreenCaptureSource<Direct3DCapture> {
frames_dropped: Default::default(),
last_cleanup: Instant::now(),
last_log: Instant::now(),
target_fps: config.fps,
last_timestamp: None,
timestamps: Timestamps::now(),
});

let mut settings = scap_direct3d::Settings {
Expand All @@ -249,7 +271,6 @@ impl PipelineSourceTask for ScreenCaptureSource<Direct3DCapture> {
back: 1,
}
}),
min_update_interval: Some(Duration::from_millis(16)),
..Default::default()
};

Expand Down Expand Up @@ -380,10 +401,7 @@ pub enum StartCapturingError {
StartCapturer(::windows::core::Error),
}

pub struct NewFrame {
pub frame: scap_direct3d::Frame,
pub display_time: SystemTime,
}
pub struct NewFrame(pub scap_direct3d::Frame);

impl Message<StartCapturing> for ScreenCaptureActor {
type Reply = Result<(), StartCapturingError>;
Expand All @@ -410,15 +428,7 @@ impl Message<StartCapturing> for ScreenCaptureActor {
msg.target,
msg.settings,
move |frame| {
let display_time = SystemTime::now();

let _ = msg
.frame_handler
.tell(NewFrame {
frame,
display_time,
})
.try_send();
let _ = msg.frame_handler.tell(NewFrame(frame)).try_send();

Ok(())
},
Expand Down
Loading