]> git.nihav.org Git - nihav.git/blame - nihav-core/src/reorder.rs
core/compr: fix clippy warnings
[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
KS
8use std::mem::swap;
9pub use crate::frame::{FrameType, NAFrameRef};
10
6c9578be 11/// A trait for frame reorderer.
ca8452f0 12pub trait FrameReorderer {
6c9578be 13 /// Stores a newly decoded frame.
ca8452f0 14 fn add_frame(&mut self, fref: NAFrameRef) -> bool;
6c9578be 15 /// Gets the next frame to be displayed (or `None` if that is not possible).
ca8452f0 16 fn get_frame(&mut self) -> Option<NAFrameRef>;
6c9578be 17 /// Clears all stored frames.
ca8452f0 18 fn flush(&mut self);
6c9578be 19 /// Retrieves the last frames stored by the reorderer.
ca8452f0
KS
20 fn get_last_frames(&mut self) -> Option<NAFrameRef>;
21}
22
6c9578be 23/// Zero reorderer.
ca8452f0
KS
24pub struct NoReorderer {
25 fref: Option<NAFrameRef>,
26}
27
28impl NoReorderer {
6c9578be 29 /// Constructs a new instance of `NoReorderer`.
ca8452f0
KS
30 pub fn new() -> Self {
31 Self { fref: None }
32 }
33}
34
b36f412c
KS
35impl Default for NoReorderer {
36 fn default() -> Self {
37 Self::new()
38 }
39}
40
ca8452f0
KS
41impl FrameReorderer for NoReorderer {
42 fn add_frame(&mut self, fref: NAFrameRef) -> bool {
43 if self.fref.is_none() {
44 self.fref = Some(fref);
45 true
46 } else {
47 false
48 }
49 }
50 fn get_frame(&mut self) -> Option<NAFrameRef> {
51 let mut ret = None;
52 swap(&mut ret, &mut self.fref);
53 ret
54 }
55 fn flush(&mut self) { self.fref = None; }
56 fn get_last_frames(&mut self) -> Option<NAFrameRef> { None }
57}
58
6c9578be 59/// Frame reorderer for codecs with I/P/B frames.
f9c35397 60#[derive(Default)]
ca8452f0 61pub struct IPBReorderer {
f9c35397
KS
62 rframe: Option<NAFrameRef>,
63 bframe: Option<NAFrameRef>,
ca8452f0
KS
64}
65
66impl IPBReorderer {
6c9578be 67 /// Constructs a new instance of `IPBReorderer`.
f9c35397 68 pub fn new() -> Self { Self::default() }
ca8452f0
KS
69}
70
71impl FrameReorderer for IPBReorderer {
72 fn add_frame(&mut self, fref: NAFrameRef) -> bool {
f9c35397
KS
73 if self.rframe.is_some() && self.bframe.is_some() { return false; }
74 let is_b = fref.get_frame_type() == FrameType::B;
75 if is_b && self.bframe.is_some() { return false; }
76 if is_b {
77 self.bframe = Some(fref);
ca8452f0 78 } else {
f9c35397
KS
79 std::mem::swap(&mut self.bframe, &mut self.rframe);
80 self.rframe = Some(fref);
ca8452f0 81 }
f9c35397 82 true
ca8452f0
KS
83 }
84 fn get_frame(&mut self) -> Option<NAFrameRef> {
f9c35397
KS
85 let mut ret = None;
86 if self.bframe.is_some() {
87 std::mem::swap(&mut ret, &mut self.bframe);
ca8452f0 88 }
f9c35397 89 ret
ca8452f0
KS
90 }
91 fn flush(&mut self) {
f9c35397
KS
92 self.rframe = None;
93 self.bframe = None;
ca8452f0
KS
94 }
95 fn get_last_frames(&mut self) -> Option<NAFrameRef> {
f9c35397
KS
96 let mut ret = None;
97 if self.bframe.is_some() {
98 std::mem::swap(&mut ret, &mut self.bframe);
99 } else if self.rframe.is_some() {
100 std::mem::swap(&mut ret, &mut self.rframe);
101 }
102 ret
ca8452f0
KS
103 }
104}
105
8480761d
KS
106/// Frame reorderer for codecs with complex I/P/B frame structure like ITU H.26x.
107#[derive(Default)]
108pub struct ComplexReorderer {
109 last_ref_dts: Option<u64>,
110 ready_idx: usize,
111 frames: Vec<NAFrameRef>,
112}
113
114impl ComplexReorderer {
115 /// Constructs a new instance of `IPBReorderer`.
116 pub fn new() -> Self { Self::default() }
117}
118
119impl FrameReorderer for ComplexReorderer {
120 fn add_frame(&mut self, fref: NAFrameRef) -> bool {
121 if self.frames.len() >= 64 {
122 return false;
123 }
124 let is_ref = fref.frame_type == FrameType::I || fref.frame_type == FrameType::P;
125 if !is_ref {
126 if self.frames.is_empty() || fref.get_dts().is_none() {
127 self.frames.push(fref);
128 } else if let Some(new_dts) = fref.get_dts() {
129 let mut idx = 0;
130 for (i, frm) in self.frames.iter().enumerate() {
131 idx = i;
132 if let Some(dts) = frm.get_dts() {
133 if dts > new_dts {
134 break;
135 }
136 }
137 }
138 self.frames.insert(idx, fref);
139 }
140 } else {
141 for (i, frm) in self.frames.iter().enumerate() {
142 if frm.get_dts() == self.last_ref_dts {
143 self.ready_idx = i + 1;
144 }
145 }
146 self.last_ref_dts = fref.get_dts();
147 self.frames.push(fref);
148 }
149 true
150 }
151 fn get_frame(&mut self) -> Option<NAFrameRef> {
152 if self.ready_idx > 0 {
153 self.ready_idx -= 1;
154 Some(self.frames.remove(0))
155 } else {
156 None
157 }
158 }
159 fn flush(&mut self) {
160 self.last_ref_dts = None;
161 self.ready_idx = 0;
b191eef3 162 self.frames.clear();
8480761d
KS
163 }
164 fn get_last_frames(&mut self) -> Option<NAFrameRef> {
165 if !self.frames.is_empty() {
166 Some(self.frames.remove(0))
167 } else {
168 None
169 }
170 }
171}
172