]> git.nihav.org Git - nihav-player.git/commitdiff
hwdec_vaapi: rework frame reorderer master
authorKostya Shishkov <kostya.shishkov@gmail.com>
Wed, 28 Jan 2026 18:04:17 +0000 (19:04 +0100)
committerKostya Shishkov <kostya.shishkov@gmail.com>
Wed, 28 Jan 2026 18:04:17 +0000 (19:04 +0100)
Previous version tried to be "smart" by re-arranging non-reference frames
between reference frames. This approach worked fine for simpler files but
failed with more complex reference structure (like B-pyramid).

New version simply assumes monotone increasing IDs, inserts frames into
the queue according to it and outputs first frame as soon as it is clear
that no frames will be inserted before it.

hwdec-vaapi/src/lib.rs

index b9a8344b12070449d1b02fbf382ae6c79db8131f..25e8bba5c65b844b175143029a1a1624b5ce9530 100644 (file)
@@ -185,65 +185,55 @@ struct WaitingFrame {
 
 struct Reorderer {
     last_ref_dts:   Option<u64>,
-    ready_idx:      usize,
     frames:         VecDeque<WaitingFrame>,
+    flush:          bool,
 }
 
+const MAX_DPB_SIZE: usize = 16;
+
 impl Default for Reorderer {
     fn default() -> Self {
         Self {
             last_ref_dts:   None,
-            ready_idx:      0,
-            frames:         VecDeque::with_capacity(16),
+            frames:         VecDeque::with_capacity(MAX_DPB_SIZE),
+            flush:          false,
         }
     }
 }
 
 impl Reorderer {
     fn add_frame(&mut self, new_frame: WaitingFrame) {
-        if !new_frame.is_ref {
-            if self.frames.is_empty() {
-                self.frames.push_back(new_frame);
-            } else {
-                let new_dts = new_frame.ts;
-                let mut idx = 0;
-                for (i, frm) in self.frames.iter().enumerate() {
-                    idx = i;
-                    if frm.ts > new_dts {
-                        break;
-                    }
-                }
-                self.frames.insert(idx, new_frame);
-            }
+        if self.frames.is_empty() {
+            self.frames.push_back(new_frame);
         } else {
-            for (i, frm) in self.frames.iter().enumerate() {
-                if Some(frm.ts) == self.last_ref_dts {
-                    self.ready_idx = i + 1;
+            let new_dts = new_frame.ts;
+            let mut idx = 0;
+            for frm in self.frames.iter() {
+                if frm.ts > new_dts {
+                    break;
                 }
+                idx += 1;
             }
-            self.last_ref_dts = Some(new_frame.ts);
-            self.frames.push_back(new_frame);
+            self.frames.insert(idx, new_frame);
         }
     }
     fn get_frame(&mut self) -> Option<WaitingFrame> {
-        if self.ready_idx > 0 {
-            match self.frames[0].pic.query_status() {
-                _ if self.ready_idx > 16 => {},
-                Ok(VASurfaceStatus::Ready) => {},
-                Ok(VASurfaceStatus::Rendering) => return None,
-                _ => {
-                    unimplemented!();
-                },
-            };
-            self.ready_idx -= 1;
-            self.frames.pop_front()
-        } else {
-            None
+        if self.frames.is_empty() && self.flush {
+            self.flush = false;
+        }
+        if !self.frames.is_empty() && self.frames[0].pic.query_status() == Ok(VASurfaceStatus::Ready) {
+            let expected_ts = self.last_ref_dts.map(|ts| ts + 1);
+            let first_ts = self.frames[0].ts;
+            if self.flush || Some(first_ts) == expected_ts || self.frames.len() >= MAX_DPB_SIZE {
+                self.last_ref_dts = Some(first_ts);
+                return self.frames.pop_front();
+            }
         }
+        None
     }
     fn flush(&mut self) {
         self.last_ref_dts = None;
-        self.ready_idx = 0;
+        self.flush = true;
     }
 }