fmp4mux: Implement handling of GAP events

This commit is contained in:
Sebastian Dröge 2022-05-17 15:11:32 +03:00
parent 987e4efc02
commit d7bd4c1c93
2 changed files with 239 additions and 5 deletions

View file

@ -680,6 +680,13 @@ impl FMP4Mux {
if interleaved_buffers.is_empty() {
assert!(timeout || at_eos);
} else {
// Remove all GAP buffers before writing them out
interleaved_buffers.retain(|buf| {
!buf.buffer.flags().contains(gst::BufferFlags::GAP)
|| !buf.buffer.flags().contains(gst::BufferFlags::DROPPABLE)
|| buf.buffer.size() != 0
});
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();
@ -1284,11 +1291,6 @@ impl AggregatorImpl for FMP4Mux {
self.parent_sink_event(aggregator, aggregator_pad, event)
}
EventView::Gap(_ev) => {
// TODO: queue up and check if draining is needed now
// i.e. make the last sample much longer
true
}
_ => self.parent_sink_event(aggregator, aggregator_pad, event),
}
}

View file

@ -644,3 +644,235 @@ fn test_live_timeout() {
let ev = h1.pull_event().unwrap();
assert_eq!(ev.type_(), gst::EventType::Eos);
}
#[test]
fn test_gap_events() {
init();
let mut h1 = gst_check::Harness::with_padnames("isofmp4mux", Some("sink_0"), Some("src"));
let mut h2 = gst_check::Harness::with_element(&h1.element().unwrap(), Some("sink_1"), None);
// 5s fragment duration
h1.element()
.unwrap()
.set_property("fragment-duration", gst::ClockTime::from_seconds(5));
h1.set_src_caps(
gst::Caps::builder("video/x-h264")
.field("width", 1920i32)
.field("height", 1080i32)
.field("framerate", gst::Fraction::new(30, 1))
.field("stream-format", "avc")
.field("alignment", "au")
.field("codec_data", gst::Buffer::with_size(1).unwrap())
.build(),
);
h1.play();
h2.set_src_caps(
gst::Caps::builder("audio/mpeg")
.field("mpegversion", 4i32)
.field("channels", 1i32)
.field("rate", 44100i32)
.field("stream-format", "raw")
.field("base-profile", "lc")
.field("profile", "lc")
.field("level", "2")
.field(
"codec_data",
gst::Buffer::from_slice([0x12, 0x08, 0x56, 0xe5, 0x00]),
)
.build(),
);
h2.play();
let output_offset = gst::ClockTime::from_seconds(60 * 60 * 1000);
// Push 7 buffers of 1s each, 1st and last buffer without DELTA_UNIT flag
for i in 0..7 {
let mut buffer = gst::Buffer::with_size(1).unwrap();
{
let buffer = buffer.get_mut().unwrap();
buffer.set_pts(gst::ClockTime::from_seconds(i));
buffer.set_dts(gst::ClockTime::from_seconds(i));
buffer.set_duration(gst::ClockTime::SECOND);
if i != 0 && i != 5 {
buffer.set_flags(gst::BufferFlags::DELTA_UNIT);
}
}
assert_eq!(h1.push(buffer), Ok(gst::FlowSuccess::Ok));
// Replace buffer 3 and 6 with a gap event
if i == 3 || i == 6 {
let ev = gst::event::Gap::builder(gst::ClockTime::from_seconds(i))
.duration(gst::ClockTime::SECOND)
.build();
assert!(h2.push_event(ev));
} else {
let mut buffer = gst::Buffer::with_size(1).unwrap();
{
let buffer = buffer.get_mut().unwrap();
buffer.set_pts(gst::ClockTime::from_seconds(i));
buffer.set_dts(gst::ClockTime::from_seconds(i));
buffer.set_duration(gst::ClockTime::SECOND);
}
assert_eq!(h2.push(buffer), Ok(gst::FlowSuccess::Ok));
}
if i == 2 {
let ev = loop {
let ev = h1.pull_upstream_event().unwrap();
if ev.type_() != gst::EventType::Reconfigure
&& ev.type_() != gst::EventType::Latency
{
break ev;
}
};
assert_eq!(ev.type_(), gst::EventType::CustomUpstream);
assert_eq!(
gst_video::UpstreamForceKeyUnitEvent::parse(&ev).unwrap(),
gst_video::UpstreamForceKeyUnitEvent {
running_time: Some(gst::ClockTime::from_seconds(5)),
all_headers: true,
count: 0
}
);
let ev = loop {
let ev = h2.pull_upstream_event().unwrap();
if ev.type_() != gst::EventType::Reconfigure
&& ev.type_() != gst::EventType::Latency
{
break ev;
}
};
assert_eq!(ev.type_(), gst::EventType::CustomUpstream);
assert_eq!(
gst_video::UpstreamForceKeyUnitEvent::parse(&ev).unwrap(),
gst_video::UpstreamForceKeyUnitEvent {
running_time: Some(gst::ClockTime::from_seconds(5)),
all_headers: true,
count: 0
}
);
}
}
let header = h1.pull().unwrap();
assert_eq!(
header.flags(),
gst::BufferFlags::HEADER | gst::BufferFlags::DISCONT
);
assert_eq!(header.pts(), Some(gst::ClockTime::ZERO + output_offset));
assert_eq!(header.dts(), Some(gst::ClockTime::ZERO + output_offset));
let fragment_header = h1.pull().unwrap();
assert_eq!(fragment_header.flags(), gst::BufferFlags::HEADER);
assert_eq!(
fragment_header.pts(),
Some(gst::ClockTime::ZERO + output_offset)
);
assert_eq!(
fragment_header.dts(),
Some(gst::ClockTime::ZERO + output_offset)
);
assert_eq!(
fragment_header.duration(),
Some(gst::ClockTime::from_seconds(5))
);
for i in 0..5 {
for j in 0..2 {
// Skip gap events that don't result in buffers
if j == 1 && i == 3 {
continue;
}
let buffer = h1.pull().unwrap();
if i == 4 && j == 1 {
assert_eq!(
buffer.flags(),
gst::BufferFlags::DELTA_UNIT | gst::BufferFlags::MARKER
);
} else {
assert_eq!(buffer.flags(), gst::BufferFlags::DELTA_UNIT);
}
assert_eq!(
buffer.pts(),
Some(gst::ClockTime::from_seconds(i) + output_offset)
);
if j == 0 {
assert_eq!(
buffer.dts(),
Some(gst::ClockTime::from_seconds(i) + output_offset)
);
} else {
assert!(buffer.dts().is_none());
}
assert_eq!(buffer.duration(), Some(gst::ClockTime::SECOND));
}
}
h1.push_event(gst::event::Eos::new());
h2.push_event(gst::event::Eos::new());
let fragment_header = h1.pull().unwrap();
assert_eq!(fragment_header.flags(), gst::BufferFlags::HEADER);
assert_eq!(
fragment_header.pts(),
Some(gst::ClockTime::from_seconds(5) + output_offset)
);
assert_eq!(
fragment_header.dts(),
Some(gst::ClockTime::from_seconds(5) + output_offset)
);
assert_eq!(
fragment_header.duration(),
Some(gst::ClockTime::from_seconds(2))
);
for i in 5..7 {
for j in 0..2 {
// Skip gap events that don't result in buffers
if j == 1 && i == 6 {
continue;
}
let buffer = h1.pull().unwrap();
if i == 6 && j == 0 {
assert_eq!(
buffer.flags(),
gst::BufferFlags::DELTA_UNIT | gst::BufferFlags::MARKER
);
} else {
assert_eq!(buffer.flags(), gst::BufferFlags::DELTA_UNIT);
}
assert_eq!(
buffer.pts(),
Some(gst::ClockTime::from_seconds(i) + output_offset)
);
if j == 0 {
assert_eq!(
buffer.dts(),
Some(gst::ClockTime::from_seconds(i) + output_offset)
);
} else {
assert!(buffer.dts().is_none());
}
assert_eq!(buffer.duration(), Some(gst::ClockTime::SECOND));
}
}
let ev = h1.pull_event().unwrap();
assert_eq!(ev.type_(), gst::EventType::StreamStart);
let ev = h1.pull_event().unwrap();
assert_eq!(ev.type_(), gst::EventType::Caps);
let ev = h1.pull_event().unwrap();
assert_eq!(ev.type_(), gst::EventType::Segment);
let ev = h1.pull_event().unwrap();
assert_eq!(ev.type_(), gst::EventType::Eos);
}