389821eb6c4e1de71642cc44ff18ada1ab4306bc
[nihav.git] / nihav-codec-support / src / codecs / mod.rs
1 //! Decoder support functions and definitions.
2 use std::fmt;
3 use std::ops::{Add, AddAssign, Sub, SubAssign};
4
5 pub use nihav_core::frame::*;
6 use std::mem;
7
8 /// Frame manager for hold-and-modify codecs.
9 ///
10 /// This frame manager simplifies frame management for the case when codec decodes new frame by updating parts of the previous frame.
11 ///
12 /// # Examples
13 ///
14 /// ````norun
15 /// let mut frame = if is_intra_frame {
16 /// allocate_video_frame()
17 /// } else {
18 /// let ret = shuffler.clone_ref();
19 /// if ret.is_none() {
20 /// return Err(DecodingError::MissingReference);
21 /// }
22 /// ret.unwrap()
23 /// };
24 /// // output data into the frame
25 /// shuffler.add_frame(frame.clone()); // tells frame manager to use the frame as the next reference
26 /// ````
27 #[allow(dead_code)]
28 pub struct HAMShuffler<T: Copy> {
29 lastframe: Option<NAVideoBufferRef<T>>,
30 }
31
32 impl<T: Copy> HAMShuffler<T> {
33 /// Constructs a new instance of frame manager.
34 #[allow(dead_code)]
35 pub fn new() -> Self { HAMShuffler { lastframe: None } }
36 /// Clears the reference.
37 #[allow(dead_code)]
38 pub fn clear(&mut self) { self.lastframe = None; }
39 /// Sets a new frame reference.
40 #[allow(dead_code)]
41 pub fn add_frame(&mut self, buf: NAVideoBufferRef<T>) {
42 self.lastframe = Some(buf);
43 }
44 /// Provides a copy of the reference frame if present or `None` if it is not.
45 #[allow(dead_code)]
46 pub fn clone_ref(&mut self) -> Option<NAVideoBufferRef<T>> {
47 if let Some(ref mut frm) = self.lastframe {
48 let newfrm = frm.copy_buffer();
49 *frm = newfrm.clone().into_ref();
50 Some(newfrm.into_ref())
51 } else {
52 None
53 }
54 }
55 /// Returns the original saved reference frame or `None` if it is not present.
56 #[allow(dead_code)]
57 pub fn get_output_frame(&mut self) -> Option<NAVideoBufferRef<T>> {
58 match self.lastframe {
59 Some(ref frm) => Some(frm.clone()),
60 None => None,
61 }
62 }
63 }
64
65 impl<T: Copy> Default for HAMShuffler<T> {
66 fn default() -> Self { Self { lastframe: None } }
67 }
68
69 /// Frame manager for codecs with intra and inter frames.
70 ///
71 /// This frame manager simplifies frame management for the case when codec decodes new frame using previous frame as source of some data.
72 ///
73 /// # Examples
74 ///
75 /// ````norun
76 /// let mut frame = allocate_video_frame();
77 /// if is_inter_frame {
78 /// let ret = shuffler.get_ref();
79 /// if ret.is_none() {
80 /// return Err(DecodingError::MissingReference);
81 /// }
82 /// let ref_frame = ret.unwrap();
83 /// // keep decoding using data from ref_frame
84 /// }
85 /// shuffler.add_frame(frame.clone()); // tells frame manager to use the frame as the next reference
86 /// ````
87 #[allow(dead_code)]
88 pub struct IPShuffler {
89 lastframe: Option<NAVideoBufferRef<u8>>,
90 }
91
92 impl IPShuffler {
93 /// Constructs a new instance of frame manager.
94 #[allow(dead_code)]
95 pub fn new() -> Self { IPShuffler { lastframe: None } }
96 /// Clears the reference.
97 #[allow(dead_code)]
98 pub fn clear(&mut self) { self.lastframe = None; }
99 /// Sets a new frame reference.
100 #[allow(dead_code)]
101 pub fn add_frame(&mut self, buf: NAVideoBufferRef<u8>) {
102 self.lastframe = Some(buf);
103 }
104 /// Returns the original saved reference frame or `None` if it is not present.
105 #[allow(dead_code)]
106 pub fn get_ref(&mut self) -> Option<NAVideoBufferRef<u8>> {
107 if let Some(ref frm) = self.lastframe {
108 Some(frm.clone())
109 } else {
110 None
111 }
112 }
113 }
114
115 impl Default for IPShuffler {
116 fn default() -> Self { Self { lastframe: None } }
117 }
118
119 /// Frame manager for codecs with I-, P- and B-frames.
120 ///
121 /// This frame manager simplifies frame management for the case when codec uses I/P/B frame scheme.
122 ///
123 /// # Examples
124 ///
125 /// ````norun
126 /// let mut frame = allocate_video_frame();
127 /// for mb in all_macroblocks {
128 /// // decode macroblock type
129 /// match mb_type {
130 /// MBType::Inter => {
131 /// do_mc(&mut frame, shuffler.get_lastref().unwrap());
132 /// },
133 /// MBType::BForward => {
134 /// do_mc(&mut frame, shuffler.get_b_fwdref().unwrap());
135 /// },
136 /// MBType::BBackward => {
137 /// do_mc(&mut frame, shuffler.get_b_bwdref().unwrap());
138 /// },
139 /// // handle the rest of cases
140 /// };
141 /// if is_random_access_frame {
142 /// shuffler.clear(); // remove all saved references
143 /// }
144 /// if is_intra_frame || is_p_frame {
145 /// shuffler.add_frame(frame.clone()); // tells frame manager to use the frame as the next reference
146 /// }
147 /// ````
148 #[allow(dead_code)]
149 pub struct IPBShuffler {
150 lastframe: Option<NAVideoBufferRef<u8>>,
151 nextframe: Option<NAVideoBufferRef<u8>>,
152 }
153
154 impl IPBShuffler {
155 /// Constructs a new instance of frame manager.
156 #[allow(dead_code)]
157 pub fn new() -> Self { IPBShuffler { lastframe: None, nextframe: None } }
158 /// Clears the reference.
159 #[allow(dead_code)]
160 pub fn clear(&mut self) { self.lastframe = None; self.nextframe = None; }
161 /// Sets a new frame reference.
162 #[allow(dead_code)]
163 pub fn add_frame(&mut self, buf: NAVideoBufferRef<u8>) {
164 mem::swap(&mut self.lastframe, &mut self.nextframe);
165 self.lastframe = Some(buf);
166 }
167 /// Returns the previous reference frame or `None` if it is not present.
168 #[allow(dead_code)]
169 pub fn get_lastref(&mut self) -> Option<NAVideoBufferRef<u8>> {
170 if let Some(ref frm) = self.lastframe {
171 Some(frm.clone())
172 } else {
173 None
174 }
175 }
176 /// Returns second last reference frame or `None` if it is not present.
177 #[allow(dead_code)]
178 pub fn get_nextref(&mut self) -> Option<NAVideoBufferRef<u8>> {
179 if let Some(ref frm) = self.nextframe {
180 Some(frm.clone())
181 } else {
182 None
183 }
184 }
185 /// Returns the temporally following reference for B-frame or `None` if it is not present.
186 #[allow(dead_code)]
187 pub fn get_b_fwdref(&mut self) -> Option<NAVideoBufferRef<u8>> {
188 if let Some(ref frm) = self.nextframe {
189 Some(frm.clone())
190 } else {
191 None
192 }
193 }
194 /// Returns the temporally preceeding reference for B-frame or `None` if it is not present.
195 #[allow(dead_code)]
196 pub fn get_b_bwdref(&mut self) -> Option<NAVideoBufferRef<u8>> {
197 if let Some(ref frm) = self.lastframe {
198 Some(frm.clone())
199 } else {
200 None
201 }
202 }
203 }
204
205 impl Default for IPBShuffler {
206 fn default() -> Self { Self { lastframe: None, nextframe: None } }
207 }
208
209 /// Motion vector data type.
210 ///
211 /// # Examples
212 ///
213 /// ```
214 /// use nihav_codec_support::codecs::MV;
215 ///
216 /// let mv0 = MV::new(1, 3);
217 /// let mv1 = MV { x: 2, y: 3 }; // choose whatever style you prefer
218 /// let mv2 = mv1 - mv0;
219 /// let mv_pred = MV::pred(mv0, mv1, mv2); // get median prediction for the vectors (1, 0)
220 /// ```
221 #[derive(Debug,Clone,Copy,Default,PartialEq)]
222 pub struct MV {
223 /// X coordinate of the vector.
224 pub x: i16,
225 /// Y coordinate of the vector.
226 pub y: i16,
227 }
228
229 #[allow(clippy::many_single_char_names)]
230 #[allow(clippy::collapsible_if)]
231 impl MV {
232 /// Creates a new motion vector instance.
233 pub fn new(x: i16, y: i16) -> Self { MV{ x, y } }
234 /// Predicts median from provided motion vectors.
235 ///
236 /// Each component of the vector is predicted as the median of corresponding input vector components.
237 pub fn pred(a: MV, b: MV, c: MV) -> Self {
238 let x;
239 if a.x < b.x {
240 if b.x < c.x {
241 x = b.x;
242 } else {
243 if a.x < c.x { x = c.x; } else { x = a.x; }
244 }
245 } else {
246 if b.x < c.x {
247 if a.x < c.x { x = a.x; } else { x = c.x; }
248 } else {
249 x = b.x;
250 }
251 }
252 let y;
253 if a.y < b.y {
254 if b.y < c.y {
255 y = b.y;
256 } else {
257 if a.y < c.y { y = c.y; } else { y = a.y; }
258 }
259 } else {
260 if b.y < c.y {
261 if a.y < c.y { y = a.y; } else { y = c.y; }
262 } else {
263 y = b.y;
264 }
265 }
266 MV { x, y }
267 }
268 }
269
270 /// Zero motion vector.
271 pub const ZERO_MV: MV = MV { x: 0, y: 0 };
272
273 impl Add for MV {
274 type Output = MV;
275 fn add(self, other: MV) -> MV { MV { x: self.x + other.x, y: self.y + other.y } }
276 }
277
278 impl AddAssign for MV {
279 fn add_assign(&mut self, other: MV) { self.x += other.x; self.y += other.y; }
280 }
281
282 impl Sub for MV {
283 type Output = MV;
284 fn sub(self, other: MV) -> MV { MV { x: self.x - other.x, y: self.y - other.y } }
285 }
286
287 impl SubAssign for MV {
288 fn sub_assign(&mut self, other: MV) { self.x -= other.x; self.y -= other.y; }
289 }
290
291 impl fmt::Display for MV {
292 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
293 write!(f, "{},{}", self.x, self.y)
294 }
295 }
296
297 #[cfg(any(feature="blockdsp"))]
298 pub mod blockdsp;
299
300 #[cfg(feature="h263")]
301 #[allow(clippy::collapsible_if)]
302 #[allow(clippy::manual_memcpy)]
303 #[allow(clippy::needless_range_loop)]
304 pub mod h263;
305
306 /// The common 8x8 zigzag scan.
307 pub const ZIGZAG: [usize; 64] = [
308 0, 1, 8, 16, 9, 2, 3, 10,
309 17, 24, 32, 25, 18, 11, 4, 5,
310 12, 19, 26, 33, 40, 48, 41, 34,
311 27, 20, 13, 6, 7, 14, 21, 28,
312 35, 42, 49, 56, 57, 50, 43, 36,
313 29, 22, 15, 23, 30, 37, 44, 51,
314 58, 59, 52, 45, 38, 31, 39, 46,
315 53, 60, 61, 54, 47, 55, 62, 63
316 ];
317
318 pub mod imaadpcm;