From: Kostya Shishkov Date: Wed, 28 Jan 2026 18:04:17 +0000 (+0100) Subject: hwdec_vaapi: rework frame reorderer X-Git-Url: https://git.nihav.org/?a=commitdiff_plain;h=4a4bf02619a82f6ffb231e56f09b5194fe31f3d5;p=nihav-player.git hwdec_vaapi: rework frame reorderer 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. --- diff --git a/hwdec-vaapi/src/lib.rs b/hwdec-vaapi/src/lib.rs index b9a8344..25e8bba 100644 --- a/hwdec-vaapi/src/lib.rs +++ b/hwdec-vaapi/src/lib.rs @@ -185,65 +185,55 @@ struct WaitingFrame { struct Reorderer { last_ref_dts: Option, - ready_idx: usize, frames: VecDeque, + 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 { - 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; } }