mirror of
https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git
synced 2024-11-25 13:01:07 +00:00
fmp4mux: Add language from tags
Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/1557>
This commit is contained in:
parent
aabb011f5a
commit
7d75e263f8
7 changed files with 77 additions and 13 deletions
|
@ -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(),
|
||||||
},
|
},
|
||||||
|
|
|
@ -700,7 +700,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));
|
assert!(lang.iter().all(u8::is_ascii_lowercase));
|
||||||
|
|
||||||
(((lang[0] as u16 - 0x60) & 0x1F) << 10)
|
(((lang[0] as u16 - 0x60) & 0x1F) << 10)
|
||||||
|
@ -710,7 +709,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 +723,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]);
|
||||||
|
|
|
@ -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,
|
||||||
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 (out, c) in Iterator::zip(language_code.iter_mut(), lang.chars()) {
|
||||||
|
*out = c as u8;
|
||||||
|
}
|
||||||
|
state.language_code = Some(language_code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.parent_sink_event(aggregator_pad, event)
|
self.parent_sink_event(aggregator_pad, event)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -459,7 +459,6 @@ fn write_mdia(
|
||||||
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));
|
assert!(lang.iter().all(u8::is_ascii_lowercase));
|
||||||
|
|
||||||
(((lang[0] as u16 - 0x60) & 0x1F) << 10)
|
(((lang[0] as u16 - 0x60) & 0x1F) << 10)
|
||||||
|
@ -469,7 +468,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>,
|
||||||
_header: &super::Header,
|
header: &super::Header,
|
||||||
stream: &super::Stream,
|
stream: &super::Stream,
|
||||||
creation_time: u64,
|
creation_time: u64,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
|
@ -492,8 +491,11 @@ fn write_mdhd(
|
||||||
v.extend(duration.to_be_bytes());
|
v.extend(duration.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) = header.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]);
|
||||||
|
|
|
@ -153,6 +153,9 @@ struct State {
|
||||||
|
|
||||||
/// Size of the `mdat` as written so far.
|
/// Size of the `mdat` as written so far.
|
||||||
mdat_size: u64,
|
mdat_size: u64,
|
||||||
|
|
||||||
|
/// Language code from tags
|
||||||
|
language_code: Option<[u8; 3]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
@ -1166,6 +1169,25 @@ impl AggregatorImpl for MP4Mux {
|
||||||
}
|
}
|
||||||
self.parent_sink_event_pre_queue(aggregator_pad, event)
|
self.parent_sink_event_pre_queue(aggregator_pad, event)
|
||||||
}
|
}
|
||||||
|
EventView::Tag(ev) => {
|
||||||
|
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 (out, c) in Iterator::zip(language_code.iter_mut(), lang.chars()) {
|
||||||
|
*out = c as u8;
|
||||||
|
}
|
||||||
|
state.language_code = Some(language_code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.parent_sink_event_pre_queue(aggregator_pad, event)
|
||||||
|
}
|
||||||
_ => self.parent_sink_event_pre_queue(aggregator_pad, event),
|
_ => self.parent_sink_event_pre_queue(aggregator_pad, event),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1365,6 +1387,7 @@ impl AggregatorImpl for MP4Mux {
|
||||||
variant: self.obj().class().as_ref().variant,
|
variant: self.obj().class().as_ref().variant,
|
||||||
movie_timescale: settings.movie_timescale,
|
movie_timescale: settings.movie_timescale,
|
||||||
streams,
|
streams,
|
||||||
|
language_code: state.language_code,
|
||||||
})
|
})
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
gst::error!(CAT, imp: self, "Failed to create moov box: {err}");
|
gst::error!(CAT, imp: self, "Failed to create moov box: {err}");
|
||||||
|
|
|
@ -135,6 +135,7 @@ pub(crate) struct Header {
|
||||||
/// Pre-defined movie timescale if not 0.
|
/// Pre-defined movie timescale if not 0.
|
||||||
movie_timescale: u32,
|
movie_timescale: u32,
|
||||||
streams: Vec<Stream>,
|
streams: Vec<Stream>,
|
||||||
|
language_code: Option<[u8; 3]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::upper_case_acronyms)]
|
#[allow(clippy::upper_case_acronyms)]
|
||||||
|
|
Loading…
Reference in a new issue