1 //! Output frame reordering.
3 //! NihAV decoders output frames in the same order as they are put in.
4 //! In result if you want to have frames in display order you might need some frame reorderer.
5 //! This module provides such functionality depending on codec type: audio codecs and video codecs without B-frames do not need any reorderer and can use `NoReorderer` if the common interface is required. Codecs with B-frames should use `IPBReorderer`. For codecs with very complex reordering rules like H.264 or H.256 `PictureIDReorderer` will be added eventually.
7 //! You can find out required reorderer by quering codec properties using `nihav_core::register` module.
9 use std::collections::VecDeque;
10 pub use crate::frame::{FrameType, NAFrameRef};
12 /// A trait for frame reorderer.
13 pub trait FrameReorderer {
14 /// Stores a newly decoded frame.
15 fn add_frame(&mut self, fref: NAFrameRef) -> bool;
16 /// Gets the next frame to be displayed (or `None` if that is not possible).
17 fn get_frame(&mut self) -> Option<NAFrameRef>;
18 /// Clears all stored frames.
20 /// Retrieves the last frames stored by the reorderer.
21 fn get_last_frames(&mut self) -> Option<NAFrameRef>;
25 pub struct NoReorderer {
26 fref: Option<NAFrameRef>,
30 /// Constructs a new instance of `NoReorderer`.
31 pub fn new() -> Self {
36 impl Default for NoReorderer {
37 fn default() -> Self {
42 impl FrameReorderer for NoReorderer {
43 fn add_frame(&mut self, fref: NAFrameRef) -> bool {
44 if self.fref.is_none() {
45 self.fref = Some(fref);
51 fn get_frame(&mut self) -> Option<NAFrameRef> {
53 swap(&mut ret, &mut self.fref);
56 fn flush(&mut self) { self.fref = None; }
57 fn get_last_frames(&mut self) -> Option<NAFrameRef> { None }
60 /// Frame reorderer for codecs with I/P/B frames.
62 pub struct IPBReorderer {
63 rframe: Option<NAFrameRef>,
64 bframe: Option<NAFrameRef>,
68 /// Constructs a new instance of `IPBReorderer`.
69 pub fn new() -> Self { Self::default() }
72 impl FrameReorderer for IPBReorderer {
73 fn add_frame(&mut self, fref: NAFrameRef) -> bool {
74 if self.rframe.is_some() && self.bframe.is_some() { return false; }
75 let is_b = fref.get_frame_type() == FrameType::B;
76 if is_b && self.bframe.is_some() { return false; }
78 self.bframe = Some(fref);
80 std::mem::swap(&mut self.bframe, &mut self.rframe);
81 self.rframe = Some(fref);
85 fn get_frame(&mut self) -> Option<NAFrameRef> {
87 if self.bframe.is_some() {
88 std::mem::swap(&mut ret, &mut self.bframe);
96 fn get_last_frames(&mut self) -> Option<NAFrameRef> {
98 if self.bframe.is_some() {
99 std::mem::swap(&mut ret, &mut self.bframe);
100 } else if self.rframe.is_some() {
101 std::mem::swap(&mut ret, &mut self.rframe);
107 /// Frame reorderer for codecs with complex I/P/B frame structure like ITU H.26x.
109 pub struct ComplexReorderer {
110 last_ref_dts: Option<u64>,
112 frames: Vec<NAFrameRef>,
115 impl ComplexReorderer {
116 /// Constructs a new instance of `IPBReorderer`.
117 pub fn new() -> Self { Self::default() }
120 impl FrameReorderer for ComplexReorderer {
121 fn add_frame(&mut self, fref: NAFrameRef) -> bool {
122 if self.frames.len() >= 64 {
125 let is_ref = fref.frame_type == FrameType::I || fref.frame_type == FrameType::P;
127 if self.frames.is_empty() || fref.get_dts().is_none() {
128 self.frames.push(fref);
129 } else if let Some(new_dts) = fref.get_dts() {
131 for (i, frm) in self.frames.iter().enumerate() {
133 if let Some(dts) = frm.get_dts() {
139 self.frames.insert(idx, fref);
142 for (i, frm) in self.frames.iter().enumerate() {
143 if frm.get_dts() == self.last_ref_dts {
144 self.ready_idx = i + 1;
147 self.last_ref_dts = fref.get_dts();
148 self.frames.push(fref);
152 fn get_frame(&mut self) -> Option<NAFrameRef> {
153 if self.ready_idx > 0 {
155 Some(self.frames.remove(0))
160 fn flush(&mut self) {
161 self.last_ref_dts = None;
165 fn get_last_frames(&mut self) -> Option<NAFrameRef> {
166 if !self.frames.is_empty() {
167 Some(self.frames.remove(0))
174 /// A generic reorderer for a multi-threaded decoder.
176 pub struct MTFrameReorderer {
178 frames: VecDeque<(u32, NAFrameRef)>,
181 output_to: Option<u32>,
182 last_ts: Option<u64>,
185 impl MTFrameReorderer {
186 /// Constructs a new instance of `MTFrameReorderer`.
187 pub fn new() -> Self { Self::default() }
188 /// Registers the fact that a new frame is queued for decoding and returns an internal ID for it.
189 pub fn register_frame(&mut self) -> u32 {
191 self.flush_mode = false;
193 let ret = self.cur_id;
198 /// Puts a newly decoded frame into the internal queue.
199 pub fn add_frame(&mut self, frm: NAFrameRef, id: u32) {
200 //let ftype = frm.get_frame_type();
201 let frm_id = if let Some(ts) = frm.ts.dts { ts } else { u64::from(id) };
203 for (_, frm) in self.frames.iter() {
204 let cur_id = if let Some(ts) = frm.ts.dts { ts } else { frm.id as u64 };
210 self.frames.insert(idx, (id, frm));
211 /*if self.frames.len() > 48 {
212 for (id, frm) in self.frames.iter() { print!(" {}{}({})", frm.get_frame_type(), frm.get_dts().unwrap_or(0), *id); } println!();
213 print!("reg IDs:"); for &id in self.ids.iter() { print!(" {}", id); } println!();
214 panic!("too many frames in the queue");
217 /// Removes the registered frame (e.g. in case of a decoding error).
218 pub fn drop_frame(&mut self, id: u32) {
219 self.ids.retain(|&el| el != id);
221 fn get_first_frame(&mut self) -> Option<NAFrameRef> {
222 let (id, frm) = self.frames.pop_front().unwrap();
224 self.last_ts = frm.get_dts();
227 /// Gets the next frame to be displayed (or `None` if that is not possible).
228 #[allow(clippy::collapsible_if)]
229 #[allow(clippy::collapsible_else_if)]
230 pub fn get_frame(&mut self) -> Option<NAFrameRef> {
231 // check if we have consequent timestamps that we can output
232 if !self.frames.is_empty() {
233 if let Some(dts) = self.frames[0].1.get_dts() {
234 let last_ts = self.last_ts.unwrap_or(0);
235 if self.last_ts.is_none() || (dts == last_ts + 1) {
236 self.output_to = None;
237 return self.get_first_frame();
241 if !self.flush_mode {
243 if let Some(last_id) = self.output_to {
244 if self.frames[0].0 != last_id {
245 return self.get_first_frame();
247 self.output_to = None;
250 for (pos, (id, frm)) in self.frames.iter().enumerate() {
251 if frm.is_keyframe() || (self.frames.len() > 32 && matches!(frm.get_frame_type(), FrameType::I | FrameType::P)) {
254 if pos == 0 && kf_id == self.ids[0] {
255 return self.get_first_frame();
257 let end = self.ids.iter().position(|&id| id == kf_id).unwrap();
258 for ref_id in self.ids[..end].iter() {
259 if !self.frames.iter().any(|(id, _)| id == ref_id) {
263 self.output_to = if pos < self.frames.len() - 1 {
264 Some(self.frames[pos + 1].0)
274 if !self.frames.is_empty() {
275 Some(self.frames.pop_front().unwrap().1)
281 /// Retrieves the last frames stored by the reorderer.
282 pub fn get_last_frames(&mut self) -> Option<NAFrameRef> {
283 self.flush_mode = true;
286 /// Clears all stored frames.
287 pub fn flush(&mut self) {
288 self.flush_mode = false;
291 self.output_to = None;