mirror of
https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git
synced 2025-06-05 23:18:55 +00:00
fmp4mux: Split huge drain function into separate functions
This commit is contained in:
parent
4ba4b00235
commit
b63627025e
1 changed files with 438 additions and 360 deletions
|
@ -672,30 +672,29 @@ impl FMP4Mux {
|
|||
))
|
||||
}
|
||||
|
||||
fn drain(
|
||||
#[allow(clippy::type_complexity)]
|
||||
fn drain_buffers(
|
||||
&self,
|
||||
element: &super::FMP4Mux,
|
||||
_element: &super::FMP4Mux,
|
||||
state: &mut State,
|
||||
settings: &Settings,
|
||||
timeout: bool,
|
||||
at_eos: bool,
|
||||
) -> Result<(Option<gst::Caps>, Option<gst::BufferList>), gst::FlowError> {
|
||||
let class = element.class();
|
||||
|
||||
if at_eos {
|
||||
gst::info!(CAT, obj: element, "Draining at EOS");
|
||||
} else if timeout {
|
||||
gst::info!(CAT, obj: element, "Draining at timeout");
|
||||
} else {
|
||||
for stream in &state.streams {
|
||||
if !stream.fragment_filled && !stream.sinkpad.is_eos() {
|
||||
return Ok((None, None));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut drain_buffers = Vec::with_capacity(state.streams.len());
|
||||
let mut streams = Vec::with_capacity(state.streams.len());
|
||||
) -> Result<
|
||||
(
|
||||
Vec<(
|
||||
gst::Caps,
|
||||
Option<super::FragmentTimingInfo>,
|
||||
VecDeque<Buffer>,
|
||||
)>,
|
||||
Option<gst::ClockTime>,
|
||||
Option<gst::ClockTime>,
|
||||
Option<gst::ClockTime>,
|
||||
Option<gst::ClockTime>,
|
||||
),
|
||||
gst::FlowError,
|
||||
> {
|
||||
let mut drained_streams = Vec::with_capacity(state.streams.len());
|
||||
|
||||
let mut min_earliest_pts_position = None;
|
||||
let mut min_earliest_pts = None;
|
||||
|
@ -740,9 +739,10 @@ impl FMP4Mux {
|
|||
"Draining no buffers",
|
||||
);
|
||||
|
||||
streams.push((stream.caps.clone(), None));
|
||||
drain_buffers.push(VecDeque::new());
|
||||
} else {
|
||||
drained_streams.push((stream.caps.clone(), None, VecDeque::new()));
|
||||
continue;
|
||||
}
|
||||
|
||||
let first_gop = gops.first().unwrap();
|
||||
let last_gop = gops.last().unwrap();
|
||||
let earliest_pts = first_gop.earliest_pts;
|
||||
|
@ -810,16 +810,7 @@ impl FMP4Mux {
|
|||
start_dts.unwrap()
|
||||
};
|
||||
|
||||
streams.push((
|
||||
stream.caps.clone(),
|
||||
Some(super::FragmentTimingInfo {
|
||||
start_time,
|
||||
intra_only: stream.intra_only,
|
||||
}),
|
||||
));
|
||||
|
||||
let mut buffers =
|
||||
VecDeque::with_capacity(gops.iter().map(|g| g.buffers.len()).sum());
|
||||
let mut buffers = VecDeque::with_capacity(gops.iter().map(|g| g.buffers.len()).sum());
|
||||
|
||||
for gop in gops {
|
||||
let mut gop_buffers = gop.buffers.into_iter().peekable();
|
||||
|
@ -885,22 +876,42 @@ impl FMP4Mux {
|
|||
});
|
||||
}
|
||||
}
|
||||
drain_buffers.push(buffers);
|
||||
}
|
||||
|
||||
drained_streams.push((
|
||||
stream.caps.clone(),
|
||||
Some(super::FragmentTimingInfo {
|
||||
start_time,
|
||||
intra_only: stream.intra_only,
|
||||
}),
|
||||
buffers,
|
||||
));
|
||||
}
|
||||
|
||||
// Remove all GAP buffers before processing them further
|
||||
for buffers in &mut drain_buffers {
|
||||
buffers.retain(|buf| {
|
||||
!buf.buffer.flags().contains(gst::BufferFlags::GAP)
|
||||
|| !buf.buffer.flags().contains(gst::BufferFlags::DROPPABLE)
|
||||
|| buf.buffer.size() != 0
|
||||
});
|
||||
Ok((
|
||||
drained_streams,
|
||||
min_earliest_pts_position,
|
||||
min_earliest_pts,
|
||||
min_start_dts_position,
|
||||
max_end_pts,
|
||||
))
|
||||
}
|
||||
|
||||
fn preprocess_drained_streams_onvif(
|
||||
&self,
|
||||
element: &super::FMP4Mux,
|
||||
state: &mut State,
|
||||
drained_streams: &mut [(
|
||||
gst::Caps,
|
||||
Option<super::FragmentTimingInfo>,
|
||||
VecDeque<Buffer>,
|
||||
)],
|
||||
) -> Result<Option<gst::ClockTime>, gst::FlowError> {
|
||||
if element.class().as_ref().variant != super::Variant::ONVIF {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let mut max_end_utc_time = None;
|
||||
// For ONVIF, replace all timestamps with timestamps based on UTC times.
|
||||
if class.as_ref().variant == super::Variant::ONVIF {
|
||||
|
||||
let calculate_pts = |buffer: &Buffer| -> gst::ClockTime {
|
||||
let composition_time_offset = buffer.composition_time_offset.unwrap_or(0);
|
||||
if composition_time_offset > 0 {
|
||||
|
@ -918,11 +929,9 @@ impl FMP4Mux {
|
|||
// If this is the first fragment then allow the first buffers to not have a reference
|
||||
// timestamp meta and backdate them
|
||||
if state.stream_header.is_none() {
|
||||
for (idx, drain_buffers) in drain_buffers.iter_mut().enumerate() {
|
||||
let (buffer_idx, utc_time, buffer) = match drain_buffers
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find_map(|(idx, buffer)| {
|
||||
for (idx, (_, _, drain_buffers)) in drained_streams.iter_mut().enumerate() {
|
||||
let (buffer_idx, utc_time, buffer) =
|
||||
match drain_buffers.iter().enumerate().find_map(|(idx, buffer)| {
|
||||
get_utc_time_from_buffer(&buffer.buffer)
|
||||
.map(|timestamp| (idx, timestamp, buffer))
|
||||
}) {
|
||||
|
@ -950,9 +959,7 @@ impl FMP4Mux {
|
|||
};
|
||||
let buffer_utc_time = if buffer_pts_diff >= 0 {
|
||||
utc_time
|
||||
.checked_sub(gst::ClockTime::from_nseconds(
|
||||
buffer_pts_diff as u64,
|
||||
))
|
||||
.checked_sub(gst::ClockTime::from_nseconds(buffer_pts_diff as u64))
|
||||
.unwrap()
|
||||
} else {
|
||||
utc_time
|
||||
|
@ -978,7 +985,7 @@ impl FMP4Mux {
|
|||
if state.start_utc_time.is_none() {
|
||||
let mut start_utc_time = None;
|
||||
|
||||
for (idx, drain_buffers) in drain_buffers.iter().enumerate() {
|
||||
for (idx, (_, _, drain_buffers)) in drained_streams.iter().enumerate() {
|
||||
for buffer in drain_buffers {
|
||||
let utc_time = match get_utc_time_from_buffer(&buffer.buffer) {
|
||||
None => {
|
||||
|
@ -1009,7 +1016,7 @@ impl FMP4Mux {
|
|||
|
||||
// Update all buffer timestamps based on the UTC time and offset to the start UTC time
|
||||
let start_utc_time = state.start_utc_time.unwrap();
|
||||
for (idx, drain_buffers) in drain_buffers.iter_mut().enumerate() {
|
||||
for (idx, (_, timing_info, drain_buffers)) in drained_streams.iter_mut().enumerate() {
|
||||
let mut start_time = None;
|
||||
|
||||
for buffer in drain_buffers.iter_mut() {
|
||||
|
@ -1131,30 +1138,36 @@ impl FMP4Mux {
|
|||
|
||||
if let Some(start_time) = start_time {
|
||||
gst::debug!(CAT, obj: &state.streams[idx].sinkpad, "Fragment starting at UTC time {}", start_time);
|
||||
streams[idx].1.as_mut().unwrap().start_time = start_time;
|
||||
timing_info.as_mut().unwrap().start_time = start_time;
|
||||
} else {
|
||||
assert!(streams[idx].1.is_none());
|
||||
}
|
||||
assert!(timing_info.is_none());
|
||||
}
|
||||
}
|
||||
|
||||
// Create header now if it was not created before and return the caps
|
||||
let mut caps = None;
|
||||
if state.stream_header.is_none() {
|
||||
let (_, new_caps) = self
|
||||
.update_header(element, state, settings, false)?
|
||||
.unwrap();
|
||||
caps = Some(new_caps);
|
||||
Ok(max_end_utc_time)
|
||||
}
|
||||
|
||||
// Interleave buffers according to the settings into a single vec
|
||||
#[allow(clippy::type_complexity)]
|
||||
fn interleave_buffers(
|
||||
&self,
|
||||
_element: &super::FMP4Mux,
|
||||
settings: &Settings,
|
||||
mut drained_streams: Vec<(
|
||||
gst::Caps,
|
||||
Option<super::FragmentTimingInfo>,
|
||||
VecDeque<Buffer>,
|
||||
)>,
|
||||
) -> Result<
|
||||
(
|
||||
Vec<Buffer>,
|
||||
Vec<(gst::Caps, Option<super::FragmentTimingInfo>)>,
|
||||
),
|
||||
gst::FlowError,
|
||||
> {
|
||||
let mut interleaved_buffers =
|
||||
Vec::with_capacity(drain_buffers.iter().map(|bs| bs.len()).sum());
|
||||
while let Some((_idx, bs)) =
|
||||
drain_buffers
|
||||
.iter_mut()
|
||||
.enumerate()
|
||||
.min_by(|(a_idx, a), (b_idx, b)| {
|
||||
Vec::with_capacity(drained_streams.iter().map(|(_, _, bufs)| bufs.len()).sum());
|
||||
while let Some((_idx, (_, _, bufs))) = drained_streams.iter_mut().enumerate().min_by(
|
||||
|(a_idx, (_, _, a)), (b_idx, (_, _, b))| {
|
||||
let (a, b) = match (a.front(), b.front()) {
|
||||
(None, None) => return std::cmp::Ordering::Equal,
|
||||
(None, _) => return std::cmp::Ordering::Greater,
|
||||
|
@ -1166,9 +1179,9 @@ impl FMP4Mux {
|
|||
std::cmp::Ordering::Equal => a_idx.cmp(b_idx),
|
||||
cmp => cmp,
|
||||
}
|
||||
})
|
||||
{
|
||||
let start_time = match bs.front() {
|
||||
},
|
||||
) {
|
||||
let start_time = match bufs.front() {
|
||||
None => {
|
||||
// No more buffers now
|
||||
break;
|
||||
|
@ -1187,7 +1200,7 @@ impl FMP4Mux {
|
|||
.opt_ge(current_end_time.saturating_sub(start_time))
|
||||
.unwrap_or(true)
|
||||
{
|
||||
if let Some(buffer) = bs.pop_front() {
|
||||
if let Some(buffer) = bufs.pop_front() {
|
||||
current_end_time = buffer.timestamp + buffer.duration;
|
||||
dequeued_bytes += buffer.buffer.size() as u64;
|
||||
interleaved_buffers.push(buffer);
|
||||
|
@ -1198,13 +1211,78 @@ impl FMP4Mux {
|
|||
}
|
||||
}
|
||||
|
||||
assert!(drain_buffers.iter().all(|bs| bs.is_empty()));
|
||||
// All buffers should be consumed now
|
||||
assert!(drained_streams.iter().all(|(_, _, bufs)| bufs.is_empty()));
|
||||
|
||||
let streams = drained_streams
|
||||
.into_iter()
|
||||
.map(|(caps, timing_info, _)| (caps, timing_info))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
Ok((interleaved_buffers, streams))
|
||||
}
|
||||
|
||||
fn drain(
|
||||
&self,
|
||||
element: &super::FMP4Mux,
|
||||
state: &mut State,
|
||||
settings: &Settings,
|
||||
timeout: bool,
|
||||
at_eos: bool,
|
||||
) -> Result<(Option<gst::Caps>, Option<gst::BufferList>), gst::FlowError> {
|
||||
if at_eos {
|
||||
gst::info!(CAT, obj: element, "Draining at EOS");
|
||||
} else if timeout {
|
||||
gst::info!(CAT, obj: element, "Draining at timeout");
|
||||
} else {
|
||||
for stream in &state.streams {
|
||||
if !stream.fragment_filled && !stream.sinkpad.is_eos() {
|
||||
return Ok((None, None));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Collect all buffers and their timing information that are to be drained right now.
|
||||
let (
|
||||
mut drained_streams,
|
||||
min_earliest_pts_position,
|
||||
min_earliest_pts,
|
||||
min_start_dts_position,
|
||||
max_end_pts,
|
||||
) = self.drain_buffers(element, state, settings, timeout, at_eos)?;
|
||||
|
||||
// For ONVIF, replace all timestamps with timestamps based on UTC times.
|
||||
let max_end_utc_time =
|
||||
self.preprocess_drained_streams_onvif(element, state, &mut drained_streams)?;
|
||||
|
||||
// Remove all GAP buffers before processing them further
|
||||
for (_, _, buffers) in &mut drained_streams {
|
||||
buffers.retain(|buf| {
|
||||
!buf.buffer.flags().contains(gst::BufferFlags::GAP)
|
||||
|| !buf.buffer.flags().contains(gst::BufferFlags::DROPPABLE)
|
||||
|| buf.buffer.size() != 0
|
||||
});
|
||||
}
|
||||
|
||||
// Create header now if it was not created before and return the caps
|
||||
let mut caps = None;
|
||||
if state.stream_header.is_none() {
|
||||
let (_, new_caps) = self
|
||||
.update_header(element, state, settings, false)?
|
||||
.unwrap();
|
||||
caps = Some(new_caps);
|
||||
}
|
||||
|
||||
// Interleave buffers according to the settings into a single vec
|
||||
let (mut interleaved_buffers, streams) =
|
||||
self.interleave_buffers(element, settings, drained_streams)?;
|
||||
|
||||
let mut buffer_list = None;
|
||||
|
||||
if interleaved_buffers.is_empty() {
|
||||
assert!(timeout || at_eos);
|
||||
} else {
|
||||
// If there are actual buffers to output then create headers as needed and create a
|
||||
// bufferlist for all buffers that have to be output.
|
||||
let min_earliest_pts_position = min_earliest_pts_position.unwrap();
|
||||
let min_earliest_pts = min_earliest_pts.unwrap();
|
||||
let max_end_pts = max_end_pts.unwrap();
|
||||
|
@ -1237,7 +1315,7 @@ impl FMP4Mux {
|
|||
state.sequence_number += 1;
|
||||
let (mut fmp4_fragment_header, moof_offset) =
|
||||
boxes::create_fmp4_fragment_header(super::FragmentHeaderConfiguration {
|
||||
variant: class.as_ref().variant,
|
||||
variant: element.class().as_ref().variant,
|
||||
sequence_number,
|
||||
streams: streams.as_slice(),
|
||||
buffers: interleaved_buffers.as_slice(),
|
||||
|
|
Loading…
Reference in a new issue