]> git.nihav.org Git - nihav.git/blame - nihav-core/src/reorder.rs
core/reorder: clear frame IDs in MTFrameReorderer on flush
[nihav.git] / nihav-core / src / reorder.rs
CommitLineData
6c9578be
KS
1//! Output frame reordering.
2//!
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.
6//!
7//! You can find out required reorderer by quering codec properties using `nihav_core::register` module.
ca8452f0 8use std::mem::swap;
4213ad59 9use std::collections::VecDeque;
ca8452f0
KS
10pub use crate::frame::{FrameType, NAFrameRef};
11
6c9578be 12/// A trait for frame reorderer.
ca8452f0 13pub trait FrameReorderer {
6c9578be 14 /// Stores a newly decoded frame.
ca8452f0 15 fn add_frame(&mut self, fref: NAFrameRef) -> bool;
6c9578be 16 /// Gets the next frame to be displayed (or `None` if that is not possible).
ca8452f0 17 fn get_frame(&mut self) -> Option<NAFrameRef>;
6c9578be 18 /// Clears all stored frames.
ca8452f0 19 fn flush(&mut self);
6c9578be 20 /// Retrieves the last frames stored by the reorderer.
ca8452f0
KS
21 fn get_last_frames(&mut self) -> Option<NAFrameRef>;
22}
23
6c9578be 24/// Zero reorderer.
ca8452f0
KS
25pub struct NoReorderer {
26 fref: Option<NAFrameRef>,
27}
28
29impl NoReorderer {
6c9578be 30 /// Constructs a new instance of `NoReorderer`.
ca8452f0
KS
31 pub fn new() -> Self {
32 Self { fref: None }
33 }
34}
35
b36f412c
KS
36impl Default for NoReorderer {
37 fn default() -> Self {
38 Self::new()
39 }
40}
41
ca8452f0
KS
42impl FrameReorderer for NoReorderer {
43 fn add_frame(&mut self, fref: NAFrameRef) -> bool {
44 if self.fref.is_none() {
45 self.fref = Some(fref);
46 true
47 } else {
48 false
49 }
50 }
51 fn get_frame(&mut self) -> Option<NAFrameRef> {
52 let mut ret = None;
53 swap(&mut ret, &mut self.fref);
54 ret
55 }
56 fn flush(&mut self) { self.fref = None; }
57 fn get_last_frames(&mut self) -> Option<NAFrameRef> { None }
58}
59
6c9578be 60/// Frame reorderer for codecs with I/P/B frames.
f9c35397 61#[derive(Default)]
ca8452f0 62pub struct IPBReorderer {
f9c35397
KS
63 rframe: Option<NAFrameRef>,
64 bframe: Option<NAFrameRef>,
ca8452f0
KS
65}
66
67impl IPBReorderer {
6c9578be 68 /// Constructs a new instance of `IPBReorderer`.
f9c35397 69 pub fn new() -> Self { Self::default() }
ca8452f0
KS
70}
71
72impl FrameReorderer for IPBReorderer {
73 fn add_frame(&mut self, fref: NAFrameRef) -> bool {
f9c35397
KS
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; }
77 if is_b {
78 self.bframe = Some(fref);
ca8452f0 79 } else {
f9c35397
KS
80 std::mem::swap(&mut self.bframe, &mut self.rframe);
81 self.rframe = Some(fref);
ca8452f0 82 }
f9c35397 83 true
ca8452f0
KS
84 }
85 fn get_frame(&mut self) -> Option<NAFrameRef> {
f9c35397
KS
86 let mut ret = None;
87 if self.bframe.is_some() {
88 std::mem::swap(&mut ret, &mut self.bframe);
ca8452f0 89 }
f9c35397 90 ret
ca8452f0
KS
91 }
92 fn flush(&mut self) {
f9c35397
KS
93 self.rframe = None;
94 self.bframe = None;
ca8452f0
KS
95 }
96 fn get_last_frames(&mut self) -> Option<NAFrameRef> {
f9c35397
KS
97 let mut ret = None;
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);
102 }
103 ret
ca8452f0
KS
104 }
105}
106
8480761d
KS
107/// Frame reorderer for codecs with complex I/P/B frame structure like ITU H.26x.
108#[derive(Default)]
109pub struct ComplexReorderer {
110 last_ref_dts: Option<u64>,
111 ready_idx: usize,
112 frames: Vec<NAFrameRef>,
113}
114
115impl ComplexReorderer {
116 /// Constructs a new instance of `IPBReorderer`.
117 pub fn new() -> Self { Self::default() }
118}
119
120impl FrameReorderer for ComplexReorderer {
121 fn add_frame(&mut self, fref: NAFrameRef) -> bool {
122 if self.frames.len() >= 64 {
123 return false;
124 }
125 let is_ref = fref.frame_type == FrameType::I || fref.frame_type == FrameType::P;
126 if !is_ref {
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() {
130 let mut idx = 0;
131 for (i, frm) in self.frames.iter().enumerate() {
132 idx = i;
133 if let Some(dts) = frm.get_dts() {
134 if dts > new_dts {
135 break;
136 }
137 }
138 }
139 self.frames.insert(idx, fref);
140 }
141 } else {
142 for (i, frm) in self.frames.iter().enumerate() {
143 if frm.get_dts() == self.last_ref_dts {
144 self.ready_idx = i + 1;
145 }
146 }
147 self.last_ref_dts = fref.get_dts();
148 self.frames.push(fref);
149 }
150 true
151 }
152 fn get_frame(&mut self) -> Option<NAFrameRef> {
153 if self.ready_idx > 0 {
154 self.ready_idx -= 1;
155 Some(self.frames.remove(0))
156 } else {
157 None
158 }
159 }
160 fn flush(&mut self) {
161 self.last_ref_dts = None;
162 self.ready_idx = 0;
b191eef3 163 self.frames.clear();
8480761d
KS
164 }
165 fn get_last_frames(&mut self) -> Option<NAFrameRef> {
166 if !self.frames.is_empty() {
167 Some(self.frames.remove(0))
168 } else {
169 None
170 }
171 }
172}
173
4213ad59
KS
174/// A generic reorderer for a multi-threaded decoder.
175#[derive(Default)]
176pub struct MTFrameReorderer {
177 ids: Vec<u32>,
178 frames: VecDeque<(u32, NAFrameRef)>,
179 cur_id: u32,
180 flush_mode: bool,
181 output_to: Option<u32>,
182 last_ts: Option<u64>,
183}
184
185impl 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 {
190 if self.flush_mode {
191 self.flush_mode = false;
192 }
193 let ret = self.cur_id;
194 self.cur_id += 1;
195 self.ids.push(ret);
196 ret
197 }
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) };
202 let mut idx = 0;
203 for (_, frm) in self.frames.iter() {
204 let cur_id = if let Some(ts) = frm.ts.dts { ts } else { frm.id as u64 };
205 if frm_id < cur_id {
206 break;
207 }
208 idx += 1;
209 }
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");
215 }*/
216 }
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);
220 }
221 fn get_first_frame(&mut self) -> Option<NAFrameRef> {
222 let (id, frm) = self.frames.pop_front().unwrap();
223 self.drop_frame(id);
224 self.last_ts = frm.get_dts();
225 Some(frm)
226 }
227 /// Gets the next frame to be displayed (or `None` if that is not possible).
228 #[allow(clippy::collapsible_if)]
229 pub fn get_frame(&mut self) -> Option<NAFrameRef> {
230 // check if we have consequent timestamps that we can output
231 if !self.frames.is_empty() {
232 if let Some(dts) = self.frames[0].1.get_dts() {
233 let last_ts = self.last_ts.unwrap_or(0);
234 if self.last_ts.is_none() || (dts == last_ts + 1) {
235 self.output_to = None;
236 return self.get_first_frame();
237 }
238 }
239 }
240 if !self.flush_mode {
241 'out_loop: loop {
242 if let Some(last_id) = self.output_to {
243 if self.frames[0].0 != last_id {
244 return self.get_first_frame();
245 } else {
246 self.output_to = None;
247 }
248 }
249 for (pos, (id, frm)) in self.frames.iter().enumerate() {
250 if frm.is_keyframe() || (self.frames.len() > 32 && matches!(frm.get_frame_type(), FrameType::I | FrameType::P)) {
251 let kf_id = *id;
252 self.ids.sort();
253 if pos == 0 && kf_id == self.ids[0] {
254 return self.get_first_frame();
255 }
256 let end = self.ids.iter().position(|&id| id == kf_id).unwrap();
257 for ref_id in self.ids[..end].iter() {
258 if self.frames.iter().position(|(id, _)| id == ref_id).is_none() {
259 return None;
260 }
261 }
262 self.output_to = if pos < self.frames.len() - 1 {
263 Some(self.frames[pos + 1].0)
264 } else {
265 Some(kf_id)
266 };
267 continue 'out_loop;
268 }
269 }
270 return None;
271 }
272 } else {
273 if !self.frames.is_empty() {
274 Some(self.frames.pop_front().unwrap().1)
275 } else {
276 None
277 }
278 }
279 }
280 /// Retrieves the last frames stored by the reorderer.
281 pub fn get_last_frames(&mut self) -> Option<NAFrameRef> {
282 self.flush_mode = true;
283 self.get_frame()
284 }
285 /// Clears all stored frames.
286 pub fn flush(&mut self) {
287 self.flush_mode = false;
288 self.frames.clear();
1bb151a6 289 self.ids.clear();
4213ad59
KS
290 self.output_to = None;
291 self.last_ts = None;
292 }
293}