]> git.nihav.org Git - nihav-player.git/commitdiff
videoplayer: improve prefill code
authorKostya Shishkov <kostya.shishkov@gmail.com>
Sat, 14 Feb 2026 19:16:29 +0000 (20:16 +0100)
committerKostya Shishkov <kostya.shishkov@gmail.com>
Sat, 14 Feb 2026 19:16:29 +0000 (20:16 +0100)
Previously prefill would fail with hardware-accelerated H.264 decoder
since it starts output after 16 frames and prefill gives up after
sending fewer packets. Repeating the cycle of sending packets and
collecting frames should fix that.

videoplayer/src/main.rs

index 96b453146251f217e19ea738ba2ebe1c7165cf30..83e162be80c1c39dd4859a7408684a7eec6c76cf 100644 (file)
@@ -569,47 +569,59 @@ impl Player {
     }
     fn prefill(&mut self, dmx: &mut DemuxerObject, disp_queue: &mut DispQueue) -> Result<(), ()> {
         debug_log!(self; {" prefilling"});
-        while self.vcontrol.get_queue_size() < FRAME_QUEUE_LEN {
-            let mut try_send = self.acontrol.get_queue_size() < FRAME_QUEUE_LEN && (!self.has_video || (!self.vcontrol.is_filled(FRAME_QUEUE_LEN) && !disp_queue.is_full()));
-
-            if !self.vcontrol.try_send_queued() && self.vcontrol.get_queue_size() > FRAME_QUEUE_LEN / 2 {
-                try_send = false;
-            }
-            if !self.acontrol.try_send_queued() && self.acontrol.get_queue_size() > FRAME_QUEUE_LEN / 2 {
-                try_send = false;
-            }
-            if try_send {
-                match dmx.get_frame() {
-                    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();
-                        if self.has_video && streamno == self.video_str {
-                            self.vcontrol.try_send_video(PktSendEvent::Packet(pkt));
-                        } else if self.has_audio && streamno == self.audio_str {
-                            self.acontrol.try_send_audio(PktSendEvent::Packet(pkt));
+        let mut got_video = !self.has_video;
+        let mut got_audio = !self.has_audio;
+        while !(got_video && got_audio) {
+            // phase 1 - try to send packets for decoding
+            loop {
+                let mut try_send = self.acontrol.get_queue_size() < FRAME_QUEUE_LEN && (!self.has_video || (!self.vcontrol.is_filled(FRAME_QUEUE_LEN) && !disp_queue.is_full()));
+
+                if !self.vcontrol.try_send_queued() && self.vcontrol.get_queue_size() > FRAME_QUEUE_LEN / 2 {
+                    try_send = false;
+                }
+                if !self.acontrol.try_send_queued() && self.acontrol.get_queue_size() > FRAME_QUEUE_LEN / 2 {
+                    try_send = false;
+                }
+                if try_send {
+                    match dmx.get_frame() {
+                        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();
+                            if self.has_video && streamno == self.video_str {
+                                self.vcontrol.try_send_video(PktSendEvent::Packet(pkt));
+                            } else if self.has_audio && streamno == self.audio_str {
+                                self.acontrol.try_send_audio(PktSendEvent::Packet(pkt));
+                            }
                         }
-                    }
-                };
-            }
-            self.vcontrol.fill(disp_queue);
+                    };
+                }
+                self.vcontrol.fill(disp_queue);
 
-            if !try_send {
-                break;
+                if !try_send {
+                    break;
+                }
             }
-        }
-        if self.has_video {
-            while self.vcontrol.get_queue_size() > 0 && !disp_queue.is_full() {
-                self.vcontrol.try_send_queued();
+            // phase 2 - retrieve available data
+            if self.has_video {
+                while self.vcontrol.get_queue_size() > 0 && !disp_queue.is_full() {
+                    self.vcontrol.try_send_queued();
+                    self.vcontrol.fill(disp_queue);
+                    std::thread::sleep(Duration::from_millis(5));
+                }
+                self.vcontrol.wait_for_frames()?;
                 self.vcontrol.fill(disp_queue);
-                std::thread::sleep(Duration::from_millis(10));
+                if disp_queue.is_full() {
+                    got_video = true;
+                }
+            }
+            if self.has_audio && self.acontrol.get_fill() > 0 {
+                got_audio = true;
             }
-            self.vcontrol.wait_for_frames()?;
-            self.vcontrol.fill(disp_queue);
         }
         debug_log!(self; {format!(" prefilling done, frames {}-{} audio {}", disp_queue.start, disp_queue.end, self.acontrol.get_fill())});
         Ok(())