mirror of
https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git
synced 2024-11-28 22:41:02 +00:00
mp4mux: Add support for edit lists
So we properly handle audio priming Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/1434>
This commit is contained in:
parent
e630aab769
commit
50a48f4b85
4 changed files with 41 additions and 5 deletions
|
@ -603,7 +603,7 @@ fn write_trak(
|
||||||
|
|
||||||
// TODO: write edts optionally for negative DTS instead of offsetting the DTS
|
// 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))?;
|
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) {
|
if let Err(e) = write_edts(v, stream) {
|
||||||
gst::warning!(CAT, "Failed to write edts: {e}");
|
gst::warning!(CAT, "Failed to write edts: {e}");
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ use once_cell::sync::Lazy;
|
||||||
use super::boxes;
|
use super::boxes;
|
||||||
use super::Buffer;
|
use super::Buffer;
|
||||||
use super::DeltaFrames;
|
use super::DeltaFrames;
|
||||||
|
use super::WriteEdtsMode;
|
||||||
|
|
||||||
/// Offset for the segment in non-single-stream variants.
|
/// Offset for the segment in non-single-stream variants.
|
||||||
const SEGMENT_OFFSET: gst::ClockTime = gst::ClockTime::from_seconds(60 * 60 * 1000);
|
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_WRITE_MEHD: bool = false;
|
||||||
const DEFAULT_INTERLEAVE_BYTES: Option<u64> = None;
|
const DEFAULT_INTERLEAVE_BYTES: Option<u64> = None;
|
||||||
const DEFAULT_INTERLEAVE_TIME: Option<gst::ClockTime> = Some(gst::ClockTime::from_mseconds(250));
|
const DEFAULT_INTERLEAVE_TIME: Option<gst::ClockTime> = Some(gst::ClockTime::from_mseconds(250));
|
||||||
|
const DEFAULT_WRITE_EDTS_MODE: WriteEdtsMode = WriteEdtsMode::Auto;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct Settings {
|
struct Settings {
|
||||||
|
@ -118,6 +120,7 @@ struct Settings {
|
||||||
interleave_time: Option<gst::ClockTime>,
|
interleave_time: Option<gst::ClockTime>,
|
||||||
movie_timescale: u32,
|
movie_timescale: u32,
|
||||||
offset_to_zero: bool,
|
offset_to_zero: bool,
|
||||||
|
write_edts_mode: WriteEdtsMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Settings {
|
impl Default for Settings {
|
||||||
|
@ -132,6 +135,7 @@ impl Default for Settings {
|
||||||
interleave_time: DEFAULT_INTERLEAVE_TIME,
|
interleave_time: DEFAULT_INTERLEAVE_TIME,
|
||||||
movie_timescale: 0,
|
movie_timescale: 0,
|
||||||
offset_to_zero: false,
|
offset_to_zero: false,
|
||||||
|
write_edts_mode: DEFAULT_WRITE_EDTS_MODE,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3103,6 +3107,12 @@ impl FMP4Mux {
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
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 {
|
let mut buffer = boxes::create_fmp4_header(super::HeaderConfiguration {
|
||||||
variant,
|
variant,
|
||||||
update: at_eos,
|
update: at_eos,
|
||||||
|
@ -3112,6 +3122,7 @@ impl FMP4Mux {
|
||||||
duration: if at_eos { duration } else { None },
|
duration: if at_eos { duration } else { None },
|
||||||
language_code: state.language_code,
|
language_code: state.language_code,
|
||||||
orientation: state.orientation,
|
orientation: state.orientation,
|
||||||
|
write_edts,
|
||||||
start_utc_time: if variant == super::Variant::ONVIF {
|
start_utc_time: if variant == super::Variant::ONVIF {
|
||||||
state
|
state
|
||||||
.earliest_pts
|
.earliest_pts
|
||||||
|
@ -3335,6 +3346,11 @@ impl ObjectImpl for FMP4Mux {
|
||||||
.blurb("Timescale to use for the movie (units per second, 0 is automatic)")
|
.blurb("Timescale to use for the movie (units per second, 0 is automatic)")
|
||||||
.mutable_ready()
|
.mutable_ready()
|
||||||
.build(),
|
.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();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
settings.movie_timescale = value.get().expect("type checked upstream");
|
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!(),
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3450,6 +3469,10 @@ impl ObjectImpl for FMP4Mux {
|
||||||
let settings = self.settings.lock().unwrap();
|
let settings = self.settings.lock().unwrap();
|
||||||
settings.movie_timescale.to_value()
|
settings.movie_timescale.to_value()
|
||||||
}
|
}
|
||||||
|
"write-edts-mode" => {
|
||||||
|
let settings = self.settings.lock().unwrap();
|
||||||
|
settings.write_edts_mode.to_value()
|
||||||
|
}
|
||||||
|
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,7 @@ pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> {
|
||||||
FMP4Mux::static_type().mark_as_plugin_api(gst::PluginAPIFlags::empty());
|
FMP4Mux::static_type().mark_as_plugin_api(gst::PluginAPIFlags::empty());
|
||||||
FMP4MuxPad::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());
|
HeaderUpdateMode::static_type().mark_as_plugin_api(gst::PluginAPIFlags::empty());
|
||||||
|
WriteEdtsMode::static_type().mark_as_plugin_api(gst::PluginAPIFlags::empty());
|
||||||
}
|
}
|
||||||
gst::Element::register(
|
gst::Element::register(
|
||||||
Some(plugin),
|
Some(plugin),
|
||||||
|
@ -167,6 +168,9 @@ pub(crate) struct HeaderConfiguration {
|
||||||
/// Start UTC time in ONVIF mode.
|
/// Start UTC time in ONVIF mode.
|
||||||
/// Since Jan 1 1601 in 100ns units.
|
/// Since Jan 1 1601 in 100ns units.
|
||||||
start_utc_time: Option<u64>,
|
start_utc_time: Option<u64>,
|
||||||
|
|
||||||
|
/// Whether to write edts box
|
||||||
|
write_edts: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -296,3 +300,12 @@ pub(crate) enum HeaderUpdateMode {
|
||||||
Rewrite,
|
Rewrite,
|
||||||
Update,
|
Update,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, glib::Enum, Default)]
|
||||||
|
#[enum_type(name = "GstFMP4MuxWriteEdtsMode")]
|
||||||
|
pub(crate) enum WriteEdtsMode {
|
||||||
|
#[default]
|
||||||
|
Auto,
|
||||||
|
Always,
|
||||||
|
Never,
|
||||||
|
}
|
||||||
|
|
|
@ -347,7 +347,7 @@ impl MP4Mux {
|
||||||
|
|
||||||
let generic_to_samples = move |t| -> Result<Option<u64>, anyhow::Error> {
|
let generic_to_samples = move |t| -> Result<Option<u64>, anyhow::Error> {
|
||||||
if let gst::GenericFormattedValue::Default(Some(v)) = t {
|
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))
|
Ok(Some(v).filter(|x| x != &0u64))
|
||||||
} else if let gst::GenericFormattedValue::Time(Some(v)) = t {
|
} else if let gst::GenericFormattedValue::Time(Some(v)) = t {
|
||||||
Ok(Some(gstclocktime_to_samples(v)?))
|
Ok(Some(gstclocktime_to_samples(v)?))
|
||||||
|
@ -356,8 +356,8 @@ impl MP4Mux {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let start: Option<u64> = generic_to_samples(cmeta.start())?;
|
let start = generic_to_samples(cmeta.start())?;
|
||||||
let end: Option<u64> = generic_to_samples(cmeta.end())?;
|
let end = generic_to_samples(cmeta.end())?;
|
||||||
|
|
||||||
if end.is_none() && start.is_none() {
|
if end.is_none() && start.is_none() {
|
||||||
return Err(anyhow!(
|
return Err(anyhow!(
|
||||||
|
|
Loading…
Reference in a new issue