]> git.nihav.org Git - nihav.git/blame - nihav-codec-support/src/codecs/mod.rs
add MPEG-4 ASP decoder
[nihav.git] / nihav-codec-support / src / codecs / mod.rs
CommitLineData
b4d5b851
KS
1//! Decoder support functions and definitions.
2use std::fmt;
473c2f76 3use std::ops::{Add, AddAssign, Sub, SubAssign, Neg};
b4d5b851
KS
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///
fa49f061 14/// ```ignore
b4d5b851
KS
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() {
fa49f061 20/// return Err(DecoderError::MissingReference);
b4d5b851
KS
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
fa49f061 26/// ```
b4d5b851 27#[allow(dead_code)]
6f263099 28#[derive(Default)]
8d7a1c5c
KS
29pub struct HAMShuffler<T: Copy> {
30 lastframe: Option<NAVideoBufferRef<T>>,
b4d5b851
KS
31}
32
8d7a1c5c 33impl<T: Copy> HAMShuffler<T> {
b4d5b851
KS
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)]
8d7a1c5c 42 pub fn add_frame(&mut self, buf: NAVideoBufferRef<T>) {
b4d5b851
KS
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)]
8d7a1c5c 47 pub fn clone_ref(&mut self) -> Option<NAVideoBufferRef<T>> {
b4d5b851
KS
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)]
8d7a1c5c 58 pub fn get_output_frame(&mut self) -> Option<NAVideoBufferRef<T>> {
e6aaad5c 59 self.lastframe.as_ref().cloned()
b4d5b851
KS
60 }
61}
62
b4d5b851
KS
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///
fa49f061 69/// ```ignore
b4d5b851
KS
70/// let mut frame = allocate_video_frame();
71/// if is_inter_frame {
72/// let ret = shuffler.get_ref();
73/// if ret.is_none() {
fa49f061 74/// return Err(DecoderError::MissingReference);
b4d5b851
KS
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
fa49f061 80/// ```
b4d5b851 81#[allow(dead_code)]
6f263099 82#[derive(Default)]
b4d5b851
KS
83pub struct IPShuffler {
84 lastframe: Option<NAVideoBufferRef<u8>>,
85}
86
87impl 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>> {
e6aaad5c 102 self.lastframe.as_ref().cloned()
b4d5b851
KS
103 }
104}
105
b4d5b851
KS
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///
fa49f061 112/// ```ignore
b4d5b851
KS
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/// }
fa49f061 134/// ```
b4d5b851 135#[allow(dead_code)]
6f263099 136#[derive(Default)]
b4d5b851
KS
137pub struct IPBShuffler {
138 lastframe: Option<NAVideoBufferRef<u8>>,
139 nextframe: Option<NAVideoBufferRef<u8>>,
140}
141
142impl 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>> {
e6aaad5c 158 self.lastframe.as_ref().cloned()
b4d5b851
KS
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>> {
e6aaad5c 163 self.nextframe.as_ref().cloned()
b4d5b851
KS
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>> {
e6aaad5c 168 self.nextframe.as_ref().cloned()
b4d5b851
KS
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>> {
e6aaad5c 173 self.lastframe.as_ref().cloned()
b4d5b851
KS
174 }
175}
176
b4d5b851
KS
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)]
190pub 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)]
e6aaad5c 199#[allow(clippy::collapsible_else_if)]
b4d5b851
KS
200impl 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.
240pub const ZERO_MV: MV = MV { x: 0, y: 0 };
241
242impl 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
247impl AddAssign for MV {
248 fn add_assign(&mut self, other: MV) { self.x += other.x; self.y += other.y; }
249}
250
251impl 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
256impl SubAssign for MV {
257 fn sub_assign(&mut self, other: MV) { self.x -= other.x; self.y -= other.y; }
258}
259
473c2f76
KS
260impl Neg for MV {
261 type Output = MV;
262 fn neg(self) -> Self::Output {
263 MV { x: -self.x, y: -self.y }
264 }
265}
266
b4d5b851
KS
267impl 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"))]
274pub mod blockdsp;
275
276#[cfg(feature="h263")]
03011b99
KS
277#[allow(clippy::collapsible_if)]
278#[allow(clippy::manual_memcpy)]
279#[allow(clippy::needless_range_loop)]
b4d5b851
KS
280pub mod h263;
281
282/// The common 8x8 zigzag scan.
283pub 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];
e781ccc3
KS
293
294pub mod imaadpcm;