From 50a48f4b8506d01a64e6a4e914d34240e2dc4f36 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 9 Jan 2024 08:47:51 -0300 Subject: [PATCH] mp4mux: Add support for edit lists So we properly handle audio priming Part-of: --- mux/fmp4/src/fmp4mux/boxes.rs | 2 +- mux/fmp4/src/fmp4mux/imp.rs | 25 ++++++++++++++++++++++++- mux/fmp4/src/fmp4mux/mod.rs | 13 +++++++++++++ mux/mp4/src/mp4mux/imp.rs | 6 +++--- 4 files changed, 41 insertions(+), 5 deletions(-) diff --git a/mux/fmp4/src/fmp4mux/boxes.rs b/mux/fmp4/src/fmp4mux/boxes.rs index d8b14382..8afa34f3 100644 --- a/mux/fmp4/src/fmp4mux/boxes.rs +++ b/mux/fmp4/src/fmp4mux/boxes.rs @@ -603,7 +603,7 @@ fn write_trak( // TODO: write edts optionally for negative DTS instead of offsetting the DTS write_box(v, b"mdia", |v| write_mdia(v, cfg, stream, creation_time))?; - if !stream.elst_infos.is_empty() { + if !stream.elst_infos.is_empty() && cfg.write_edts { if let Err(e) = write_edts(v, stream) { gst::warning!(CAT, "Failed to write edts: {e}"); } diff --git a/mux/fmp4/src/fmp4mux/imp.rs b/mux/fmp4/src/fmp4mux/imp.rs index 1aa5fe45..6b3496b4 100644 --- a/mux/fmp4/src/fmp4mux/imp.rs +++ b/mux/fmp4/src/fmp4mux/imp.rs @@ -26,6 +26,7 @@ use once_cell::sync::Lazy; use super::boxes; use super::Buffer; use super::DeltaFrames; +use super::WriteEdtsMode; /// Offset for the segment in non-single-stream variants. const SEGMENT_OFFSET: gst::ClockTime = gst::ClockTime::from_seconds(60 * 60 * 1000); @@ -106,6 +107,7 @@ const DEFAULT_WRITE_MFRA: bool = false; const DEFAULT_WRITE_MEHD: bool = false; const DEFAULT_INTERLEAVE_BYTES: Option = None; const DEFAULT_INTERLEAVE_TIME: Option = Some(gst::ClockTime::from_mseconds(250)); +const DEFAULT_WRITE_EDTS_MODE: WriteEdtsMode = WriteEdtsMode::Auto; #[derive(Debug, Clone)] struct Settings { @@ -118,6 +120,7 @@ struct Settings { interleave_time: Option, movie_timescale: u32, offset_to_zero: bool, + write_edts_mode: WriteEdtsMode, } impl Default for Settings { @@ -132,6 +135,7 @@ impl Default for Settings { interleave_time: DEFAULT_INTERLEAVE_TIME, movie_timescale: 0, offset_to_zero: false, + write_edts_mode: DEFAULT_WRITE_EDTS_MODE, } } } @@ -3103,6 +3107,12 @@ impl FMP4Mux { }) .collect::>(); + let write_edts = match settings.write_edts_mode { + WriteEdtsMode::Auto => self.obj().latency().is_none(), + WriteEdtsMode::Always => true, + WriteEdtsMode::Never => false, + }; + let mut buffer = boxes::create_fmp4_header(super::HeaderConfiguration { variant, update: at_eos, @@ -3112,6 +3122,7 @@ impl FMP4Mux { duration: if at_eos { duration } else { None }, language_code: state.language_code, orientation: state.orientation, + write_edts, start_utc_time: if variant == super::Variant::ONVIF { state .earliest_pts @@ -3335,6 +3346,11 @@ impl ObjectImpl for FMP4Mux { .blurb("Timescale to use for the movie (units per second, 0 is automatic)") .mutable_ready() .build(), + glib::ParamSpecEnum::builder_with_default("write-edts-mode", DEFAULT_WRITE_EDTS_MODE) + .nick("Write edts mode") + .blurb("Mode for writing EDTS, when in auto mode, edts written only for non-live streams.") + .mutable_ready() + .build(), ] }); @@ -3404,7 +3420,10 @@ impl ObjectImpl for FMP4Mux { let mut settings = self.settings.lock().unwrap(); settings.movie_timescale = value.get().expect("type checked upstream"); } - + "write-edts-mode" => { + let mut settings = self.settings.lock().unwrap(); + settings.write_edts_mode = value.get().expect("type checked upstream"); + } _ => unimplemented!(), } } @@ -3450,6 +3469,10 @@ impl ObjectImpl for FMP4Mux { let settings = self.settings.lock().unwrap(); settings.movie_timescale.to_value() } + "write-edts-mode" => { + let settings = self.settings.lock().unwrap(); + settings.write_edts_mode.to_value() + } _ => unimplemented!(), } diff --git a/mux/fmp4/src/fmp4mux/mod.rs b/mux/fmp4/src/fmp4mux/mod.rs index bbf2f027..b130180d 100644 --- a/mux/fmp4/src/fmp4mux/mod.rs +++ b/mux/fmp4/src/fmp4mux/mod.rs @@ -44,6 +44,7 @@ pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { FMP4Mux::static_type().mark_as_plugin_api(gst::PluginAPIFlags::empty()); FMP4MuxPad::static_type().mark_as_plugin_api(gst::PluginAPIFlags::empty()); HeaderUpdateMode::static_type().mark_as_plugin_api(gst::PluginAPIFlags::empty()); + WriteEdtsMode::static_type().mark_as_plugin_api(gst::PluginAPIFlags::empty()); } gst::Element::register( Some(plugin), @@ -167,6 +168,9 @@ pub(crate) struct HeaderConfiguration { /// Start UTC time in ONVIF mode. /// Since Jan 1 1601 in 100ns units. start_utc_time: Option, + + /// Whether to write edts box + write_edts: bool, } #[derive(Debug, Clone)] @@ -296,3 +300,12 @@ pub(crate) enum HeaderUpdateMode { Rewrite, Update, } + +#[derive(Debug, Clone, Copy, PartialEq, Eq, glib::Enum, Default)] +#[enum_type(name = "GstFMP4MuxWriteEdtsMode")] +pub(crate) enum WriteEdtsMode { + #[default] + Auto, + Always, + Never, +} diff --git a/mux/mp4/src/mp4mux/imp.rs b/mux/mp4/src/mp4mux/imp.rs index 66697bde..83437969 100644 --- a/mux/mp4/src/mp4mux/imp.rs +++ b/mux/mp4/src/mp4mux/imp.rs @@ -347,7 +347,7 @@ impl MP4Mux { let generic_to_samples = move |t| -> Result, anyhow::Error> { if let gst::GenericFormattedValue::Default(Some(v)) = t { - let v: u64 = v.into(); + let v = u64::from(v); Ok(Some(v).filter(|x| x != &0u64)) } else if let gst::GenericFormattedValue::Time(Some(v)) = t { Ok(Some(gstclocktime_to_samples(v)?)) @@ -356,8 +356,8 @@ impl MP4Mux { } }; - let start: Option = generic_to_samples(cmeta.start())?; - let end: Option = generic_to_samples(cmeta.end())?; + let start = generic_to_samples(cmeta.start())?; + let end = generic_to_samples(cmeta.end())?; if end.is_none() && start.is_none() { return Err(anyhow!(