mirror of
https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git
synced 2024-11-25 13:01:07 +00:00
fmp4mux: Add support for ONVIF timed XML metadata
This commit is contained in:
parent
e4634ca2fe
commit
ffea0e2d2d
2 changed files with 58 additions and 14 deletions
|
@ -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
|
||||
|
|
|
@ -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>(),
|
||||
|
|
Loading…
Reference in a new issue