diff --git a/README.md b/README.md index abfc30e..6b4bd85 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ Features: - Small (around 300 lines). Limitations (hopefully to be fixed): +- Lazy frame syncing. Playback is usually a few frames and the decoder and audio runs ahead. Seeking is also latent. - GStreamer is a bit annoying to set up on Windows. This is a "composable" instead of a `iced::Widget`. This is because `Widget`s don't support subscriptions (yet?). Once Iced gets animation support (i.e. widgets scheduling a time to update), this can become a widget. diff --git a/src/lib.rs b/src/lib.rs index c4a1a44..95705ac 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -46,6 +46,9 @@ pub struct VideoPlayer { frame_rx: crossbeam_channel::Receiver, frame: Option, pause: bool, + // if true, then the playback resets to the most recent frame. + // set this to true whenever playback is changed (e.g. pause, seek, etc). + reset: bool, } impl Drop for VideoPlayer { @@ -162,6 +165,7 @@ impl VideoPlayer { frame_rx, frame: None, pause: false, + reset: true, }) } @@ -201,6 +205,7 @@ impl VideoPlayer { /// Set if the media is paused or not. pub fn set_paused(&mut self, pause: bool) { + self.reset = true; self.pause = pause; self.source .set_state(if pause { @@ -221,6 +226,7 @@ impl VideoPlayer { /// /// The position is converted to nanoseconds, so any duration with values more significant that nanoseconds is truncated. pub fn seek(&mut self, position: std::time::Duration) -> Result<(), Error> { + self.reset = true; self.source.seek_simple( gst::SeekFlags::empty(), gst::GenericFormattedValue::Time(gst::ClockTime::from_nseconds( @@ -254,7 +260,12 @@ impl VideoPlayer { } } - if let Ok(frame) = self.frame_rx.try_recv() { + if self.reset { + self.reset = false; + if let Some(frame) = self.frame_rx.iter().nth(self.frame_rx.len() - 1) { + self.frame = Some(frame); + } + } else if let Ok(frame) = self.frame_rx.try_recv() { self.frame = Some(frame); } }