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