mirror of
https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git
synced 2024-06-26 10:00:36 +00:00
livesync: Split fallback_duration into in_ and out_duration
Make it independent of the `latency`; this was inconsistent anyway, where the default latency of zero got you a fallback duration of 100 ms and something else got you half the latency. Maintain a separate duration for the `in` and the `out` side so we change the duration of repeat buffers after a caps change, not just before. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/1387>
This commit is contained in:
parent
dafdb48ff6
commit
72506b94e3
|
@ -36,6 +36,16 @@ fn audio_info_from_caps(
|
||||||
.transpose()
|
.transpose()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn duration_from_caps(caps: &gst::CapsRef) -> Option<gst::ClockTime> {
|
||||||
|
caps.structure(0)
|
||||||
|
.filter(|s| s.name().starts_with("video/"))
|
||||||
|
.and_then(|s| s.get::<gst::Fraction>("framerate").ok())
|
||||||
|
.filter(|framerate| framerate.denom() > 0 && framerate.numer() > 0)
|
||||||
|
.and_then(|framerate| {
|
||||||
|
gst::ClockTime::SECOND.mul_div_round(framerate.denom() as u64, framerate.numer() as u64)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
enum BufferLateness {
|
enum BufferLateness {
|
||||||
OnTime,
|
OnTime,
|
||||||
|
@ -82,9 +92,6 @@ struct State {
|
||||||
/// Latency reported by upstream
|
/// Latency reported by upstream
|
||||||
upstream_latency: Option<gst::ClockTime>,
|
upstream_latency: Option<gst::ClockTime>,
|
||||||
|
|
||||||
/// Duration we assume for buffers without one
|
|
||||||
fallback_duration: gst::ClockTime,
|
|
||||||
|
|
||||||
/// Whether we're in PLAYING state
|
/// Whether we're in PLAYING state
|
||||||
playing: bool,
|
playing: bool,
|
||||||
|
|
||||||
|
@ -118,6 +125,12 @@ struct State {
|
||||||
/// Audio format of our srcpad
|
/// Audio format of our srcpad
|
||||||
out_audio_info: Option<gst_audio::AudioInfo>,
|
out_audio_info: Option<gst_audio::AudioInfo>,
|
||||||
|
|
||||||
|
/// Duration from caps on our sinkpad
|
||||||
|
in_duration: Option<gst::ClockTime>,
|
||||||
|
|
||||||
|
/// Duration from caps on our srcpad
|
||||||
|
out_duration: Option<gst::ClockTime>,
|
||||||
|
|
||||||
/// Queue between sinkpad and srcpad
|
/// Queue between sinkpad and srcpad
|
||||||
queue: VecDeque<Item>,
|
queue: VecDeque<Item>,
|
||||||
|
|
||||||
|
@ -159,7 +172,9 @@ const PROP_OUT: &str = "out";
|
||||||
const PROP_DUPLICATE: &str = "duplicate";
|
const PROP_DUPLICATE: &str = "duplicate";
|
||||||
|
|
||||||
const DEFAULT_LATENCY: gst::ClockTime = gst::ClockTime::ZERO;
|
const DEFAULT_LATENCY: gst::ClockTime = gst::ClockTime::ZERO;
|
||||||
|
const MINIMUM_DURATION: gst::ClockTime = gst::ClockTime::from_mseconds(8);
|
||||||
const DEFAULT_DURATION: gst::ClockTime = gst::ClockTime::from_mseconds(100);
|
const DEFAULT_DURATION: gst::ClockTime = gst::ClockTime::from_mseconds(100);
|
||||||
|
const MAXIMUM_DURATION: gst::ClockTime = gst::ClockTime::from_seconds(10);
|
||||||
const MINIMUM_LATE_THRESHOLD: gst::ClockTime = gst::ClockTime::ZERO;
|
const MINIMUM_LATE_THRESHOLD: gst::ClockTime = gst::ClockTime::ZERO;
|
||||||
const DEFAULT_LATE_THRESHOLD: Option<gst::ClockTime> = Some(gst::ClockTime::from_seconds(2));
|
const DEFAULT_LATE_THRESHOLD: Option<gst::ClockTime> = Some(gst::ClockTime::from_seconds(2));
|
||||||
|
|
||||||
|
@ -170,7 +185,6 @@ impl Default for State {
|
||||||
late_threshold: DEFAULT_LATE_THRESHOLD,
|
late_threshold: DEFAULT_LATE_THRESHOLD,
|
||||||
single_segment: false,
|
single_segment: false,
|
||||||
upstream_latency: None,
|
upstream_latency: None,
|
||||||
fallback_duration: DEFAULT_DURATION,
|
|
||||||
playing: false,
|
playing: false,
|
||||||
eos: false,
|
eos: false,
|
||||||
srcresult: Err(gst::FlowError::Flushing),
|
srcresult: Err(gst::FlowError::Flushing),
|
||||||
|
@ -180,6 +194,8 @@ impl Default for State {
|
||||||
out_segment: None,
|
out_segment: None,
|
||||||
in_caps: None,
|
in_caps: None,
|
||||||
pending_caps: None,
|
pending_caps: None,
|
||||||
|
in_duration: None,
|
||||||
|
out_duration: None,
|
||||||
in_audio_info: None,
|
in_audio_info: None,
|
||||||
out_audio_info: None,
|
out_audio_info: None,
|
||||||
queue: VecDeque::with_capacity(32),
|
queue: VecDeque::with_capacity(32),
|
||||||
|
@ -348,7 +364,6 @@ impl ObjectImpl for LiveSync {
|
||||||
match pspec.name() {
|
match pspec.name() {
|
||||||
PROP_LATENCY => {
|
PROP_LATENCY => {
|
||||||
state.latency = value.get().unwrap();
|
state.latency = value.get().unwrap();
|
||||||
state.update_fallback_duration();
|
|
||||||
let _ = self.obj().post_message(gst::message::Latency::new());
|
let _ = self.obj().post_message(gst::message::Latency::new());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -490,31 +505,6 @@ impl State {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_fallback_duration(&mut self) {
|
|
||||||
self.fallback_duration = self
|
|
||||||
// First, try 1/framerate from the caps
|
|
||||||
.in_caps
|
|
||||||
.as_ref()
|
|
||||||
.and_then(|c| c.structure(0))
|
|
||||||
.filter(|s| s.name().starts_with("video/"))
|
|
||||||
.and_then(|s| s.get::<gst::Fraction>("framerate").ok())
|
|
||||||
.filter(|framerate| framerate.denom() > 0 && framerate.numer() > 0)
|
|
||||||
.and_then(|framerate| {
|
|
||||||
gst::ClockTime::SECOND
|
|
||||||
.mul_div_round(framerate.denom() as u64, framerate.numer() as u64)
|
|
||||||
})
|
|
||||||
.filter(|&dur| dur > 8.mseconds() && dur < 10.seconds())
|
|
||||||
// Otherwise, half the configured latency
|
|
||||||
.or_else(|| Some(self.latency / 2))
|
|
||||||
// In any case, don't allow a zero duration
|
|
||||||
.filter(|&dur| dur > gst::ClockTime::ZERO)
|
|
||||||
// Safe default
|
|
||||||
.unwrap_or(DEFAULT_DURATION);
|
|
||||||
|
|
||||||
// Change the duration of the next duplicate buffer
|
|
||||||
self.out_buffer_duplicate = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pending_events(&self) -> bool {
|
fn pending_events(&self) -> bool {
|
||||||
self.pending_caps.is_some() || self.pending_segment.is_some()
|
self.pending_caps.is_some() || self.pending_segment.is_some()
|
||||||
}
|
}
|
||||||
|
@ -585,8 +575,8 @@ impl LiveSync {
|
||||||
state.in_segment = None;
|
state.in_segment = None;
|
||||||
state.in_caps = None;
|
state.in_caps = None;
|
||||||
state.in_audio_info = None;
|
state.in_audio_info = None;
|
||||||
|
state.in_duration = None;
|
||||||
state.in_timestamp = None;
|
state.in_timestamp = None;
|
||||||
state.update_fallback_duration();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn src_reset(&self, state: &mut State) {
|
fn src_reset(&self, state: &mut State) {
|
||||||
|
@ -594,6 +584,7 @@ impl LiveSync {
|
||||||
state.out_segment = None;
|
state.out_segment = None;
|
||||||
state.pending_caps = None;
|
state.pending_caps = None;
|
||||||
state.out_audio_info = None;
|
state.out_audio_info = None;
|
||||||
|
state.out_duration = None;
|
||||||
state.out_buffer = None;
|
state.out_buffer = None;
|
||||||
state.out_buffer_duplicate = false;
|
state.out_buffer_duplicate = false;
|
||||||
state.out_timestamp = None;
|
state.out_timestamp = None;
|
||||||
|
@ -671,10 +662,12 @@ impl LiveSync {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let duration = duration_from_caps(&caps);
|
||||||
|
|
||||||
let mut state = self.state.lock();
|
let mut state = self.state.lock();
|
||||||
state.in_caps = Some(caps);
|
state.in_caps = Some(caps);
|
||||||
state.in_audio_info = audio_info;
|
state.in_audio_info = audio_info;
|
||||||
state.update_fallback_duration();
|
state.in_duration = duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
gst::EventView::Gap(_) => {
|
gst::EventView::Gap(_) => {
|
||||||
|
@ -894,13 +887,25 @@ impl LiveSync {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
gst::debug!(CAT, imp: self, "Incoming buffer without duration");
|
gst::debug!(
|
||||||
|
CAT,
|
||||||
|
imp: self,
|
||||||
|
"Patching incoming buffer with duration {calc_duration}"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
buf_mut.set_duration(calc_duration);
|
buf_mut.set_duration(calc_duration);
|
||||||
} else if buf_mut.duration().is_none() {
|
} else if buf_mut.duration().is_none() {
|
||||||
gst::debug!(CAT, imp: self, "Incoming buffer without duration");
|
let duration = state.in_duration.map_or(DEFAULT_DURATION, |dur| {
|
||||||
buf_mut.set_duration(state.fallback_duration);
|
dur.clamp(MINIMUM_DURATION, MAXIMUM_DURATION)
|
||||||
|
});
|
||||||
|
|
||||||
|
gst::debug!(
|
||||||
|
CAT,
|
||||||
|
imp: self,
|
||||||
|
"Patching incoming buffer with duration {duration}"
|
||||||
|
);
|
||||||
|
buf_mut.set_duration(duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
// At this stage we should really really have a segment
|
// At this stage we should really really have a segment
|
||||||
|
@ -1077,7 +1082,6 @@ impl LiveSync {
|
||||||
|
|
||||||
gst::EventView::Caps(e) => {
|
gst::EventView::Caps(e) => {
|
||||||
state.pending_caps = Some(e.caps_owned());
|
state.pending_caps = Some(e.caps_owned());
|
||||||
state.update_fallback_duration();
|
|
||||||
push = false;
|
push = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1164,6 +1168,7 @@ impl LiveSync {
|
||||||
state.srcresult?;
|
state.srcresult?;
|
||||||
|
|
||||||
state.out_audio_info = audio_info_from_caps(&caps).unwrap();
|
state.out_audio_info = audio_info_from_caps(&caps).unwrap();
|
||||||
|
state.out_duration = duration_from_caps(&caps);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(segment) = segment {
|
if let Some(segment) = segment {
|
||||||
|
@ -1317,7 +1322,9 @@ impl LiveSync {
|
||||||
let buffer = out_buffer.make_mut();
|
let buffer = out_buffer.make_mut();
|
||||||
|
|
||||||
if !duplicate {
|
if !duplicate {
|
||||||
let duration = state.fallback_duration;
|
let duration = state.out_duration.map_or(DEFAULT_DURATION, |dur| {
|
||||||
|
dur.clamp(MINIMUM_DURATION, MAXIMUM_DURATION)
|
||||||
|
});
|
||||||
|
|
||||||
if let Some(audio_info) = &state.out_audio_info {
|
if let Some(audio_info) = &state.out_audio_info {
|
||||||
let Some(size) = audio_info
|
let Some(size) = audio_info
|
||||||
|
|
Loading…
Reference in a new issue