aac: clear M/S flags
[nihav.git] / nihav-duck / src / codecs / vp6.rs
index 20491ed6445c66ac4a7768ebd6923b2c3ae7956e..916711cddbc00b5392b75c4f1c7f6b28ba257f7e 100644 (file)
@@ -1,10 +1,10 @@
 use nihav_core::codecs::*;
 use nihav_core::io::bitreader::*;
 use nihav_codec_support::codecs::{MV, ZIGZAG};
-use nihav_codec_support::codecs::blockdsp::edge_emu;
 use super::vpcommon::*;
 use super::vp56::*;
 use super::vp6data::*;
+use super::vp6dsp::*;
 
 #[derive(Default)]
 struct VP6BR {
@@ -51,9 +51,9 @@ impl VP56Parser for VP6BR {
         if hdr.multistream || (hdr.profile == VP6_SIMPLE_PROFILE) {
             hdr.offset                          = br.read(16)? as u16;
             validate!(hdr.offset > if hdr.is_intra { 6 } else { 2 });
+            hdr.multistream = true;
         }
         let bytes = br.tell() >> 3;
-        std::mem::drop(br);
         bc.skip_bytes(bytes);
         self.loop_mode = 0;
         if hdr.is_intra {
@@ -472,138 +472,22 @@ fn decode_zero_run_huff(br: &mut BitReader, huff: &VP6Huff) -> DecoderResult<usi
     }
 }
 
-#[allow(clippy::too_many_arguments)]
-fn get_block(dst: &mut [u8], dstride: usize, src: NAVideoBufferRef<u8>, comp: usize,
-             dx: usize, dy: usize, mv_x: i16, mv_y: i16)
-{
-    let (w, h) = src.get_dimensions(comp);
-    let sx = (dx as isize) + (mv_x as isize);
-    let sy = (dy as isize) + (mv_y as isize);
-
-    if (sx - 2 < 0) || (sx + 8 + 2 > (w as isize)) ||
-       (sy - 2 < 0) || (sy + 8 + 2 > (h as isize)) {
-        edge_emu(&src, sx - 2, sy - 2, 8 + 2 + 2, 8 + 2 + 2,
-                 dst, dstride, comp, 0);
-    } else {
-        let sstride = src.get_stride(comp);
-        let soff    = src.get_offset(comp);
-        let sdta    = src.get_data();
-        let sbuf: &[u8] = sdta.as_slice();
-        let saddr = soff + ((sx - 2) as usize) + ((sy - 2) as usize) * sstride;
-        let src = &sbuf[saddr..];
-        for (dline, sline) in dst.chunks_mut(dstride).zip(src.chunks(sstride)).take(12) {
-            dline[..12].copy_from_slice(&sline[..12]);
-        }
-    }
-}
-
-fn calc_variance(src: &[u8], stride: usize) -> u16 {
-    let mut sum = 0;
-    let mut ssum = 0;
-    for line in src.chunks(stride * 2).take(4) {
-        for el in line.iter().take(8).step_by(2) {
-            let pix = u32::from(*el);
-            sum += pix;
-            ssum += pix * pix;
-        }
-    }
-    ((ssum * 16 - sum * sum) >> 8) as u16
-}
-
-macro_rules! mc_filter {
-    (bilinear; $a: expr, $b: expr, $c: expr) => {
-        ((u16::from($a) * (8 - $c) + u16::from($b) * $c + 4) >> 3) as u8
-    };
-    (bicubic; $src: expr, $off: expr, $step: expr, $coeffs: expr) => {
-        ((i32::from($src[$off - $step]    ) * i32::from($coeffs[0]) +
-          i32::from($src[$off]            ) * i32::from($coeffs[1]) +
-          i32::from($src[$off + $step]    ) * i32::from($coeffs[2]) +
-          i32::from($src[$off + $step * 2]) * i32::from($coeffs[3]) + 64) >> 7).min(255).max(0) as u8
-    }
-}
-
-//#[allow(snake_case)]
-fn mc_bilinear(dst: &mut [u8], dstride: usize, src: &[u8], mut soff: usize, sstride: usize, mx: u16, my: u16) {
-    if my == 0 {
-        for dline in dst.chunks_mut(dstride).take(8) {
-            for i in 0..8 {
-                dline[i] = mc_filter!(bilinear; src[soff + i], src[soff + i + 1], mx);
-            }
-            soff += sstride;
-        }
-    } else if mx == 0 {
-        for dline in dst.chunks_mut(dstride).take(8) {
-            for i in 0..8 {
-                dline[i] = mc_filter!(bilinear; src[soff + i], src[soff + i + sstride], my);
-            }
-            soff += sstride;
-        }
-    } else {
-        let mut tmp = [0u8; 8];
-        for i in 0..8 {
-            tmp[i] = mc_filter!(bilinear; src[soff + i], src[soff + i + 1], mx);
-        }
-        soff += sstride;
-        for dline in dst.chunks_mut(dstride).take(8) {
-            for i in 0..8 {
-                let cur = mc_filter!(bilinear; src[soff + i], src[soff + i + 1], mx);
-                dline[i] = mc_filter!(bilinear; tmp[i], cur, my);
-                tmp[i] = cur;
-            }
-            soff += sstride;
-        }
-    }
-}
-
-#[allow(clippy::trivially_copy_pass_by_ref)]
-fn mc_bicubic(dst: &mut [u8], dstride: usize, src: &[u8], mut soff: usize, sstride: usize, coeffs_w: &[i16; 4], coeffs_h: &[i16; 4]) {
-    if coeffs_h[1] == 128 {
-        for dline in dst.chunks_mut(dstride).take(8) {
-            for i in 0..8 {
-                dline[i] = mc_filter!(bicubic; src, soff + i, 1, coeffs_w);
-            }
-            soff += sstride;
-        }
-    } else if coeffs_w[1] == 128 { // horizontal-only interpolation
-        for dline in dst.chunks_mut(dstride).take(8) {
-            for i in 0..8 {
-                dline[i] = mc_filter!(bicubic; src, soff + i, sstride, coeffs_h);
-            }
-            soff += sstride;
-        }
-    } else {
-        let mut buf = [0u8; 16 * 11];
-        soff -= sstride;
-        for dline in buf.chunks_mut(16) {
-            for i in 0..8 {
-                dline[i] = mc_filter!(bicubic; src, soff + i, 1, coeffs_w);
-            }
-            soff += sstride;
-        }
-        let mut soff = 16;
-        for dline in dst.chunks_mut(dstride).take(8) {
-            for i in 0..8 {
-                dline[i] = mc_filter!(bicubic; buf, soff + i, 16, coeffs_h);
-            }
-            soff += 16;
-        }
-    }
-}
-
 struct VP6Decoder {
     dec:        VP56Decoder,
     info:       NACodecInfoRef,
     br:         VP6BR,
     has_alpha:  bool,
+    flipped:    bool,
 }
 
 impl VP6Decoder {
-    fn new(has_alpha: bool) -> Self {
+    fn new(flipped: bool, has_alpha: bool) -> Self {
         Self {
-            dec:        VP56Decoder::new(6, has_alpha, true),
+            dec:        VP56Decoder::new(6, has_alpha, flipped),
             info:       NACodecInfoRef::default(),
             br:         VP6BR::new(),
             has_alpha,
+            flipped,
         }
     }
 }
@@ -616,7 +500,15 @@ impl NADecoder for VP6Decoder {
                 } else {
                     VP_YUVA420_FORMAT
                 };
-            let myvinfo = NAVideoInfo::new(vinfo.get_width(), vinfo.get_height(), false, fmt);
+            let mut width  = vinfo.get_width();
+            let mut height = vinfo.get_height();
+            if let (false, Some(edta)) = (self.flipped, info.get_extradata()) {
+                if (width & 0xF) == 0 && (height & 0xF) == 0 {
+                    width  -= usize::from(edta[0] >> 4);
+                    height -= usize::from(edta[0] & 0xF);
+                }
+            }
+            let myvinfo = NAVideoInfo::new(width, height, self.flipped, fmt);
             let myinfo = NACodecTypeInfo::Video(myvinfo);
             self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref();
             self.dec.init(supp, myvinfo)?;
@@ -647,11 +539,15 @@ impl NAOptionHandler for VP6Decoder {
 }
 
 pub fn get_decoder_vp6() -> Box<dyn NADecoder + Send> {
-    Box::new(VP6Decoder::new(false))
+    Box::new(VP6Decoder::new(true, false))
+}
+
+pub fn get_decoder_vp6f() -> Box<dyn NADecoder + Send> {
+    Box::new(VP6Decoder::new(false, false))
 }
 
 pub fn get_decoder_vp6_alpha() -> Box<dyn NADecoder + Send> {
-    Box::new(VP6Decoder::new(true))
+    Box::new(VP6Decoder::new(false, true))
 }
 
 #[cfg(test)]
@@ -669,6 +565,7 @@ mod test {
         let mut dec_reg = RegisteredDecoders::new();
         duck_register_all_decoders(&mut dec_reg);
 
+        // sample from a private collection
         test_decoding("avi", "vp6", "assets/Duck/selection_720x576_300kBit_vp60i.avi", Some(16),
                       &dmx_reg, &dec_reg,
                       ExpectedTestResult::MD5([0x042c3e96, 0x8a9b26a2, 0x4dcbaf66, 0x1b788d03]));
@@ -680,6 +577,7 @@ mod test {
         let mut dec_reg = RegisteredDecoders::new();
         duck_register_all_decoders(&mut dec_reg);
 
+        // sample: https://samples.mplayerhq.hu/V-codecs/VP6/vp6_crash.avi
         test_decoding("avi", "vp6", "assets/Duck/vp6_crash.avi", Some(4),
                       &dmx_reg, &dec_reg, ExpectedTestResult::MD5Frames(vec![
                             [0xdcd70fa0, 0x0d075ce2, 0xc9e65077, 0xb003a92e],
@@ -688,5 +586,41 @@ mod test {
                             [0x11b048ac, 0xedb3e471, 0xd04e9399, 0x64e623e3],
                             [0x182871b1, 0x2146893a, 0x2912210e, 0x6dd592e8]]));
     }
-    // todo find good sample for vp6a test
+    #[test]
+    fn test_vp6_alpha() {
+        let mut dmx_reg = RegisteredDemuxers::new();
+        generic_register_all_demuxers(&mut dmx_reg);
+        let mut dec_reg = RegisteredDecoders::new();
+        duck_register_all_decoders(&mut dec_reg);
+
+        // sample created by remuxing some VP6A in FLV
+        test_decoding("avi", "vp6a", "assets/Duck/vp6a.avi", Some(25),
+                      &dmx_reg, &dec_reg, ExpectedTestResult::MD5Frames(vec![
+                            [0xaf903d79, 0x17ddb3c7, 0xf0a381e8, 0x26b36a7d],
+                            [0xaf903d79, 0x17ddb3c7, 0xf0a381e8, 0x26b36a7d],
+                            [0xaf903d79, 0x17ddb3c7, 0xf0a381e8, 0x26b36a7d],
+                            [0xaf903d79, 0x17ddb3c7, 0xf0a381e8, 0x26b36a7d],
+                            [0xaf903d79, 0x17ddb3c7, 0xf0a381e8, 0x26b36a7d],
+                            [0xaf903d79, 0x17ddb3c7, 0xf0a381e8, 0x26b36a7d],
+                            [0xaf903d79, 0x17ddb3c7, 0xf0a381e8, 0x26b36a7d],
+                            [0xaf903d79, 0x17ddb3c7, 0xf0a381e8, 0x26b36a7d],
+                            [0xaf903d79, 0x17ddb3c7, 0xf0a381e8, 0x26b36a7d],
+                            [0xaf903d79, 0x17ddb3c7, 0xf0a381e8, 0x26b36a7d],
+                            [0xaf903d79, 0x17ddb3c7, 0xf0a381e8, 0x26b36a7d],
+                            [0xaf903d79, 0x17ddb3c7, 0xf0a381e8, 0x26b36a7d],
+                            [0xaf903d79, 0x17ddb3c7, 0xf0a381e8, 0x26b36a7d],
+                            [0xaf903d79, 0x17ddb3c7, 0xf0a381e8, 0x26b36a7d],
+                            [0xaf903d79, 0x17ddb3c7, 0xf0a381e8, 0x26b36a7d],
+                            [0xaf903d79, 0x17ddb3c7, 0xf0a381e8, 0x26b36a7d],
+                            [0xaf903d79, 0x17ddb3c7, 0xf0a381e8, 0x26b36a7d],
+                            [0xaf903d79, 0x17ddb3c7, 0xf0a381e8, 0x26b36a7d],
+                            [0xaf903d79, 0x17ddb3c7, 0xf0a381e8, 0x26b36a7d],
+                            [0xaf903d79, 0x17ddb3c7, 0xf0a381e8, 0x26b36a7d],
+                            [0xaf903d79, 0x17ddb3c7, 0xf0a381e8, 0x26b36a7d],
+                            [0xaf903d79, 0x17ddb3c7, 0xf0a381e8, 0x26b36a7d],
+                            [0xd3801a96, 0x1b5384ff, 0x422b228c, 0x9c4582c4],
+                            [0x8ddb0dfe, 0x302eb1ed, 0x10e64e22, 0x5a5a62b9],
+                            [0x79338328, 0x06113781, 0x8b116d18, 0xde56707e],
+                            [0xdb58433b, 0x1de4ce67, 0x15fcbcee, 0x1df9de61]]));
+    }
 }