]> git.nihav.org Git - nihav.git/blobdiff - nihav-core/src/scale/mod.rs
avimux: do not record palette change chunks in OpenDML index
[nihav.git] / nihav-core / src / scale / mod.rs
index 6c1daa9f0f71597a71cb0b36d8ebbccab1cfe85b..93d42a4148e374079e458ab73326a64cea83524f 100644 (file)
@@ -20,6 +20,7 @@ use crate::frame::*;
 mod kernel;
 
 mod colorcvt;
+mod fill;
 mod repack;
 #[allow(clippy::module_inception)]
 mod scale;
@@ -91,6 +92,7 @@ const KERNELS: &[KernelDesc] = &[
     KernelDesc { name: "depal",         create: repack::create_depal },
     KernelDesc { name: "palette",       create: palette::create_palettise },
     KernelDesc { name: "scale",         create: scale::create_scale },
+    KernelDesc { name: "fill",          create: fill::create_fill },
     KernelDesc { name: "rgb_to_yuv",    create: colorcvt::create_rgb2yuv },
     KernelDesc { name: "yuv_to_rgb",    create: colorcvt::create_yuv2rgb },
 ];
@@ -159,9 +161,34 @@ fn check_format(in_fmt: NAVideoInfo, ref_fmt: &ScaleInfo, just_convert: bool) ->
 fn copy(pic_in: &NABufferType, pic_out: &mut NABufferType)
 {
     if let (Some(ref sbuf), Some(ref mut dbuf)) = (pic_in.get_vbuf(), pic_out.get_vbuf()) {
+        if sbuf.get_info().get_format().is_paletted() {
+            let same = sbuf.get_stride(0) == dbuf.get_stride(0) && sbuf.get_offset(1) == dbuf.get_offset(1);
+            if same {
+                let src = sbuf.get_data();
+                let dst = dbuf.get_data_mut().unwrap();
+                dst.copy_from_slice(src);
+            } else {
+                let (_, h) = sbuf.get_dimensions(0);
+                let soff = sbuf.get_offset(0);
+                let spoff = sbuf.get_offset(1);
+                let sstride = sbuf.get_stride(0);
+                let src = sbuf.get_data();
+                let doff = dbuf.get_offset(0);
+                let dpoff = dbuf.get_offset(1);
+                let dstride = dbuf.get_stride(0);
+                let dst = dbuf.get_data_mut().unwrap();
+                let copy_size = sstride.min(dstride);
+                for (dline, sline) in dst[doff..].chunks_exact_mut(dstride).take(h).zip(src[soff..].chunks_exact(sstride)) {
+                    dline[..copy_size].copy_from_slice(&sline[..copy_size]);
+                }
+                dst[dpoff..].copy_from_slice(&src[spoff..]);
+            }
+            return;
+        }
         let mut same = true;
-        let num_components = sbuf.get_info().get_format().get_num_comp();
-        for i in 0..num_components {
+        let src_components = sbuf.get_info().get_format().get_num_comp();
+        let dst_components = dbuf.get_info().get_format().get_num_comp();
+        for i in 0..src_components.max(dst_components) {
             if sbuf.get_stride(i) != dbuf.get_stride(i) {
                 same = false;
                 break;
@@ -177,7 +204,7 @@ fn copy(pic_in: &NABufferType, pic_out: &mut NABufferType)
             ddata.copy_from_slice(&sdata[0..]);
         } else {
             let sdata = sbuf.get_data();
-            for comp in 0..num_components {
+            for comp in 0..src_components.min(dst_components) {
                 let (_, h) = sbuf.get_dimensions(comp);
                 let src = &sdata[sbuf.get_offset(comp)..];
                 let sstride = sbuf.get_stride(comp);
@@ -187,14 +214,15 @@ fn copy(pic_in: &NABufferType, pic_out: &mut NABufferType)
                 let dst = &mut ddata[doff..];
                 let copy_size = sstride.min(dstride);
                 for (dline, sline) in dst.chunks_exact_mut(dstride).take(h).zip(src.chunks_exact(sstride)) {
-                    (&mut dline[..copy_size]).copy_from_slice(&sline[..copy_size]);
+                    dline[..copy_size].copy_from_slice(&sline[..copy_size]);
                 }
             }
         }
     } else if let (Some(ref sbuf), Some(ref mut dbuf)) = (pic_in.get_vbuf16(), pic_out.get_vbuf16()) {
         let mut same = true;
-        let num_components = sbuf.get_info().get_format().get_num_comp();
-        for i in 0..num_components {
+        let src_components = sbuf.get_info().get_format().get_num_comp();
+        let dst_components = dbuf.get_info().get_format().get_num_comp();
+        for i in 0..src_components.max(dst_components) {
             if sbuf.get_stride(i) != dbuf.get_stride(i) {
                 same = false;
                 break;
@@ -210,7 +238,7 @@ fn copy(pic_in: &NABufferType, pic_out: &mut NABufferType)
             ddata.copy_from_slice(&sdata[0..]);
         } else {
             let sdata = sbuf.get_data();
-            for comp in 0..num_components {
+            for comp in 0..src_components.min(dst_components) {
                 let (_, h) = sbuf.get_dimensions(comp);
                 let src = &sdata[sbuf.get_offset(comp)..];
                 let sstride = sbuf.get_stride(comp);
@@ -220,7 +248,7 @@ fn copy(pic_in: &NABufferType, pic_out: &mut NABufferType)
                 let dst = &mut ddata[doff..];
                 let copy_size = sstride.min(dstride);
                 for (dline, sline) in dst.chunks_exact_mut(dstride).take(h).zip(src.chunks_exact(sstride)) {
-                    (&mut dline[..copy_size]).copy_from_slice(&sline[..copy_size]);
+                    dline[..copy_size].copy_from_slice(&sline[..copy_size]);
                 }
             }
         }
@@ -333,6 +361,16 @@ fn build_pipeline(ifmt: &ScaleInfo, ofmt: &ScaleInfo, just_convert: bool, option
         cur_fmt = new_stage.fmt_out;
         add_stage!(stages, new_stage);
     }
+    let icomponents = cur_fmt.fmt.components - if cur_fmt.fmt.alpha { 1 } else { 0 };
+    let ocomponents = ofmt.fmt.components - if ofmt.fmt.alpha { 1 } else { 0 };
+    if !needs_palettise && ((!cur_fmt.fmt.alpha && ofmt.fmt.alpha) || (icomponents < ocomponents)) {
+        if debug {
+            println!("[adding fill]");
+        }
+        let new_stage = Stage::new("fill", &cur_fmt, ofmt, options)?;
+        cur_fmt = new_stage.fmt_out;
+        add_stage!(stages, new_stage);
+    }
     if needs_pack && !needs_palettise {
         if debug {
             println!("[adding pack]");
@@ -363,8 +401,8 @@ fn swap_plane<T:Copy>(data: &mut [T], stride: usize, h: usize, line0: &mut [T],
     for _ in 0..h/2 {
         line0.copy_from_slice(&data[doff0..][..stride]);
         line1.copy_from_slice(&data[doff1..][..stride]);
-        (&mut data[doff1..][..stride]).copy_from_slice(line0);
-        (&mut data[doff0..][..stride]).copy_from_slice(line1);
+        data[doff1..][..stride].copy_from_slice(line0);
+        data[doff0..][..stride].copy_from_slice(line1);
         doff0 += stride;
         doff1 -= stride;
     }
@@ -595,4 +633,60 @@ mod test {
         assert_eq!(odata[paloff + 1], 129);
         assert_eq!(odata[paloff + 2], 170);
     }
+    #[test]
+    fn test_scale_modes() {
+        const IN_DATA: [[u8; 6]; 2] = [
+            [0xFF, 0xC0, 0x40, 0x00, 0x40, 0xC0],
+            [0x00, 0x40, 0xC0, 0xFF, 0xC0, 0x40]
+        ];
+        const TEST_DATA: &[(&str, [[u8; 9]; 3])] = &[
+            ("nn",
+               [[0xFF, 0xC0, 0x40, 0xFF, 0xC0, 0x40, 0x00, 0x40, 0xC0],
+                [0xFF, 0xC0, 0x40, 0xFF, 0xC0, 0x40, 0x00, 0x40, 0xC0],
+                [0x00, 0x40, 0xC0, 0x00, 0x40, 0xC0, 0xFF, 0xC0, 0x40]]),
+            ("bilin",
+               [[0xFF, 0xC0, 0x40, 0x55, 0x6A, 0x95, 0x00, 0x40, 0xC0],
+                [0x55, 0x6A, 0x95, 0x8D, 0x86, 0x78, 0xAA, 0x95, 0x6A],
+                [0x00, 0x40, 0xC0, 0xAA, 0x95, 0x6A, 0xFF, 0xC0, 0x40]]),
+            ("bicubic",
+               [[0xFF, 0xC0, 0x40, 0x4B, 0x65, 0x9A, 0x00, 0x36, 0xC9],
+                [0x4B, 0x65, 0x9A, 0x94, 0x8A, 0x74, 0xB3, 0x9D, 0x61],
+                [0x00, 0x36, 0xC9, 0xBA, 0x9D, 0x61, 0xFF, 0xD3, 0x2B]]),
+            ("lanczos",
+               [[0xFF, 0xC0, 0x40, 0x4C, 0x66, 0x98, 0x00, 0x31, 0xCD],
+                [0x4C, 0x66, 0x98, 0x91, 0x88, 0x74, 0xB1, 0x9D, 0x5F],
+                [0x00, 0x31, 0xCD, 0xBB, 0x9D, 0x5F, 0xFF, 0xDD, 0x1E]]),
+            ("lanczos2",
+               [[0xFF, 0xC0, 0x40, 0x4F, 0x68, 0x9B, 0x00, 0x35, 0xCD],
+                [0x4F, 0x68, 0x9B, 0x96, 0x8D, 0x79, 0xB3, 0xA0, 0x64],
+                [0x00, 0x35, 0xCD, 0xBE, 0xA1, 0x65, 0xFF, 0xDC, 0x28]]),
+        ];
+
+        let in_pic = alloc_video_buffer(NAVideoInfo::new(2, 2, false, RGB24_FORMAT), 3).unwrap();
+        if let Some(ref mut vbuf) = in_pic.get_vbuf() {
+            let stride = vbuf.get_stride(0);
+            let data = vbuf.get_data_mut().unwrap();
+            for (dline, rline) in data.chunks_mut(stride).zip(IN_DATA.iter()) {
+                dline[..6].copy_from_slice(rline);
+            }
+        } else {
+            panic!("wrong format");
+        }
+        let mut out_pic = alloc_video_buffer(NAVideoInfo::new(3, 3, false, RGB24_FORMAT), 3).unwrap();
+        let ifmt = get_scale_fmt_from_pic(&in_pic);
+        let ofmt = get_scale_fmt_from_pic(&out_pic);
+        for (method, ref_data) in TEST_DATA.iter() {
+            fill_pic(&mut out_pic, 0);
+            let mut scaler = NAScale::new_with_options(ifmt, ofmt, &[("scaler".to_string(), method.to_string())]).unwrap();
+            scaler.convert(&in_pic, &mut out_pic).unwrap();
+            let obuf = out_pic.get_vbuf().unwrap();
+            let ostride = obuf.get_stride(0);
+            let odata = obuf.get_data();
+            for (oline, rline) in odata.chunks(ostride).zip(ref_data.iter()) {
+                for (&a, &b) in oline.iter().zip(rline.iter()) {
+                    assert_eq!(a, b);
+                }
+            }
+        }
+    }
 }