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 self.lastframe.as_ref().cloned()
63 /// Frame manager for codecs with intra and inter frames.
65 /// This frame manager simplifies frame management for the case when codec decodes new frame using previous frame as source of some data.
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);
76 /// let ref_frame = ret.unwrap();
77 /// // keep decoding using data from ref_frame
79 /// shuffler.add_frame(frame.clone()); // tells frame manager to use the frame as the next reference
83 pub struct IPShuffler {
84 lastframe: Option<NAVideoBufferRef<u8>>,
88 /// Constructs a new instance of frame manager.
90 pub fn new() -> Self { IPShuffler { lastframe: None } }
91 /// Clears the reference.
93 pub fn clear(&mut self) { self.lastframe = None; }
94 /// Sets a new frame reference.
96 pub fn add_frame(&mut self, buf: NAVideoBufferRef<u8>) {
97 self.lastframe = Some(buf);
99 /// Returns the original saved reference frame or `None` if it is not present.
101 pub fn get_ref(&mut self) -> Option<NAVideoBufferRef<u8>> {
102 self.lastframe.as_ref().cloned()
106 /// Frame manager for codecs with I-, P- and B-frames.
108 /// This frame manager simplifies frame management for the case when codec uses I/P/B frame scheme.
113 /// let mut frame = allocate_video_frame();
114 /// for mb in all_macroblocks {
115 /// // decode macroblock type
117 /// MBType::Inter => {
118 /// do_mc(&mut frame, shuffler.get_lastref().unwrap());
120 /// MBType::BForward => {
121 /// do_mc(&mut frame, shuffler.get_b_fwdref().unwrap());
123 /// MBType::BBackward => {
124 /// do_mc(&mut frame, shuffler.get_b_bwdref().unwrap());
126 /// // handle the rest of cases
128 /// if is_random_access_frame {
129 /// shuffler.clear(); // remove all saved references
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
137 pub struct IPBShuffler {
138 lastframe: Option<NAVideoBufferRef<u8>>,
139 nextframe: Option<NAVideoBufferRef<u8>>,
143 /// Constructs a new instance of frame manager.
145 pub fn new() -> Self { IPBShuffler { lastframe: None, nextframe: None } }
146 /// Clears the reference.
148 pub fn clear(&mut self) { self.lastframe = None; self.nextframe = None; }
149 /// Sets a new frame reference.
151 pub fn add_frame(&mut self, buf: NAVideoBufferRef<u8>) {
152 mem::swap(&mut self.lastframe, &mut self.nextframe);
153 self.lastframe = Some(buf);
155 /// Returns the previous reference frame or `None` if it is not present.
157 pub fn get_lastref(&mut self) -> Option<NAVideoBufferRef<u8>> {
158 self.lastframe.as_ref().cloned()
160 /// Returns second last reference frame or `None` if it is not present.
162 pub fn get_nextref(&mut self) -> Option<NAVideoBufferRef<u8>> {
163 self.nextframe.as_ref().cloned()
165 /// Returns the temporally following reference for B-frame or `None` if it is not present.
167 pub fn get_b_fwdref(&mut self) -> Option<NAVideoBufferRef<u8>> {
168 self.nextframe.as_ref().cloned()
170 /// Returns the temporally preceeding reference for B-frame or `None` if it is not present.
172 pub fn get_b_bwdref(&mut self) -> Option<NAVideoBufferRef<u8>> {
173 self.lastframe.as_ref().cloned()
177 /// Motion vector data type.
182 /// use nihav_codec_support::codecs::MV;
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)
189 #[derive(Debug,Clone,Copy,Default,PartialEq)]
191 /// X coordinate of the vector.
193 /// Y coordinate of the vector.
197 #[allow(clippy::many_single_char_names)]
198 #[allow(clippy::collapsible_if)]
199 #[allow(clippy::collapsible_else_if)]
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.
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 {
212 if a.x < c.x { x = c.x; } else { x = a.x; }
216 if a.x < c.x { x = a.x; } else { x = c.x; }
226 if a.y < c.y { y = c.y; } else { y = a.y; }
230 if a.y < c.y { y = a.y; } else { y = c.y; }
239 /// Zero motion vector.
240 pub const ZERO_MV: MV = MV { x: 0, y: 0 };
244 fn add(self, other: MV) -> MV { MV { x: self.x + other.x, y: self.y + other.y } }
247 impl AddAssign for MV {
248 fn add_assign(&mut self, other: MV) { self.x += other.x; self.y += other.y; }
253 fn sub(self, other: MV) -> MV { MV { x: self.x - other.x, y: self.y - other.y } }
256 impl SubAssign for MV {
257 fn sub_assign(&mut self, other: MV) { self.x -= other.x; self.y -= other.y; }
262 fn neg(self) -> Self::Output {
263 MV { x: -self.x, y: -self.y }
267 impl fmt::Display for MV {
268 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
269 write!(f, "{},{}", self.x, self.y)
273 #[cfg(any(feature="blockdsp"))]
276 #[cfg(feature="h263")]
277 #[allow(clippy::collapsible_if)]
278 #[allow(clippy::manual_memcpy)]
279 #[allow(clippy::needless_range_loop)]
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