1 //! Decoder support functions and definitions.
3 use std::ops::{Add, AddAssign, Sub, SubAssign, Neg};
5 pub use nihav_core::frame::*;
8 /// Frame manager for hold-and-modify codecs.
10 /// This frame manager simplifies frame management for the case when codec decodes new frame by updating parts of the previous frame.
15 /// let mut frame = if is_intra_frame {
16 /// allocate_video_frame()
18 /// let ret = shuffler.clone_ref();
19 /// if ret.is_none() {
20 /// return Err(DecoderError::MissingReference);
24 /// // output data into the frame
25 /// shuffler.add_frame(frame.clone()); // tells frame manager to use the frame as the next reference
29 pub struct HAMShuffler<T: Copy> {
30 lastframe: Option<NAVideoBufferRef<T>>,
33 impl<T: Copy> HAMShuffler<T> {
34 /// Constructs a new instance of frame manager.
36 pub fn new() -> Self { HAMShuffler { lastframe: None } }
37 /// Clears the reference.
39 pub fn clear(&mut self) { self.lastframe = None; }
40 /// Sets a new frame reference.
42 pub fn add_frame(&mut self, buf: NAVideoBufferRef<T>) {
43 self.lastframe = Some(buf);
45 /// Provides a copy of the reference frame if present or `None` if it is not.
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())
56 /// Returns the original saved reference frame or `None` if it is not present.
58 pub fn get_output_frame(&mut self) -> Option<NAVideoBufferRef<T>> {
59 match self.lastframe {
60 Some(ref frm) => Some(frm.clone()),
66 /// Frame manager for codecs with intra and inter frames.
68 /// This frame manager simplifies frame management for the case when codec decodes new frame using previous frame as source of some data.
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);
79 /// let ref_frame = ret.unwrap();
80 /// // keep decoding using data from ref_frame
82 /// shuffler.add_frame(frame.clone()); // tells frame manager to use the frame as the next reference
86 pub struct IPShuffler {
87 lastframe: Option<NAVideoBufferRef<u8>>,
91 /// Constructs a new instance of frame manager.
93 pub fn new() -> Self { IPShuffler { lastframe: None } }
94 /// Clears the reference.
96 pub fn clear(&mut self) { self.lastframe = None; }
97 /// Sets a new frame reference.
99 pub fn add_frame(&mut self, buf: NAVideoBufferRef<u8>) {
100 self.lastframe = Some(buf);
102 /// Returns the original saved reference frame or `None` if it is not present.
104 pub fn get_ref(&mut self) -> Option<NAVideoBufferRef<u8>> {
105 if let Some(ref frm) = self.lastframe {
113 /// Frame manager for codecs with I-, P- and B-frames.
115 /// This frame manager simplifies frame management for the case when codec uses I/P/B frame scheme.
120 /// let mut frame = allocate_video_frame();
121 /// for mb in all_macroblocks {
122 /// // decode macroblock type
124 /// MBType::Inter => {
125 /// do_mc(&mut frame, shuffler.get_lastref().unwrap());
127 /// MBType::BForward => {
128 /// do_mc(&mut frame, shuffler.get_b_fwdref().unwrap());
130 /// MBType::BBackward => {
131 /// do_mc(&mut frame, shuffler.get_b_bwdref().unwrap());
133 /// // handle the rest of cases
135 /// if is_random_access_frame {
136 /// shuffler.clear(); // remove all saved references
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
144 pub struct IPBShuffler {
145 lastframe: Option<NAVideoBufferRef<u8>>,
146 nextframe: Option<NAVideoBufferRef<u8>>,
150 /// Constructs a new instance of frame manager.
152 pub fn new() -> Self { IPBShuffler { lastframe: None, nextframe: None } }
153 /// Clears the reference.
155 pub fn clear(&mut self) { self.lastframe = None; self.nextframe = None; }
156 /// Sets a new frame reference.
158 pub fn add_frame(&mut self, buf: NAVideoBufferRef<u8>) {
159 mem::swap(&mut self.lastframe, &mut self.nextframe);
160 self.lastframe = Some(buf);
162 /// Returns the previous reference frame or `None` if it is not present.
164 pub fn get_lastref(&mut self) -> Option<NAVideoBufferRef<u8>> {
165 if let Some(ref frm) = self.lastframe {
171 /// Returns second last reference frame or `None` if it is not present.
173 pub fn get_nextref(&mut self) -> Option<NAVideoBufferRef<u8>> {
174 if let Some(ref frm) = self.nextframe {
180 /// Returns the temporally following reference for B-frame or `None` if it is not present.
182 pub fn get_b_fwdref(&mut self) -> Option<NAVideoBufferRef<u8>> {
183 if let Some(ref frm) = self.nextframe {
189 /// Returns the temporally preceeding reference for B-frame or `None` if it is not present.
191 pub fn get_b_bwdref(&mut self) -> Option<NAVideoBufferRef<u8>> {
192 if let Some(ref frm) = self.lastframe {
200 /// Motion vector data type.
205 /// use nihav_codec_support::codecs::MV;
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)
212 #[derive(Debug,Clone,Copy,Default,PartialEq)]
214 /// X coordinate of the vector.
216 /// Y coordinate of the vector.
220 #[allow(clippy::many_single_char_names)]
221 #[allow(clippy::collapsible_if)]
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.
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 {
234 if a.x < c.x { x = c.x; } else { x = a.x; }
238 if a.x < c.x { x = a.x; } else { x = c.x; }
248 if a.y < c.y { y = c.y; } else { y = a.y; }
252 if a.y < c.y { y = a.y; } else { y = c.y; }
261 /// Zero motion vector.
262 pub const ZERO_MV: MV = MV { x: 0, y: 0 };
266 fn add(self, other: MV) -> MV { MV { x: self.x + other.x, y: self.y + other.y } }
269 impl AddAssign for MV {
270 fn add_assign(&mut self, other: MV) { self.x += other.x; self.y += other.y; }
275 fn sub(self, other: MV) -> MV { MV { x: self.x - other.x, y: self.y - other.y } }
278 impl SubAssign for MV {
279 fn sub_assign(&mut self, other: MV) { self.x -= other.x; self.y -= other.y; }
284 fn neg(self) -> Self::Output {
285 MV { x: -self.x, y: -self.y }
289 impl fmt::Display for MV {
290 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
291 write!(f, "{},{}", self.x, self.y)
295 #[cfg(any(feature="blockdsp"))]
298 #[cfg(feature="h263")]
299 #[allow(clippy::collapsible_if)]
300 #[allow(clippy::manual_memcpy)]
301 #[allow(clippy::needless_range_loop)]
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