zoomvtools 2.0.0

Video motion vector analysis utilities in pure Rust
Documentation
use std::num::NonZeroUsize;

use crate::{fake::block_data::FakeBlockData, mv::MotionVector, params::Subpel};
use semisafe::slice::get as semisafe_get;
use semisafe::slice::get_mut as semisafe_get_mut;

pub(crate) struct FakePlaneOfBlocks {
    /// width in number of blocks
    pub(crate) blk_x: NonZeroUsize,
    /// height in number of blocks
    pub(crate) blk_y: NonZeroUsize,
    /// width of a block
    pub(crate) blk_size_x: NonZeroUsize,
    /// height of a block
    pub(crate) blk_size_y: NonZeroUsize,
    /// number of blocks in the plane (isn't this just `blk_x` * `blk_y`?)
    pub(crate) blk_count: NonZeroUsize,
    pub(crate) pel: Subpel,
    /// horizontal overlap of blocks
    pub(crate) overlap_x: usize,
    /// vertical overlap of blocks
    pub(crate) overlap_y: usize,
    pub(crate) blocks: Vec<FakeBlockData>,
}

impl FakePlaneOfBlocks {
    #[must_use]
    #[inline]
    pub fn new(
        blk_size_x: NonZeroUsize,
        blk_size_y: NonZeroUsize,
        pel: Subpel,
        overlap_x: usize,
        overlap_y: usize,
        blk_x: NonZeroUsize,
        blk_y: NonZeroUsize,
    ) -> Self {
        let blk_count = blk_x.saturating_mul(blk_y);
        let mut blocks = Vec::with_capacity(blk_count.get());
        for j in 0..blk_y.get() {
            for i in 0..blk_x.get() {
                let block = FakeBlockData {
                    x: (i * (blk_size_x.get() - overlap_x)) as _,
                    y: (j * (blk_size_y.get() - overlap_y)) as _,
                    vector: MotionVector::zero(),
                };
                blocks.push(block);
            }
        }

        FakePlaneOfBlocks {
            blk_x,
            blk_y,
            blk_size_x,
            blk_size_y,
            blk_count,
            pel,
            overlap_x,
            overlap_y,
            blocks,
        }
    }

    pub(crate) fn update(&mut self, data: &[u8]) {
        // SAFETY: we know the size and layout of the data
        let blocks: &[MotionVector] = unsafe {
            core::ptr::slice_from_raw_parts(
                data as *const [u8] as *const MotionVector,
                self.blk_count.get(),
            )
            .as_ref()
        }
        .expect("reference should be valid");

        for i in 0..self.blk_count.get() {
            semisafe_get_mut(&mut self.blocks, i).update(*semisafe_get(blocks, i));
        }
    }

    pub(crate) fn get_block(&self, blk: usize) -> &FakeBlockData {
        semisafe_get(&self.blocks, blk)
    }

    pub(crate) fn is_scenechange(&self, thscd1: u64, thscd2: u64) -> bool {
        let sum = self
            .blocks
            .iter()
            .filter(|blk| blk.vector.sad > thscd1 as i64)
            .count();
        sum > thscd2 as usize
    }
}