zoomvtools 1.1.1

Video motion vector analysis utilities in pure Rust
Documentation
use std::{num::NonZeroUsize, ptr::copy_nonoverlapping};

use crate::util::Pixel;

pub type CopyFn = unsafe fn(
    dest: *mut u8,
    dest_stride_bytes: NonZeroUsize,
    src: *const u8,
    src_stride_bytes: NonZeroUsize,
);

#[must_use]
#[inline]
pub fn select_copy<T: Pixel>(width: NonZeroUsize, height: NonZeroUsize) -> CopyFn {
    match (width.get(), height.get()) {
        (2, 2) => copy_impl::<T, 2, 2>,
        (2, 4) => copy_impl::<T, 2, 4>,
        (4, 2) => copy_impl::<T, 4, 2>,
        (4, 4) => copy_impl::<T, 4, 4>,
        (4, 8) => copy_impl::<T, 4, 8>,
        (8, 1) => copy_impl::<T, 8, 1>,
        (8, 2) => copy_impl::<T, 8, 2>,
        (8, 4) => copy_impl::<T, 8, 4>,
        (8, 8) => copy_impl::<T, 8, 8>,
        (8, 16) => copy_impl::<T, 8, 16>,
        (16, 1) => copy_impl::<T, 16, 1>,
        (16, 2) => copy_impl::<T, 16, 2>,
        (16, 4) => copy_impl::<T, 16, 4>,
        (16, 8) => copy_impl::<T, 16, 8>,
        (16, 16) => copy_impl::<T, 16, 16>,
        (16, 32) => copy_impl::<T, 16, 32>,
        (32, 8) => copy_impl::<T, 32, 8>,
        (32, 16) => copy_impl::<T, 32, 16>,
        (32, 32) => copy_impl::<T, 32, 32>,
        (32, 64) => copy_impl::<T, 32, 64>,
        (64, 16) => copy_impl::<T, 64, 16>,
        (64, 32) => copy_impl::<T, 64, 32>,
        (64, 64) => copy_impl::<T, 64, 64>,
        (64, 128) => copy_impl::<T, 64, 128>,
        (128, 32) => copy_impl::<T, 128, 32>,
        (128, 64) => copy_impl::<T, 128, 64>,
        (128, 128) => copy_impl::<T, 128, 128>,
        _ => panic!("unsupported block size for copy: {}x{}", width, height),
    }
}

unsafe fn copy_impl<T: Pixel, const WIDTH: usize, const HEIGHT: usize>(
    dest: *mut u8,
    dest_stride_bytes: NonZeroUsize,
    src: *const u8,
    src_stride_bytes: NonZeroUsize,
) {
    // The C code does manual unrolling here, but we can let the compiler handle it.
    for j in 0..HEIGHT {
        copy_nonoverlapping(
            src.add(src_stride_bytes.get() * j),
            dest.add(dest_stride_bytes.get() * j),
            WIDTH * size_of::<T>(),
        );
    }
}