mirror of
https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git
synced 2024-10-31 22:58:51 +00:00
transcriberbin: Add support for runtime translation-languages update
Allows updating translation-languages at runtime Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/1162>
This commit is contained in:
parent
65c6117962
commit
538e2e0c9e
2 changed files with 161 additions and 13 deletions
|
@ -5020,9 +5020,9 @@
|
|||
"blurb": "A map of CEA 608 channels to language codes, eg translation-languages=\"languages, CC1=fr, CC3=transcript\" will map the French translation to CC1 and the original transcript to CC3",
|
||||
"conditionally-available": false,
|
||||
"construct": false,
|
||||
"construct-only": true,
|
||||
"construct-only": false,
|
||||
"controllable": false,
|
||||
"mutable": "null",
|
||||
"mutable": "playing",
|
||||
"readable": true,
|
||||
"type": "GstStructure",
|
||||
"writable": true
|
||||
|
|
|
@ -73,6 +73,7 @@ struct State {
|
|||
audio_tee: gst::Element,
|
||||
transcriber_aconv: gst::Element,
|
||||
transcriber: gst::Element,
|
||||
ccmux: gst::Element,
|
||||
cccombiner: gst::Element,
|
||||
transcription_bin: gst::Bin,
|
||||
transcription_channels: HashMap<String, TranscriptionChannel>,
|
||||
|
@ -168,16 +169,13 @@ impl TranscriberBin {
|
|||
.property("max-size-time", 5_000_000_000u64)
|
||||
.property_from_str("leaky", "downstream")
|
||||
.build()?;
|
||||
let ccmux = gst::ElementFactory::make("cea608mux")
|
||||
.property_from_str("start-time-selection", "first")
|
||||
.build()?;
|
||||
let ccconverter = gst::ElementFactory::make("ccconverter").build()?;
|
||||
|
||||
state.transcription_bin.add_many([
|
||||
&aqueue_transcription,
|
||||
&state.transcriber_aconv,
|
||||
&state.transcriber,
|
||||
&ccmux,
|
||||
&state.ccmux,
|
||||
&ccconverter,
|
||||
&state.cccapsfilter,
|
||||
&state.transcription_valve,
|
||||
|
@ -190,7 +188,7 @@ impl TranscriberBin {
|
|||
])?;
|
||||
|
||||
gst::Element::link_many([
|
||||
&ccmux,
|
||||
&state.ccmux,
|
||||
&ccconverter,
|
||||
&state.cccapsfilter,
|
||||
&state.transcription_valve,
|
||||
|
@ -201,13 +199,14 @@ impl TranscriberBin {
|
|||
|
||||
channel.link_transcriber(&state.transcriber)?;
|
||||
|
||||
let ccmux_pad = ccmux
|
||||
let ccmux_pad = state
|
||||
.ccmux
|
||||
.request_pad_simple(padname)
|
||||
.ok_or(anyhow!("Failed to request ccmux sink pad"))?;
|
||||
channel.bin.static_pad("src").unwrap().link(&ccmux_pad)?;
|
||||
}
|
||||
|
||||
ccmux.set_property("latency", CEA608MUX_LATENCY);
|
||||
state.ccmux.set_property("latency", CEA608MUX_LATENCY);
|
||||
|
||||
let transcription_audio_sinkpad = gst::GhostPad::with_target(
|
||||
Some("sink"),
|
||||
|
@ -358,9 +357,12 @@ impl TranscriberBin {
|
|||
state.transcription_bin.set_locked_state(false);
|
||||
state.transcription_bin.sync_state_with_parent().unwrap();
|
||||
|
||||
let audio_tee_pad = state.audio_tee.request_pad_simple("src_%u").unwrap();
|
||||
let transcription_sink_pad = state.transcription_bin.static_pad("sink").unwrap();
|
||||
audio_tee_pad.link(&transcription_sink_pad).unwrap();
|
||||
// Might be linked already if "translation-languages" is set
|
||||
if transcription_sink_pad.peer().is_none() {
|
||||
let audio_tee_pad = state.audio_tee.request_pad_simple("src_%u").unwrap();
|
||||
audio_tee_pad.link(&transcription_sink_pad).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
drop(settings);
|
||||
|
@ -495,6 +497,139 @@ impl TranscriberBin {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn reconfigure_channels(&self) -> Result<(), Error> {
|
||||
let mut state = self.state.lock().unwrap();
|
||||
|
||||
if let Some(ref mut state) = state.as_mut() {
|
||||
let settings = self.settings.lock().unwrap();
|
||||
|
||||
gst::debug!(
|
||||
CAT,
|
||||
imp: self,
|
||||
"Updating transcription/translation channel configuration"
|
||||
);
|
||||
|
||||
// Unlink sinkpad temporarily
|
||||
let sinkpad = state.transcription_bin.static_pad("sink").unwrap();
|
||||
let peer = sinkpad.peer();
|
||||
if let Some(peer) = &peer {
|
||||
gst::debug!(CAT, imp: self, "Unlinking {:?}", peer);
|
||||
peer.unlink(&sinkpad)?;
|
||||
state.audio_tee.release_request_pad(peer);
|
||||
}
|
||||
|
||||
state.transcription_bin.set_locked_state(true);
|
||||
state.transcription_bin.set_state(gst::State::Null).unwrap();
|
||||
|
||||
for channel in state.transcription_channels.values() {
|
||||
let sinkpad = channel.bin.static_pad("sink").unwrap();
|
||||
if let Some(peer) = sinkpad.peer() {
|
||||
peer.unlink(&sinkpad)?;
|
||||
if channel.language != "transcript" {
|
||||
state.transcriber.release_request_pad(&peer);
|
||||
}
|
||||
}
|
||||
|
||||
let srcpad = channel.bin.static_pad("src").unwrap();
|
||||
if let Some(peer) = srcpad.peer() {
|
||||
srcpad.unlink(&peer)?;
|
||||
state.ccmux.release_request_pad(&peer);
|
||||
}
|
||||
|
||||
state.transcription_bin.remove(&channel.bin)?;
|
||||
}
|
||||
|
||||
state.transcription_channels.clear();
|
||||
|
||||
if let Some(ref map) = settings.translation_languages {
|
||||
for (key, value) in map.iter() {
|
||||
let channel = key.to_lowercase();
|
||||
if !["cc1", "cc3"].contains(&channel.as_str()) {
|
||||
anyhow::bail!("Unknown 608 channel {}, valid values are cc1, cc3", channel);
|
||||
}
|
||||
let language_code = value.get::<String>()?;
|
||||
|
||||
state.transcription_channels.insert(
|
||||
channel.to_owned(),
|
||||
self.construct_channel_bin(&language_code).unwrap(),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
state.transcription_channels.insert(
|
||||
"cc1".to_string(),
|
||||
self.construct_channel_bin("transcript").unwrap(),
|
||||
);
|
||||
}
|
||||
|
||||
for (padname, channel) in &state.transcription_channels {
|
||||
state.transcription_bin.add(&channel.bin)?;
|
||||
|
||||
channel.link_transcriber(&state.transcriber)?;
|
||||
|
||||
let ccmux_pad = state
|
||||
.ccmux
|
||||
.request_pad_simple(padname)
|
||||
.ok_or(anyhow!("Failed to request ccmux sink pad"))?;
|
||||
channel.bin.static_pad("src").unwrap().link(&ccmux_pad)?;
|
||||
}
|
||||
|
||||
drop(settings);
|
||||
self.setup_cc_mode(state);
|
||||
|
||||
if !self.settings.lock().unwrap().passthrough {
|
||||
gst::debug!(CAT, imp: self, "Syncing state with parent");
|
||||
|
||||
state.transcription_bin.set_locked_state(false);
|
||||
state.transcription_bin.sync_state_with_parent()?;
|
||||
|
||||
let audio_tee_pad = state.audio_tee.request_pad_simple("src_%u").unwrap();
|
||||
audio_tee_pad.link(&sinkpad)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn update_channels(&self) {
|
||||
let s = self.state.lock().unwrap();
|
||||
|
||||
if let Some(state) = s.as_ref() {
|
||||
gst::debug!(
|
||||
CAT,
|
||||
imp: self,
|
||||
"Schedule transcription/translation channel update"
|
||||
);
|
||||
|
||||
let sinkpad = state.transcription_bin.static_pad("sink").unwrap();
|
||||
let imp_weak = self.downgrade();
|
||||
drop(s);
|
||||
|
||||
let _ = sinkpad.add_probe(
|
||||
gst::PadProbeType::IDLE
|
||||
| gst::PadProbeType::BUFFER
|
||||
| gst::PadProbeType::EVENT_DOWNSTREAM,
|
||||
move |_pad, _info| {
|
||||
let imp = match imp_weak.upgrade() {
|
||||
None => return gst::PadProbeReturn::Remove,
|
||||
Some(imp) => imp,
|
||||
};
|
||||
|
||||
if imp.reconfigure_channels().is_err() {
|
||||
gst::element_imp_error!(
|
||||
imp,
|
||||
gst::StreamError::Failed,
|
||||
["Couldn't reconfigure channels"]
|
||||
);
|
||||
}
|
||||
|
||||
gst::PadProbeReturn::Remove
|
||||
},
|
||||
);
|
||||
} else {
|
||||
gst::debug!(CAT, imp: self, "Transcriber is not configured yet");
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::single_match)]
|
||||
fn src_query(&self, pad: &gst::Pad, query: &mut gst::QueryRef) -> bool {
|
||||
use gst::QueryViewMut;
|
||||
|
@ -572,6 +707,9 @@ impl TranscriberBin {
|
|||
let transcription_valve = gst::ElementFactory::make("valve")
|
||||
.property_from_str("drop-mode", "transform-to-gap")
|
||||
.build()?;
|
||||
let ccmux = gst::ElementFactory::make("cea608mux")
|
||||
.property_from_str("start-time-selection", "first")
|
||||
.build()?;
|
||||
|
||||
let mut transcription_channels = HashMap::new();
|
||||
|
||||
|
@ -602,6 +740,7 @@ impl TranscriberBin {
|
|||
video_queue,
|
||||
transcriber_aconv,
|
||||
transcriber,
|
||||
ccmux,
|
||||
audio_tee,
|
||||
cccombiner,
|
||||
transcription_bin,
|
||||
|
@ -750,7 +889,7 @@ impl ObjectImpl for TranscriberBin {
|
|||
glib::ParamSpecBoxed::builder::<gst::Structure>("translation-languages")
|
||||
.nick("Translation languages")
|
||||
.blurb("A map of CEA 608 channels to language codes, eg translation-languages=\"languages, CC1=fr, CC3=transcript\" will map the French translation to CC1 and the original transcript to CC3")
|
||||
.construct_only()
|
||||
.mutable_playing()
|
||||
.build(),
|
||||
glib::ParamSpecUInt::builder("translate-latency")
|
||||
.nick("Translation Latency")
|
||||
|
@ -842,7 +981,16 @@ impl ObjectImpl for TranscriberBin {
|
|||
let mut settings = self.settings.lock().unwrap();
|
||||
settings.translation_languages = value
|
||||
.get::<Option<gst::Structure>>()
|
||||
.expect("type checked upstream")
|
||||
.expect("type checked upstream");
|
||||
gst::debug!(
|
||||
CAT,
|
||||
imp: self,
|
||||
"Updated translation-languages {:?}",
|
||||
settings.translation_languages
|
||||
);
|
||||
drop(settings);
|
||||
|
||||
self.update_channels();
|
||||
}
|
||||
"translate-latency" => {
|
||||
let mut settings = self.settings.lock().unwrap();
|
||||
|
|
Loading…
Reference in a new issue