Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Dröge <sebastian@centricular.com>2022-05-24 14:04:11 +0300
committerSebastian Dröge <sebastian@centricular.com>2022-08-12 18:51:06 +0300
commit537659655776225320838b426aefdae04994f5c7 (patch)
treecee748c8c3fb7e6ff984cbfa3e833aaf1984fca8 /generic
parent2b61d51e919caec4041e3170531890c0e115e21e (diff)
fmp4mux: Write ONVIF Export File Format CorrectStartTime box for ONVIF variant
Diffstat (limited to 'generic')
-rw-r--r--generic/fmp4/Cargo.toml1
-rw-r--r--generic/fmp4/src/fmp4mux/boxes.rs56
-rw-r--r--generic/fmp4/src/fmp4mux/imp.rs10
-rw-r--r--generic/fmp4/src/fmp4mux/mod.rs10
4 files changed, 52 insertions, 25 deletions
diff --git a/generic/fmp4/Cargo.toml b/generic/fmp4/Cargo.toml
index 135f7f9d5..242ef00bf 100644
--- a/generic/fmp4/Cargo.toml
+++ b/generic/fmp4/Cargo.toml
@@ -15,6 +15,7 @@ gst-base = { package = "gstreamer-base", git = "https://gitlab.freedesktop.org/g
gst-audio = { package = "gstreamer-audio", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs" }
gst-video = { package = "gstreamer-video", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs" }
once_cell = "1.0"
+uuid = { version = "1", features = ["v4"] }
[lib]
name = "gstfmp4"
diff --git a/generic/fmp4/src/fmp4mux/boxes.rs b/generic/fmp4/src/fmp4mux/boxes.rs
index ccd09b41f..5c93ed6be 100644
--- a/generic/fmp4/src/fmp4mux/boxes.rs
+++ b/generic/fmp4/src/fmp4mux/boxes.rs
@@ -355,8 +355,7 @@ fn brands_from_variant_and_caps<'a>(
pub(super) fn create_fmp4_header(cfg: super::HeaderConfiguration) -> Result<gst::Buffer, Error> {
let mut v = vec![];
- let (brand, compatible_brands) =
- brands_from_variant_and_caps(cfg.variant, cfg.streams.iter().map(|s| &s.1));
+ let (brand, compatible_brands) = brands_from_variant_and_caps(cfg.variant, cfg.streams.iter());
write_box(&mut v, b"ftyp", |v| {
// major brand
@@ -371,6 +370,42 @@ pub(super) fn create_fmp4_header(cfg: super::HeaderConfiguration) -> Result<gst:
write_box(&mut v, b"moov", |v| write_moov(v, &cfg))?;
+ if cfg.variant == super::Variant::ONVIF {
+ write_full_box(
+ &mut v,
+ b"meta",
+ FULL_BOX_VERSION_0,
+ FULL_BOX_FLAGS_NONE,
+ |v| {
+ write_full_box(v, b"hdlr", FULL_BOX_VERSION_0, FULL_BOX_FLAGS_NONE, |v| {
+ // Handler type
+ v.extend(b"null");
+
+ // Reserved
+ v.extend([0u8; 3 * 4]);
+
+ // Name
+ v.extend(b"MetadataHandler");
+
+ Ok(())
+ })?;
+
+ write_box(v, b"cstb", |v| {
+ // entry count
+ v.extend(1u32.to_be_bytes());
+
+ // track id
+ v.extend(0u32.to_be_bytes());
+
+ // XXX: start UTC time in 100ns units since Jan 1 1601
+ v.extend(0u64.to_be_bytes());
+
+ Ok(())
+ })
+ },
+ )?;
+ }
+
Ok(gst::Buffer::from_mut_slice(v))
}
@@ -385,7 +420,7 @@ fn write_moov(v: &mut Vec<u8>, cfg: &super::HeaderConfiguration) -> Result<(), E
write_full_box(v, b"mvhd", FULL_BOX_VERSION_1, FULL_BOX_FLAGS_NONE, |v| {
write_mvhd(v, cfg, creation_time)
})?;
- for (idx, (pad, caps)) in cfg.streams.iter().enumerate() {
+ for (idx, caps) in cfg.streams.iter().enumerate() {
write_box(v, b"trak", |v| {
let mut references = vec![];
@@ -394,7 +429,7 @@ fn write_moov(v: &mut Vec<u8>, cfg: &super::HeaderConfiguration) -> Result<(), E
&& caps.structure(0).unwrap().name() == "application/x-onvif-metadata"
{
// Find the first video track
- for (idx, (_pad, caps)) in cfg.streams.iter().enumerate() {
+ for (idx, caps) in cfg.streams.iter().enumerate() {
let s = caps.structure(0).unwrap();
if matches!(s.name(), "video/x-h264" | "video/x-h265" | "image/jpeg") {
@@ -407,7 +442,7 @@ fn write_moov(v: &mut Vec<u8>, cfg: &super::HeaderConfiguration) -> Result<(), E
}
}
- write_trak(v, cfg, idx, pad, caps, creation_time, &references)
+ write_trak(v, cfg, idx, caps, creation_time, &references)
})?;
}
write_box(v, b"mvex", |v| write_mvex(v, cfg))?;
@@ -454,7 +489,7 @@ fn write_mvhd(
// Modification time
v.extend(creation_time.to_be_bytes());
// Timescale: uses the reference track timescale
- v.extend(caps_to_timescale(&cfg.streams[0].1).to_be_bytes());
+ v.extend(caps_to_timescale(&cfg.streams[0]).to_be_bytes());
// Duration
v.extend(0u64.to_be_bytes());
@@ -504,7 +539,6 @@ fn write_trak(
v: &mut Vec<u8>,
cfg: &super::HeaderConfiguration,
idx: usize,
- _pad: &gst_base::AggregatorPad,
caps: &gst::CapsRef,
creation_time: u64,
references: &[TrackReference],
@@ -1389,7 +1423,7 @@ fn write_mvex(v: &mut Vec<u8>, cfg: &super::HeaderConfiguration) -> Result<(), E
}
}
- for (idx, (_pad, _caps)) in cfg.streams.iter().enumerate() {
+ for (idx, _caps) in cfg.streams.iter().enumerate() {
write_full_box(v, b"trex", FULL_BOX_VERSION_0, FULL_BOX_FLAGS_NONE, |v| {
write_trex(v, cfg, idx)
})?;
@@ -1400,7 +1434,7 @@ fn write_mvex(v: &mut Vec<u8>, cfg: &super::HeaderConfiguration) -> Result<(), E
fn write_mehd(v: &mut Vec<u8>, cfg: &super::HeaderConfiguration) -> Result<(), Error> {
// Use the reference track timescale
- let timescale = caps_to_timescale(&cfg.streams[0].1);
+ let timescale = caps_to_timescale(&cfg.streams[0]);
let duration = cfg
.duration
@@ -1443,7 +1477,7 @@ pub(super) fn create_fmp4_fragment_header(
let mut v = vec![];
let (brand, compatible_brands) =
- brands_from_variant_and_caps(cfg.variant, cfg.streams.iter().map(|s| &s.1));
+ brands_from_variant_and_caps(cfg.variant, cfg.streams.iter().map(|s| &s.0));
write_box(&mut v, b"styp", |v| {
// major brand
@@ -1494,7 +1528,7 @@ fn write_moof(
})?;
let mut data_offset_offsets = vec![];
- for (idx, (_pad, caps, timing_info)) in cfg.streams.iter().enumerate() {
+ for (idx, (caps, timing_info)) in cfg.streams.iter().enumerate() {
// Skip tracks without any buffers for this fragment.
let timing_info = match timing_info {
None => continue,
diff --git a/generic/fmp4/src/fmp4mux/imp.rs b/generic/fmp4/src/fmp4mux/imp.rs
index f1ba3c121..60d8b919c 100644
--- a/generic/fmp4/src/fmp4mux/imp.rs
+++ b/generic/fmp4/src/fmp4mux/imp.rs
@@ -607,7 +607,7 @@ impl FMP4Mux {
"Draining no buffers",
);
- streams.push((stream.sinkpad.clone(), stream.caps.clone(), None));
+ streams.push((stream.caps.clone(), None));
drain_buffers.push(VecDeque::new());
} else {
let first_gop = gops.first().unwrap();
@@ -678,7 +678,6 @@ impl FMP4Mux {
};
streams.push((
- stream.sinkpad.clone(),
stream.caps.clone(),
Some(super::FragmentTimingInfo {
start_time,
@@ -928,7 +927,7 @@ impl FMP4Mux {
// Write mfra only for the main stream, and if there are no buffers for the main stream
// in this segment then don't write anything.
- if let Some((_pad, _caps, Some(ref timing_info))) = streams.get(0) {
+ if let Some((_caps, Some(ref timing_info))) = streams.get(0) {
state.fragment_offsets.push(super::FragmentOffset {
time: timing_info.start_time,
offset: moof_offset,
@@ -952,7 +951,7 @@ impl FMP4Mux {
}
if settings.write_mfra && at_eos {
- match boxes::create_mfra(&streams[0].1, &state.fragment_offsets) {
+ match boxes::create_mfra(&streams[0].0, &state.fragment_offsets) {
Ok(mut mfra) => {
{
let mfra = mfra.get_mut().unwrap();
@@ -1100,11 +1099,10 @@ impl FMP4Mux {
let streams = state
.streams
.iter()
- .map(|s| (s.sinkpad.clone(), s.caps.clone()))
+ .map(|s| s.caps.clone())
.collect::<Vec<_>>();
let mut buffer = boxes::create_fmp4_header(super::HeaderConfiguration {
- element,
variant,
update: at_eos,
streams: streams.as_slice(),
diff --git a/generic/fmp4/src/fmp4mux/mod.rs b/generic/fmp4/src/fmp4mux/mod.rs
index a9b649a61..2d0ba10ea 100644
--- a/generic/fmp4/src/fmp4mux/mod.rs
+++ b/generic/fmp4/src/fmp4mux/mod.rs
@@ -64,12 +64,10 @@ pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> {
#[derive(Debug)]
pub(crate) struct HeaderConfiguration<'a> {
variant: Variant,
- #[allow(dead_code)]
- element: &'a FMP4Mux,
update: bool,
/// First caps must be the video/reference stream. Must be in the order the tracks are going to
/// be used later for the fragments too.
- streams: &'a [(gst_base::AggregatorPad, gst::Caps)],
+ streams: &'a [gst::Caps],
write_mehd: bool,
duration: Option<gst::ClockTime>,
}
@@ -78,11 +76,7 @@ pub(crate) struct HeaderConfiguration<'a> {
pub(crate) struct FragmentHeaderConfiguration<'a> {
variant: Variant,
sequence_number: u32,
- streams: &'a [(
- gst_base::AggregatorPad,
- gst::Caps,
- Option<FragmentTimingInfo>,
- )],
+ streams: &'a [(gst::Caps, Option<FragmentTimingInfo>)],
buffers: &'a [Buffer],
}