fix(sync): keep probe video on fresh pacing

This commit is contained in:
Brad Stein 2026-04-26 16:11:15 -03:00
parent 3bf53922bd
commit fb323cb5cc
6 changed files with 39 additions and 20 deletions

6
Cargo.lock generated
View File

@ -1642,7 +1642,7 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
[[package]]
name = "lesavka_client"
version = "0.14.3"
version = "0.14.6"
dependencies = [
"anyhow",
"async-stream",
@ -1676,7 +1676,7 @@ dependencies = [
[[package]]
name = "lesavka_common"
version = "0.14.3"
version = "0.14.6"
dependencies = [
"anyhow",
"base64",
@ -1688,7 +1688,7 @@ dependencies = [
[[package]]
name = "lesavka_server"
version = "0.14.3"
version = "0.14.6"
dependencies = [
"anyhow",
"base64",

View File

@ -4,7 +4,7 @@ path = "src/main.rs"
[package]
name = "lesavka_client"
version = "0.14.5"
version = "0.14.6"
edition = "2024"
[dependencies]

View File

@ -1,15 +1,5 @@
use super::*;
pub(super) fn rebase_probe_packet_pts(
pts_rebaser: &crate::live_capture_clock::SourcePtsRebaser,
source_pts_us: u64,
lag_cap: Duration,
) -> u64 {
pts_rebaser
.rebase_with_lag_cap(Some(source_pts_us), 1, Some(lag_cap))
.packet_pts_us
}
fn rebase_probe_audio_packet_pts(
pts_rebaser: &crate::live_capture_clock::DurationPacedSourcePtsRebaser,
source_pts_us: u64,
@ -19,6 +9,17 @@ fn rebase_probe_audio_packet_pts(
pts_rebaser.rebase_with_packet_duration(Some(source_pts_us), packet_duration_us, lag_cap)
}
#[cfg(test)]
pub(super) fn rebase_probe_packet_pts(
pts_rebaser: &crate::live_capture_clock::DurationPacedSourcePtsRebaser,
source_pts_us: u64,
lag_cap: Duration,
) -> u64 {
pts_rebaser
.rebase_with_packet_duration(Some(source_pts_us), 1, lag_cap)
.packet_pts_us
}
pub struct SyncProbeCapture {
pipeline: gst::Pipeline,
running: Arc<AtomicBool>,
@ -164,7 +165,7 @@ fn spawn_video_thread(
queue: FreshPacketQueue<VideoPacket>,
) -> JoinHandle<()> {
thread::spawn(move || {
let pts_rebaser = crate::live_capture_clock::SourcePtsRebaser::default();
let pts_rebaser = crate::live_capture_clock::DurationPacedSourcePtsRebaser::default();
let lag_cap = crate::live_capture_clock::upstream_source_lag_cap();
let dark_frame = build_dark_probe_frame(camera.width as usize, camera.height as usize);
let regular_pulse_frame =
@ -207,14 +208,24 @@ fn spawn_video_thread(
break;
}
if let Some(sample) = sink.try_pull_sample(gst::ClockTime::from_mseconds(250))
if let Some(sample) = freshest_probe_video_sample(&sink)
&& let Some(buffer) = sample.buffer()
&& let Ok(map) = buffer.map_readable()
{
let source_pts_us = buffer.pts().unwrap_or(gst::ClockTime::ZERO).nseconds() / 1_000;
let packet_duration_us = buffer
.duration()
.map(|ts| (ts.nseconds() / 1_000).max(1))
.unwrap_or(frame_step.as_micros().min(u64::MAX as u128) as u64);
let packet = VideoPacket {
id: 2,
pts: rebase_probe_packet_pts(&pts_rebaser, source_pts_us, lag_cap),
pts: pts_rebaser
.rebase_with_packet_duration(
Some(source_pts_us),
packet_duration_us,
lag_cap,
)
.packet_pts_us,
data: map.as_slice().to_vec(),
..Default::default()
};
@ -229,6 +240,14 @@ fn spawn_video_thread(
})
}
fn freshest_probe_video_sample(sink: &gst_app::AppSink) -> Option<gst::Sample> {
let mut newest = sink.try_pull_sample(gst::ClockTime::from_mseconds(250));
while let Some(sample) = sink.try_pull_sample(gst::ClockTime::ZERO) {
newest = Some(sample);
}
newest
}
fn spawn_audio_thread(
schedule: PulseSchedule,
duration: Duration,

View File

@ -143,7 +143,7 @@ fn probe_video_frames_render_distinct_idle_regular_and_marker_patterns() {
#[test]
fn probe_video_pts_are_lag_capped_like_audio() {
let rebaser = crate::live_capture_clock::SourcePtsRebaser::default();
let rebaser = crate::live_capture_clock::DurationPacedSourcePtsRebaser::default();
let _first =
super::runtime::rebase_probe_packet_pts(&rebaser, 1_000_000, Duration::from_millis(2));
std::thread::sleep(Duration::from_millis(8));

View File

@ -1,6 +1,6 @@
[package]
name = "lesavka_common"
version = "0.14.5"
version = "0.14.6"
edition = "2024"
build = "build.rs"

View File

@ -10,7 +10,7 @@ bench = false
[package]
name = "lesavka_server"
version = "0.14.5"
version = "0.14.6"
edition = "2024"
autobins = false