fix(sync): keep probe video on fresh pacing
This commit is contained in:
parent
3bf53922bd
commit
fb323cb5cc
6
Cargo.lock
generated
6
Cargo.lock
generated
@ -1642,7 +1642,7 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lesavka_client"
|
name = "lesavka_client"
|
||||||
version = "0.14.3"
|
version = "0.14.6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-stream",
|
"async-stream",
|
||||||
@ -1676,7 +1676,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lesavka_common"
|
name = "lesavka_common"
|
||||||
version = "0.14.3"
|
version = "0.14.6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"base64",
|
"base64",
|
||||||
@ -1688,7 +1688,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lesavka_server"
|
name = "lesavka_server"
|
||||||
version = "0.14.3"
|
version = "0.14.6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"base64",
|
"base64",
|
||||||
|
|||||||
@ -4,7 +4,7 @@ path = "src/main.rs"
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "lesavka_client"
|
name = "lesavka_client"
|
||||||
version = "0.14.5"
|
version = "0.14.6"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|||||||
@ -1,15 +1,5 @@
|
|||||||
use super::*;
|
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(
|
fn rebase_probe_audio_packet_pts(
|
||||||
pts_rebaser: &crate::live_capture_clock::DurationPacedSourcePtsRebaser,
|
pts_rebaser: &crate::live_capture_clock::DurationPacedSourcePtsRebaser,
|
||||||
source_pts_us: u64,
|
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)
|
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 {
|
pub struct SyncProbeCapture {
|
||||||
pipeline: gst::Pipeline,
|
pipeline: gst::Pipeline,
|
||||||
running: Arc<AtomicBool>,
|
running: Arc<AtomicBool>,
|
||||||
@ -164,7 +165,7 @@ fn spawn_video_thread(
|
|||||||
queue: FreshPacketQueue<VideoPacket>,
|
queue: FreshPacketQueue<VideoPacket>,
|
||||||
) -> JoinHandle<()> {
|
) -> JoinHandle<()> {
|
||||||
thread::spawn(move || {
|
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 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 dark_frame = build_dark_probe_frame(camera.width as usize, camera.height as usize);
|
||||||
let regular_pulse_frame =
|
let regular_pulse_frame =
|
||||||
@ -207,14 +208,24 @@ fn spawn_video_thread(
|
|||||||
break;
|
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 Some(buffer) = sample.buffer()
|
||||||
&& let Ok(map) = buffer.map_readable()
|
&& let Ok(map) = buffer.map_readable()
|
||||||
{
|
{
|
||||||
let source_pts_us = buffer.pts().unwrap_or(gst::ClockTime::ZERO).nseconds() / 1_000;
|
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 {
|
let packet = VideoPacket {
|
||||||
id: 2,
|
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(),
|
data: map.as_slice().to_vec(),
|
||||||
..Default::default()
|
..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(
|
fn spawn_audio_thread(
|
||||||
schedule: PulseSchedule,
|
schedule: PulseSchedule,
|
||||||
duration: Duration,
|
duration: Duration,
|
||||||
|
|||||||
@ -143,7 +143,7 @@ fn probe_video_frames_render_distinct_idle_regular_and_marker_patterns() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn probe_video_pts_are_lag_capped_like_audio() {
|
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 =
|
let _first =
|
||||||
super::runtime::rebase_probe_packet_pts(&rebaser, 1_000_000, Duration::from_millis(2));
|
super::runtime::rebase_probe_packet_pts(&rebaser, 1_000_000, Duration::from_millis(2));
|
||||||
std::thread::sleep(Duration::from_millis(8));
|
std::thread::sleep(Duration::from_millis(8));
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "lesavka_common"
|
name = "lesavka_common"
|
||||||
version = "0.14.5"
|
version = "0.14.6"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,7 @@ bench = false
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "lesavka_server"
|
name = "lesavka_server"
|
||||||
version = "0.14.5"
|
version = "0.14.6"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
autobins = false
|
autobins = false
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user