zoomvtools 1.1.1

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

use num_traits::clamp;

use crate::util::{Pixel, round_ties_to_even};
use semisafe::option::unwrap as semisafe_opt_unwrap;
use semisafe::slice::get as semisafe_get;
use semisafe::slice::get_mut as semisafe_get_mut;

/// Scalar reference implementation of `DctHelper::float_src_to_pixels`.
///
/// Converts contiguous `src_dct` rows of width `size_x` into `dst` rows with
/// stride `dst_pitch`. The DC coefficient at index 0 uses `dct_shift0` and a
/// `0.5` scale factor; all other coefficients use `dct_shift` and `sqrt(2)/2`.
///
/// CONTRACT: `src_dct.len() >= size_x * size_y`, `dst.len() >= dst_pitch * size_y`.
pub(super) fn float_src_to_pixels<T: Pixel>(
    dst: &mut [T],
    dst_pitch: NonZeroUsize,
    src_dct: &[f32],
    size_x: NonZeroUsize,
    size_y: NonZeroUsize,
    bits_per_sample: NonZeroU8,
    dct_shift: usize,
    dct_shift0: usize,
) {
    let sqrt_2_div_2: f32 = (2f32).sqrt() / 2.0;

    // Have to do math in larger type to avoid overflow.
    let pixel_max = (1 << bits_per_sample.get() as usize) - 1;
    let pixel_half = 1 << (bits_per_sample.get() as usize - 1);

    for j in 0..size_y.get() {
        let real_data = semisafe_get(semisafe_get(src_dct, j * size_x.get()..), ..size_x.get());
        let dst = semisafe_get_mut(semisafe_get_mut(dst, j * dst_pitch.get()..), ..size_x.get());
        for (f, p) in real_data.iter().zip(dst.iter_mut()) {
            // to be compatible with integer DCTINT8
            let f = *f * sqrt_2_div_2;
            let integ = round_ties_to_even(f) as i32;
            *p = semisafe_opt_unwrap(T::from(clamp(
                (integ >> dct_shift) + pixel_half,
                0,
                pixel_max,
            )));
        }
    }

    // to be compatible with integer DCTINT8
    let f = *semisafe_get(src_dct, 0) * 0.5;
    let integ = round_ties_to_even(f) as i32;
    *semisafe_get_mut(dst, 0) = semisafe_opt_unwrap(T::from(clamp(
        (integ >> dct_shift0) + pixel_half,
        0,
        pixel_max,
    )));
}