fmp4mux: Add support for ONVIF timed XML metadata

This commit is contained in:
Sebastian Dröge 2022-05-13 12:13:54 +03:00
parent e4634ca2fe
commit ffea0e2d2d
2 changed files with 58 additions and 14 deletions

View file

@ -644,10 +644,11 @@ fn write_hdlr(
let s = caps.structure(0).unwrap();
let (handler_type, name) = match s.name() {
"video/x-h264" | "video/x-h265" | "image/jpeg" => (b"vide", b"VideoHandler\0"),
"video/x-h264" | "video/x-h265" | "image/jpeg" => (b"vide", b"VideoHandler\0".as_slice()),
"audio/mpeg" | "audio/x-alaw" | "audio/x-mulaw" | "audio/x-adpcm" => {
(b"soun", b"SoundHandler\0")
(b"soun", b"SoundHandler\0".as_slice())
}
"application/x-onvif-metadata" => (b"meta", b"MetadataHandler\0".as_slice()),
_ => unreachable!(),
};
@ -680,6 +681,11 @@ fn write_minf(
write_smhd(v, cfg)
})?
}
"application/x-onvif-metadata" => {
write_full_box(v, b"nmhd", FULL_BOX_VERSION_0, FULL_BOX_FLAGS_NONE, |_v| {
Ok(())
})?
}
_ => unreachable!(),
}
@ -785,6 +791,7 @@ fn write_stsd(
"audio/mpeg" | "audio/x-alaw" | "audio/x-mulaw" | "audio/x-adpcm" => {
write_audio_sample_entry(v, cfg, caps)?
}
"application/x-onvif-metadata" => write_xml_meta_data_sample_entry(v, cfg, caps)?,
_ => unreachable!(),
}
@ -1246,6 +1253,34 @@ fn write_esds_aac(v: &mut Vec<u8>, codec_data: &[u8]) -> Result<(), Error> {
)
}
fn write_xml_meta_data_sample_entry(
v: &mut Vec<u8>,
_cfg: &super::HeaderConfiguration,
caps: &gst::CapsRef,
) -> Result<(), Error> {
let s = caps.structure(0).unwrap();
let namespace = match s.name() {
"application/x-onvif-metadata" => b"http://www.onvif.org/ver10/schema",
_ => unreachable!(),
};
write_sample_entry_box(v, b"metx", move |v| {
// content_encoding, empty string
v.push(0);
// namespace
v.extend_from_slice(namespace);
v.push(0);
// schema_location, empty string list
v.push(0);
Ok(())
})?;
Ok(())
}
fn write_stts(v: &mut Vec<u8>, _cfg: &super::HeaderConfiguration) -> Result<(), Error> {
// Entry count
v.extend(0u32.to_be_bytes());
@ -1681,7 +1716,12 @@ fn write_traf(
let check_dts = matches!(s.name(), "video/x-h264" | "video/x-h265");
let intra_only = matches!(
s.name(),
"audio/mpeg" | "audio/x-alaw" | "audio/x-mulaw" | "audio/x-adpcm" | "image/jpeg"
"audio/mpeg"
| "audio/x-alaw"
| "audio/x-mulaw"
| "audio/x-adpcm"
| "image/jpeg"
| "application/x-onvif-metadata"
);
// Analyze all buffers to know what values can be put into the tfhd for all samples and what

View file

@ -860,6 +860,9 @@ impl FMP4Mux {
"audio/x-adpcm" => {
intra_only = true;
}
"application/x-onvif-metadata" => {
intra_only = true;
}
_ => unreachable!(),
}
@ -879,32 +882,30 @@ impl FMP4Mux {
return Err(gst::FlowError::Error);
}
// Sort video streams first and then audio streams, and each group by pad name.
// Sort video streams first and then audio streams and then metadata streams, and each group by pad name.
state.streams.sort_by(|a, b| {
let stream_type_of_caps = |caps: &gst::CapsRef| {
let order_of_caps = |caps: &gst::CapsRef| {
let s = caps.structure(0).unwrap();
if s.name().starts_with("video/") {
gst::StreamType::VIDEO
0
} else if s.name().starts_with("audio/") {
gst::StreamType::AUDIO
1
} else if s.name().starts_with("application/x-onvif-metadata") {
2
} else {
unimplemented!();
}
};
let st_a = stream_type_of_caps(&a.caps);
let st_b = stream_type_of_caps(&b.caps);
let st_a = order_of_caps(&a.caps);
let st_b = order_of_caps(&b.caps);
if st_a == st_b {
return a.sinkpad.name().cmp(&b.sinkpad.name());
}
if st_a == gst::StreamType::VIDEO {
std::cmp::Ordering::Less
} else {
std::cmp::Ordering::Greater
}
st_a.cmp(&st_b)
});
Ok(())
@ -1963,6 +1964,9 @@ impl ElementImpl for ONVIFFMP4Mux {
.field("rate", 8000i32)
.field("bitrate", gst::List::new([16000i32, 24000, 32000, 40000]))
.build(),
gst::Structure::builder("application/x-onvif-metadata")
.field("encoding", "utf8")
.build(),
]
.into_iter()
.collect::<gst::Caps>(),