zoomvtools 1.1.1

Video motion vector analysis utilities in pure Rust
Documentation
mod block_functions;
#[cfg(all(target_arch = "x86_64", feature = "avx2"))]
mod cpu;
mod fps;
mod mask;
mod math;
#[cfg(test)]
mod tests;

use semisafe::slice::get as semisafe_get;
use semisafe::slice::get_mut as semisafe_get_mut;
use std::{
    fmt::Display,
    mem::{ManuallyDrop, MaybeUninit},
};

pub use crate::frame::PlaneSizeTuple;
pub use block_functions::*;

#[cfg(all(target_arch = "x86_64", feature = "avx2"))]
pub use cpu::*;
pub use fps::*;
pub use mask::*;
pub use math::*;
use num_traits::{AsPrimitive, PrimInt};

/// Represents a pixel that can be `u8` or `u16`
pub trait Pixel:
    Copy
    + Clone
    + Default
    + Send
    + Sync
    + PrimInt
    + Display
    + AsPrimitive<u16>
    + AsPrimitive<u32>
    + AsPrimitive<u64>
    + AsPrimitive<i32>
    + AsPrimitive<i64>
    + 'static
{
    #[must_use]
    /// Converts from `u32`, saturating to the pixel type's maximum on overflow.
    fn from_u32_or_max_value(value: u32) -> Self;
}

impl<T> Pixel for T
where
    T: Copy
        + Clone
        + Default
        + Send
        + Sync
        + PrimInt
        + Display
        + AsPrimitive<u16>
        + AsPrimitive<u32>
        + AsPrimitive<u64>
        + AsPrimitive<i32>
        + AsPrimitive<i64>
        + 'static,
{
    #[inline(always)]
    fn from_u32_or_max_value(value: u32) -> Self {
        Self::from(value).unwrap_or_else(Self::max_value)
    }
}

#[cfg_attr(feature = "tracing", tracing::instrument(skip_all))]
#[inline]
/// Copies a padded plane from `src` to `dest` using pixel strides.
pub fn vs_bitblt<T: Pixel>(
    dest: &mut [T],
    dest_stride_pixels: std::num::NonZeroUsize,
    src: &[T],
    src_stride_pixels: std::num::NonZeroUsize,
    row_size: std::num::NonZeroUsize,
    height: std::num::NonZeroUsize,
) {
    let height = height.get();
    let row_size = row_size.get();
    let src_stride = src_stride_pixels.get();
    let dest_stride = dest_stride_pixels.get();

    if src_stride == dest_stride && src_stride == row_size {
        semisafe_get_mut(dest, ..row_size * height)
            .copy_from_slice(semisafe_get(src, ..row_size * height));
    } else {
        for i in 0..height {
            let src_start = i * src_stride;
            let dest_start = i * dest_stride;
            semisafe_get_mut(semisafe_get_mut(dest, dest_start..), ..row_size)
                .copy_from_slice(semisafe_get(semisafe_get(src, src_start..), ..row_size));
        }
    }
}

#[inline(always)]
#[must_use]
/// Allocates a vector of uninitialized elements for callers that fill every slot.
pub fn uninit_vec<T>(len: usize) -> Vec<MaybeUninit<T>> {
    let mut values = Vec::with_capacity(len);
    // SAFETY: `MaybeUninit<T>` may be left uninitialized until callers write every slot.
    unsafe { values.set_len(len) };
    values
}

#[inline(always)]
#[must_use]
/// # Safety
///
/// The caller must guarantee that every element in `values` has been initialized.
pub unsafe fn assume_init_vec<T>(values: Vec<MaybeUninit<T>>) -> Vec<T> {
    let mut values = ManuallyDrop::new(values);
    let ptr = values.as_mut_ptr().cast::<T>();
    let len = values.len();
    let cap = values.capacity();

    // SAFETY: Caller guarantees all elements have been initialized.
    unsafe { Vec::from_raw_parts(ptr, len, cap) }
}