Merge branch 'fmp4-language-from-tags' into 'main'

fmp4mux: Add language from tags

See merge request gstreamer/gst-plugins-rs!1557
This commit is contained in:
Rafael Caricio 2024-05-03 08:35:00 +00:00
commit 2d61e20809
4 changed files with 47 additions and 12 deletions

View file

@ -360,6 +360,10 @@ impl AudioStream {
.property("samplesperbuffer", 4410) .property("samplesperbuffer", 4410)
.property_from_str("wave", &self.wave) .property_from_str("wave", &self.wave)
.build()?; .build()?;
let taginject = gst::ElementFactory::make("taginject")
.property_from_str("tags", &format!("language-code={}", self.lang))
.property_from_str("scope", "stream")
.build()?;
let raw_capsfilter = gst::ElementFactory::make("capsfilter") let raw_capsfilter = gst::ElementFactory::make("capsfilter")
.property( .property(
"caps", "caps",
@ -374,9 +378,23 @@ impl AudioStream {
.build()?; .build()?;
let appsink = gst_app::AppSink::builder().buffer_list(true).build(); let appsink = gst_app::AppSink::builder().buffer_list(true).build();
pipeline.add_many([&src, &raw_capsfilter, &enc, &mux, appsink.upcast_ref()])?; pipeline.add_many([
&src,
&taginject,
&raw_capsfilter,
&enc,
&mux,
appsink.upcast_ref(),
])?;
gst::Element::link_many([&src, &raw_capsfilter, &enc, &mux, appsink.upcast_ref()])?; gst::Element::link_many([
&src,
&taginject,
&raw_capsfilter,
&enc,
&mux,
appsink.upcast_ref(),
])?;
probe_encoder(state, enc); probe_encoder(state, enc);
@ -416,7 +434,7 @@ fn main() -> Result<(), Error> {
}, },
AudioStream { AudioStream {
name: "audio_1".to_string(), name: "audio_1".to_string(),
lang: "fre".to_string(), lang: "fra".to_string(),
default: false, default: false,
wave: "white-noise".to_string(), wave: "white-noise".to_string(),
}, },

View file

@ -699,10 +699,6 @@ fn write_tref(
fn language_code(lang: impl std::borrow::Borrow<[u8; 3]>) -> u16 { fn language_code(lang: impl std::borrow::Borrow<[u8; 3]>) -> u16 {
let lang = lang.borrow(); let lang = lang.borrow();
// TODO: Need to relax this once we get the language code from tags
assert!(lang.iter().all(u8::is_ascii_lowercase));
(((lang[0] as u16 - 0x60) & 0x1F) << 10) (((lang[0] as u16 - 0x60) & 0x1F) << 10)
+ (((lang[1] as u16 - 0x60) & 0x1F) << 5) + (((lang[1] as u16 - 0x60) & 0x1F) << 5)
+ ((lang[2] as u16 - 0x60) & 0x1F) + ((lang[2] as u16 - 0x60) & 0x1F)
@ -710,7 +706,7 @@ fn language_code(lang: impl std::borrow::Borrow<[u8; 3]>) -> u16 {
fn write_mdhd( fn write_mdhd(
v: &mut Vec<u8>, v: &mut Vec<u8>,
_cfg: &super::HeaderConfiguration, cfg: &super::HeaderConfiguration,
stream: &super::HeaderStream, stream: &super::HeaderStream,
creation_time: u64, creation_time: u64,
) -> Result<(), Error> { ) -> Result<(), Error> {
@ -724,8 +720,11 @@ fn write_mdhd(
v.extend(0u64.to_be_bytes()); v.extend(0u64.to_be_bytes());
// Language as ISO-639-2/T // Language as ISO-639-2/T
// TODO: get actual language from the tags if let Some(lang) = cfg.language_code {
v.extend(language_code(b"und").to_be_bytes()); v.extend(language_code(lang).to_be_bytes());
} else {
v.extend(language_code(b"und").to_be_bytes());
}
// Pre-defined // Pre-defined
v.extend([0u8; 2]); v.extend([0u8; 2]);

View file

@ -250,6 +250,8 @@ struct State {
end_pts: Option<gst::ClockTime>, end_pts: Option<gst::ClockTime>,
/// Start DTS of the whole stream /// Start DTS of the whole stream
start_dts: Option<gst::ClockTime>, start_dts: Option<gst::ClockTime>,
/// Language code from tags
language_code: Option<[u8; 3]>,
/// Start PTS of the current fragment /// Start PTS of the current fragment
fragment_start_pts: Option<gst::ClockTime>, fragment_start_pts: Option<gst::ClockTime>,
@ -2707,6 +2709,7 @@ impl FMP4Mux {
streams, streams,
write_mehd: settings.write_mehd, write_mehd: settings.write_mehd,
duration: if at_eos { duration } else { None }, duration: if at_eos { duration } else { None },
language_code: state.language_code.clone(),
start_utc_time: if variant == super::Variant::ONVIF { start_utc_time: if variant == super::Variant::ONVIF {
state state
.earliest_pts .earliest_pts
@ -3140,8 +3143,22 @@ impl AggregatorImpl for FMP4Mux {
self.parent_sink_event(aggregator_pad, event) self.parent_sink_event(aggregator_pad, event)
} }
EventView::Tag(_ev) => { EventView::Tag(ev) => {
// TODO: Maybe store for putting into the headers of the next fragment? if let Some(tag_value) = ev.tag().get::<gst::tags::LanguageCode>() {
let lang = tag_value.get();
gst::trace!(CAT, imp: self, "Received language code from tags: {:?}", lang);
// Language as ISO-639-2/T
if lang.len() == 3 && lang.chars().all(|c| c.is_ascii_lowercase()) {
let mut state = self.state.lock().unwrap();
let mut language_code: [u8; 3] = [0; 3];
for (i, c) in lang.chars().enumerate() {
language_code[i] = c as u8;
}
state.language_code = Some(language_code);
}
}
self.parent_sink_event(aggregator_pad, event) self.parent_sink_event(aggregator_pad, event)
} }

View file

@ -85,6 +85,7 @@ pub(crate) struct HeaderConfiguration {
write_mehd: bool, write_mehd: bool,
duration: Option<gst::ClockTime>, duration: Option<gst::ClockTime>,
language_code: Option<[u8; 3]>,
/// 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.