respect subtitle duration
This commit is contained in:
parent
1c21e28a03
commit
f029b073d4
2 changed files with 29 additions and 9 deletions
23
src/video.rs
23
src/video.rs
|
@ -67,6 +67,7 @@ pub(crate) struct Internal {
|
||||||
pub(crate) sync_av_counter: u64,
|
pub(crate) sync_av_counter: u64,
|
||||||
|
|
||||||
pub(crate) subtitle_text: Arc<Mutex<Option<String>>>,
|
pub(crate) subtitle_text: Arc<Mutex<Option<String>>>,
|
||||||
|
pub(crate) upload_text: Arc<AtomicBool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Internal {
|
impl Internal {
|
||||||
|
@ -279,9 +280,13 @@ impl Video {
|
||||||
let paused_ref = Arc::clone(&paused);
|
let paused_ref = Arc::clone(&paused);
|
||||||
|
|
||||||
let subtitle_text = Arc::new(Mutex::new(None));
|
let subtitle_text = Arc::new(Mutex::new(None));
|
||||||
|
let upload_text = Arc::new(AtomicBool::new(false));
|
||||||
let subtitle_text_ref = Arc::clone(&subtitle_text);
|
let subtitle_text_ref = Arc::clone(&subtitle_text);
|
||||||
|
let upload_text_ref = Arc::clone(&upload_text);
|
||||||
|
|
||||||
let worker = std::thread::spawn(move || {
|
let worker = std::thread::spawn(move || {
|
||||||
|
let mut clear_subtitles_at = None;
|
||||||
|
|
||||||
while alive_ref.load(Ordering::Acquire) {
|
while alive_ref.load(Ordering::Acquire) {
|
||||||
if let Err(gst::FlowError::Error) = (|| -> Result<(), gst::FlowError> {
|
if let Err(gst::FlowError::Error) = (|| -> Result<(), gst::FlowError> {
|
||||||
let sample = if paused_ref.load(Ordering::SeqCst) {
|
let sample = if paused_ref.load(Ordering::SeqCst) {
|
||||||
|
@ -307,12 +312,24 @@ impl Video {
|
||||||
|
|
||||||
upload_frame_ref.swap(true, Ordering::SeqCst);
|
upload_frame_ref.swap(true, Ordering::SeqCst);
|
||||||
|
|
||||||
|
if let Some(at) = clear_subtitles_at.clone() {
|
||||||
|
if Instant::now() >= at {
|
||||||
|
*subtitle_text_ref
|
||||||
|
.lock()
|
||||||
|
.map_err(|_| gst::FlowError::Error)? = None;
|
||||||
|
upload_text_ref.store(true, Ordering::SeqCst);
|
||||||
|
clear_subtitles_at = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let text = text_sink
|
let text = text_sink
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|sink| sink.try_pull_sample(gst::ClockTime::from_seconds(0)));
|
.and_then(|sink| sink.try_pull_sample(gst::ClockTime::from_seconds(0)));
|
||||||
if let Some(text) = text {
|
if let Some(text) = text {
|
||||||
let text = text.buffer().ok_or(gst::FlowError::Error)?;
|
let text = text.buffer().ok_or(gst::FlowError::Error)?;
|
||||||
|
let duration = text.duration();
|
||||||
let map = text.map_readable().map_err(|_| gst::FlowError::Error)?;
|
let map = text.map_readable().map_err(|_| gst::FlowError::Error)?;
|
||||||
|
|
||||||
let text = html_escape::decode_html_entities(
|
let text = html_escape::decode_html_entities(
|
||||||
std::str::from_utf8(map.as_slice())
|
std::str::from_utf8(map.as_slice())
|
||||||
.map_err(|_| gst::FlowError::Error)?,
|
.map_err(|_| gst::FlowError::Error)?,
|
||||||
|
@ -321,6 +338,11 @@ impl Video {
|
||||||
*subtitle_text_ref
|
*subtitle_text_ref
|
||||||
.lock()
|
.lock()
|
||||||
.map_err(|_| gst::FlowError::Error)? = Some(text);
|
.map_err(|_| gst::FlowError::Error)? = Some(text);
|
||||||
|
upload_text_ref.store(true, Ordering::SeqCst);
|
||||||
|
|
||||||
|
clear_subtitles_at = duration.map(|duration| {
|
||||||
|
Instant::now() + Duration::from_nanos(duration.nseconds())
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -356,6 +378,7 @@ impl Video {
|
||||||
sync_av_counter: 0,
|
sync_av_counter: 0,
|
||||||
|
|
||||||
subtitle_text,
|
subtitle_text,
|
||||||
|
upload_text,
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ where
|
||||||
height: iced::Length,
|
height: iced::Length,
|
||||||
on_end_of_stream: Option<Message>,
|
on_end_of_stream: Option<Message>,
|
||||||
on_new_frame: Option<Message>,
|
on_new_frame: Option<Message>,
|
||||||
on_subtitle_text: Option<Box<dyn Fn(String) -> Message + 'a>>,
|
on_subtitle_text: Option<Box<dyn Fn(Option<String>) -> Message + 'a>>,
|
||||||
on_error: Option<Box<dyn Fn(&glib::Error) -> Message + 'a>>,
|
on_error: Option<Box<dyn Fn(&glib::Error) -> Message + 'a>>,
|
||||||
_phantom: PhantomData<(Theme, Renderer)>,
|
_phantom: PhantomData<(Theme, Renderer)>,
|
||||||
}
|
}
|
||||||
|
@ -87,7 +87,7 @@ where
|
||||||
/// Message to send when the video receives a new frame.
|
/// Message to send when the video receives a new frame.
|
||||||
pub fn on_subtitle_text<F>(self, on_subtitle_text: F) -> Self
|
pub fn on_subtitle_text<F>(self, on_subtitle_text: F) -> Self
|
||||||
where
|
where
|
||||||
F: 'a + Fn(String) -> Message,
|
F: 'a + Fn(Option<String>) -> Message,
|
||||||
{
|
{
|
||||||
VideoPlayer {
|
VideoPlayer {
|
||||||
on_subtitle_text: Some(Box::new(on_subtitle_text)),
|
on_subtitle_text: Some(Box::new(on_subtitle_text)),
|
||||||
|
@ -273,13 +273,10 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(on_subtitle_text) = &self.on_subtitle_text {
|
if let Some(on_subtitle_text) = &self.on_subtitle_text {
|
||||||
if let Some(text) = inner
|
if inner.upload_text.swap(false, Ordering::SeqCst) {
|
||||||
.subtitle_text
|
if let Some(text) = inner.subtitle_text.try_lock().ok() {
|
||||||
.try_lock()
|
shell.publish(on_subtitle_text(text.clone()));
|
||||||
.ok()
|
}
|
||||||
.and_then(|mut text| text.take())
|
|
||||||
{
|
|
||||||
shell.publish(on_subtitle_text(text));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue