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
28 pub struct HAMShuffler<T: Copy> {
29 lastframe: Option<NAVideoBufferRef<T>>,
32 impl<T: Copy> HAMShuffler<T> {
33 /// Constructs a new instance of frame manager.
35 pub fn new() -> Self { HAMShuffler { lastframe: None } }
36 /// Clears the reference.
38 pub fn clear(&mut self) { self.lastframe = None; }
39 /// Sets a new frame reference.
41 pub fn add_frame(&mut self, buf: NAVideoBufferRef<T>) {
42 self.lastframe = Some(buf);
44 /// Provides a copy of the reference frame if present or `None` if it is not.
46 pub fn clone_ref(&mut self) -> Option<NAVideoBufferRef<T>> {
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())
55 /// Returns the original saved reference frame or `None` if it is not present.
57 pub fn get_output_frame(&mut self) -> Option<NAVideoBufferRef<T>> {
58 match self.lastframe {
59 Some(ref frm) => Some(frm.clone()),
65 impl<T: Copy> Default for HAMShuffler<T> {
66 fn default() -> Self { Self { lastframe: None } }
69 /// Frame manager for codecs with intra and inter frames.
71 /// This frame manager simplifies frame management for the case when codec decodes new frame using previous frame as source of some data.
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(DecoderError::MissingReference);
82 /// let ref_frame = ret.unwrap();
83 /// // keep decoding using data from ref_frame
85 /// shuffler.add_frame(frame.clone()); // tells frame manager to use the frame as the next reference
88 pub struct IPShuffler {
89 lastframe: Option<NAVideoBufferRef<u8>>,
93 /// Constructs a new instance of frame manager.
95 pub fn new() -> Self { IPShuffler { lastframe: None } }
96 /// Clears the reference.
98 pub fn clear(&mut self) { self.lastframe = None; }
99 /// Sets a new frame reference.
101 pub fn add_frame(&mut self, buf: NAVideoBufferRef<u8>) {
102 self.lastframe = Some(buf);
104 /// Returns the original saved reference frame or `None` if it is not present.
106 pub fn get_ref(&mut self) -> Option<NAVideoBufferRef<u8>> {
107 if let Some(ref frm) = self.lastframe {
115 impl Default for IPShuffler {
116 fn default() -> Self { Self { lastframe: None } }
119 /// Frame manager for codecs with I-, P- and B-frames.
121 /// This frame manager simplifies frame management for the case when codec uses I/P/B frame scheme.
126 /// let mut frame = allocate_video_frame();
127 /// for mb in all_macroblocks {
128 /// // decode macroblock type
130 /// MBType::Inter => {
131 /// do_mc(&mut frame, shuffler.get_lastref().unwrap());
133 /// MBType::BForward => {
134 /// do_mc(&mut frame, shuffler.get_b_fwdref().unwrap());
136 /// MBType::BBackward => {
137 /// do_mc(&mut frame, shuffler.get_b_bwdref().unwrap());
139 /// // handle the rest of cases
141 /// if is_random_access_frame {
142 /// shuffler.clear(); // remove all saved references
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
149 pub struct IPBShuffler {
150 lastframe: Option<NAVideoBufferRef<u8>>,
151 nextframe: Option<NAVideoBufferRef<u8>>,
155 /// Constructs a new instance of frame manager.
157 pub fn new() -> Self { IPBShuffler { lastframe: None, nextframe: None } }
158 /// Clears the reference.
160 pub fn clear(&mut self) { self.lastframe = None; self.nextframe = None; }
161 /// Sets a new frame reference.
163 pub fn add_frame(&mut self, buf: NAVideoBufferRef<u8>) {
164 mem::swap(&mut self.lastframe, &mut self.nextframe);
165 self.lastframe = Some(buf);
167 /// Returns the previous reference frame or `None` if it is not present.
169 pub fn get_lastref(&mut self) -> Option<NAVideoBufferRef<u8>> {
170 if let Some(ref frm) = self.lastframe {
176 /// Returns second last reference frame or `None` if it is not present.
178 pub fn get_nextref(&mut self) -> Option<NAVideoBufferRef<u8>> {
179 if let Some(ref frm) = self.nextframe {
185 /// Returns the temporally following reference for B-frame or `None` if it is not present.
187 pub fn get_b_fwdref(&mut self) -> Option<NAVideoBufferRef<u8>> {
188 if let Some(ref frm) = self.nextframe {
194 /// Returns the temporally preceeding reference for B-frame or `None` if it is not present.
196 pub fn get_b_bwdref(&mut self) -> Option<NAVideoBufferRef<u8>> {
197 if let Some(ref frm) = self.lastframe {
205 impl Default for IPBShuffler {
206 fn default() -> Self { Self { lastframe: None, nextframe: None } }
209 /// Motion vector data type.
214 /// use nihav_codec_support::codecs::MV;
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)
221 #[derive(Debug,Clone,Copy,Default,PartialEq)]
223 /// X coordinate of the vector.
225 /// Y coordinate of the vector.
229 #[allow(clippy::many_single_char_names)]
230 #[allow(clippy::collapsible_if)]
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.
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 {
243 if a.x < c.x { x = c.x; } else { x = a.x; }
247 if a.x < c.x { x = a.x; } else { x = c.x; }
257 if a.y < c.y { y = c.y; } else { y = a.y; }
261 if a.y < c.y { y = a.y; } else { y = c.y; }
270 /// Zero motion vector.
271 pub const ZERO_MV: MV = MV { x: 0, y: 0 };
275 fn add(self, other: MV) -> MV { MV { x: self.x + other.x, y: self.y + other.y } }
278 impl AddAssign for MV {
279 fn add_assign(&mut self, other: MV) { self.x += other.x; self.y += other.y; }
284 fn sub(self, other: MV) -> MV { MV { x: self.x - other.x, y: self.y - other.y } }
287 impl SubAssign for MV {
288 fn sub_assign(&mut self, other: MV) { self.x -= other.x; self.y -= other.y; }
293 fn neg(self) -> Self::Output {
294 MV { x: -self.x, y: -self.y }
298 impl fmt::Display for MV {
299 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
300 write!(f, "{},{}", self.x, self.y)
304 #[cfg(any(feature="blockdsp"))]
307 #[cfg(feature="h263")]
308 #[allow(clippy::collapsible_if)]
309 #[allow(clippy::manual_memcpy)]
310 #[allow(clippy::needless_range_loop)]
313 /// The common 8x8 zigzag scan.
314 pub const ZIGZAG: [usize; 64] = [
315 0, 1, 8, 16, 9, 2, 3, 10,
316 17, 24, 32, 25, 18, 11, 4, 5,
317 12, 19, 26, 33, 40, 48, 41, 34,
318 27, 20, 13, 6, 7, 14, 21, 28,
319 35, 42, 49, 56, 57, 50, 43, 36,
320 29, 22, 15, 23, 30, 37, 44, 51,
321 58, 59, 52, 45, 38, 31, 39, 46,
322 53, 60, 61, 54, 47, 55, 62, 63