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