]> git.nihav.org Git - nihav-player.git/commitdiff
videoplayer: (hopefully) fix near-end seek issues
authorKostya Shishkov <kostya.shishkov@gmail.com>
Tue, 10 Feb 2026 17:38:00 +0000 (18:38 +0100)
committerKostya Shishkov <kostya.shishkov@gmail.com>
Tue, 10 Feb 2026 17:38:00 +0000 (18:38 +0100)
The original design was simple: get last frames, end decoding.
Unfortunately, this did not take into account that user may want to rewind
video at the last moment. In such case playback would either end or lock up
waiting for the video decoding thread (that has finished by this point)
to send a reply.

Hence the need to reset "at the end" state in various places of the player.

videoplayer/src/main.rs
videoplayer/src/videodec.rs

index 8b1bbaa960a7415749c46fcb0c42efeb8fc781c9..bcc210b6fb09614ac4bfb3def6eab7a5362507f5 100644 (file)
@@ -464,6 +464,7 @@ struct Player {
     mute:           bool,
     volume:         usize,
     end:            bool,
+    seeked:         bool,
 
     tkeep:          TimeKeep,
 
@@ -513,6 +514,7 @@ impl Player {
             mute:           false,
             volume:         100,
             end:            false,
+            seeked:         false,
 
             tkeep:          TimeKeep::new(),
 
@@ -537,6 +539,8 @@ impl Player {
             return Ok(()); //TODO: not ignore some of seek errors?
         }
 
+        self.seeked = true;
+
         self.acontrol.flush();
         self.vcontrol.flush();
         disp_queue.flush();
@@ -576,7 +580,11 @@ impl Player {
             }
             if try_send {
                 match dmx.get_frame() {
-                    Err(DemuxerError::EOF) => break,
+                    Err(DemuxerError::EOF) => {
+                        self.vcontrol.try_send_video(PktSendEvent::End);
+                        self.acontrol.try_send_audio(PktSendEvent::End);
+                        break;
+                    },
                     Err(_) => break,
                     Ok(pkt) => {
                         let streamno = pkt.get_stream().get_id();
@@ -1010,6 +1018,7 @@ impl Player {
         let mut last_disp = Instant::now();
         let mut has_data = true;
         'main: loop {
+            self.seeked = false;
             let ret = self.handle_events(&mut event_pump, &mut canvas, &mut dmx, &mut disp_q);
             if matches!(ret, Ok(true) | Err(_)) {
                 if !self.quiet {
@@ -1017,6 +1026,9 @@ impl Player {
                 }
                 break 'main;
             }
+            if self.seeked {
+                has_data = true;
+            }
             if !self.paused {
                 let mut try_send = self.acontrol.get_queue_size() < FRAME_QUEUE_LEN && self.vcontrol.get_queue_size() < FRAME_QUEUE_LEN;
                 if !self.vcontrol.try_send_queued() && self.vcontrol.is_filled(FRAME_QUEUE_LEN) {
index ea6ca72d772b09022fddf9062821f86ffc40e430..b8add27f33b3dd6fc1037ed8cd09edbda4206c34 100644 (file)
@@ -282,7 +282,9 @@ fn start_video_decoding(width: usize, height: usize, tb_num: u32, tb_den: u32, v
                         while let Some((buf, time)) = vdec.more_frames(false) {
                             vfsend.send((buf, time)).expect("video frame should be sent");
                         }
-                        VDEC_STATE.set_state(DecodingState::Waiting);
+                        if VDEC_STATE.get_state() != DecodingState::End {
+                            VDEC_STATE.set_state(DecodingState::Waiting);
+                        }
                     },
                     Ok(PktSendEvent::Flush) => {
                         vdec.flush();
@@ -297,7 +299,6 @@ fn start_video_decoding(width: usize, height: usize, tb_num: u32, tb_den: u32, v
                             }
                         }
                         VDEC_STATE.set_state(DecodingState::End);
-                        break;
                     },
                     Ok(PktSendEvent::ImmediateEnd) => {
                         VDEC_STATE.set_state(DecodingState::End);
@@ -433,6 +434,9 @@ impl VideoControl {
         matches!(VDEC_STATE.get_state(), DecodingState::End | DecodingState::Error)
     }
     pub fn wait_for_frames(&mut self) -> Result<(), ()> {
+        if self.is_video_end() {
+            return Ok(());
+        }
         VDEC_STATE.set_state(DecodingState::Prefetch);
         self.try_send_event(PktSendEvent::GetFrames);
         while !self.try_send_queued() {