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 {
}
}
-#[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,
}
}
}
} 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)?;
}
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)]
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]));
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],
[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]]));
+ }
}