make HAMShuffler generic
[nihav.git] / nihav-codec-support / src / codecs / mod.rs
CommitLineData
b4d5b851
KS
1//! Decoder support functions and definitions.
2use std::fmt;
3use std::ops::{Add, AddAssign, Sub, SubAssign};
4
5pub use nihav_core::frame::*;
6use 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)]
8d7a1c5c
KS
28pub struct HAMShuffler<T: Copy> {
29 lastframe: Option<NAVideoBufferRef<T>>,
b4d5b851
KS
30}
31
8d7a1c5c 32impl<T: Copy> HAMShuffler<T> {
b4d5b851
KS
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)]
8d7a1c5c 41 pub fn add_frame(&mut self, buf: NAVideoBufferRef<T>) {
b4d5b851
KS
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)]
8d7a1c5c 46 pub fn clone_ref(&mut self) -> Option<NAVideoBufferRef<T>> {
b4d5b851
KS
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)]
8d7a1c5c 57 pub fn get_output_frame(&mut self) -> Option<NAVideoBufferRef<T>> {
b4d5b851
KS
58 match self.lastframe {
59 Some(ref frm) => Some(frm.clone()),
60 None => None,
61 }
62 }
63}
64
8d7a1c5c 65impl<T: Copy> Default for HAMShuffler<T> {
b4d5b851
KS
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)]
88pub struct IPShuffler {
89 lastframe: Option<NAVideoBufferRef<u8>>,
90}
91
92impl 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
115impl 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)]
149pub struct IPBShuffler {
150 lastframe: Option<NAVideoBufferRef<u8>>,
151 nextframe: Option<NAVideoBufferRef<u8>>,
152}
153
154impl 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
205impl 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)]
222pub 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)]
231impl 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.
271pub const ZERO_MV: MV = MV { x: 0, y: 0 };
272
273impl 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
278impl AddAssign for MV {
279 fn add_assign(&mut self, other: MV) { self.x += other.x; self.y += other.y; }
280}
281
282impl 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
287impl SubAssign for MV {
288 fn sub_assign(&mut self, other: MV) { self.x -= other.x; self.y -= other.y; }
289}
290
291impl 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"))]
298pub mod blockdsp;
299
300#[cfg(feature="h263")]
03011b99
KS
301#[allow(clippy::collapsible_if)]
302#[allow(clippy::manual_memcpy)]
303#[allow(clippy::needless_range_loop)]
b4d5b851
KS
304pub mod h263;
305
306/// The common 8x8 zigzag scan.
307pub 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];
e781ccc3
KS
317
318pub mod imaadpcm;