zoomvtools 2.0.0

Video motion vector analysis utilities in pure Rust
Documentation
#![allow(clippy::indexing_slicing, reason = "allow in test files")]
#![allow(clippy::unwrap_used, reason = "allow in test files")]

use std::num::NonZeroUsize;

use super::{Frame, FramePlanes, FramePlanesMut, PlaneRef};

#[test]
fn frame_planes_returns_requested_plane() {
    let y = [1u8, 2, 3, 4];
    let planes = FramePlanes::new([Some(PlaneRef::new(&y)), None, None]);

    assert_eq!(planes.plane(0).unwrap(), &y);
}

#[test]
fn frame_planes_reports_missing_plane() {
    let planes = FramePlanes::<u8>::new([None, None, None]);

    let err = planes.plane(0).unwrap_err();
    assert!(
        err.to_string()
            .contains("requested plane 0 is not available")
    );
}

#[test]
fn frame_planes_mut_can_write_plane() {
    let mut y = [0u8; 4];
    let mut planes = FramePlanesMut::new([Some(&mut y), None, None]);

    planes.plane_mut(0).unwrap().copy_from_slice(&[5, 6, 7, 8]);

    assert_eq!(planes.plane(0).unwrap(), &[5, 6, 7, 8]);
}

#[test]
fn frame_planes_mut_split_exposes_shared_backing() {
    let mut y = [10u8, 20, 30, 40];
    let mut planes = FramePlanesMut::new([Some(&mut y), None, None]);

    // SAFETY: Test reads and writes disjoint logical usage through the returned views.
    let (src, dst) = unsafe { planes.plane_split(0).unwrap() };
    assert_eq!(src, &[10, 20, 30, 40]);
    dst[2] = 99;

    assert_eq!(planes.plane(0).unwrap(), &[10, 20, 99, 40]);
}

#[test]
fn owned_frame_exposes_borrowed_frame_planes() {
    let y = super::FramePlane::new(
        vec![1u8, 2, 3, 4].into_boxed_slice(),
        NonZeroUsize::new(2).unwrap(),
        NonZeroUsize::new(2).unwrap(),
        NonZeroUsize::new(2).unwrap(),
    )
    .unwrap();
    let frame = super::Frame::new([Some(y), None, None]);

    let planes = frame.as_planes();

    assert_eq!(planes.plane(0).unwrap(), &[1, 2, 3, 4]);
}

#[test]
fn owned_frame_rejects_plane_shorter_than_stride_times_height() {
    let err = super::FramePlane::new(
        vec![0u8; 3].into_boxed_slice(),
        NonZeroUsize::new(2).unwrap(),
        NonZeroUsize::new(2).unwrap(),
        NonZeroUsize::new(2).unwrap(),
    )
    .unwrap_err();

    assert!(
        err.to_string()
            .contains("plane data is shorter than stride * height")
    );
}

#[test]
fn owned_frame_can_build_borrowed_view_with_pitch() {
    let y = super::FramePlane::new(
        vec![1u8, 2, 3, 4].into_boxed_slice(),
        NonZeroUsize::new(2).unwrap(),
        NonZeroUsize::new(2).unwrap(),
        NonZeroUsize::new(2).unwrap(),
    )
    .unwrap();
    let frame = Frame::new([Some(y), None, None]);

    let view = frame.as_view().unwrap();

    assert_eq!(view.plane(0).unwrap(), &[1, 2, 3, 4]);
    assert_eq!(view.pitch().0.get(), 2);
    assert!(view.pitch().1.is_none());
    assert!(view.pitch().2.is_none());
}

#[test]
fn frame_view_reports_plane_count_and_pitch_per_plane() {
    let y = super::FramePlane::new(
        vec![1u8, 2, 3, 4, 5, 6].into_boxed_slice(),
        NonZeroUsize::new(2).unwrap(),
        NonZeroUsize::new(2).unwrap(),
        NonZeroUsize::new(3).unwrap(),
    )
    .unwrap();
    let u = super::FramePlane::new(
        vec![7u8, 8].into_boxed_slice(),
        NonZeroUsize::new(1).unwrap(),
        NonZeroUsize::new(1).unwrap(),
        NonZeroUsize::new(2).unwrap(),
    )
    .unwrap();
    let v = super::FramePlane::new(
        vec![9u8, 10].into_boxed_slice(),
        NonZeroUsize::new(1).unwrap(),
        NonZeroUsize::new(1).unwrap(),
        NonZeroUsize::new(2).unwrap(),
    )
    .unwrap();
    let frame = Frame::new([Some(y), Some(u), Some(v)]);

    let view = frame.as_view().unwrap();

    assert_eq!(view.plane_count(), 3);
    assert_eq!(view.pitch_for_plane(0).unwrap().get(), 3);
    assert_eq!(view.pitch_for_plane(1).unwrap().get(), 2);
    assert_eq!(view.pitch_for_plane(2).unwrap().get(), 2);
}

#[test]
fn frame_view_reports_missing_chroma_pitch() {
    let y = super::FramePlane::new(
        vec![1u8, 2, 3, 4].into_boxed_slice(),
        NonZeroUsize::new(2).unwrap(),
        NonZeroUsize::new(2).unwrap(),
        NonZeroUsize::new(2).unwrap(),
    )
    .unwrap();
    let frame = Frame::new([Some(y), None, None]);

    let view = frame.as_view().unwrap();
    let err = view.pitch_for_plane(1).unwrap_err();

    assert_eq!(view.plane_count(), 1);
    assert!(
        err.to_string()
            .contains("requested plane 1 is not available")
    );
}

#[test]
#[should_panic(expected = "FrameView planes and pitch must agree for chroma U")]
fn frame_view_new_rejects_misaligned_chroma_u_pitch() {
    let y = [1u8, 2, 3, 4];
    let planes = FramePlanes::new([Some(PlaneRef::new(&y)), None, None]);

    let _ = super::FrameView::new(
        planes,
        (
            NonZeroUsize::new(2).unwrap(),
            Some(NonZeroUsize::new(1).unwrap()),
            None,
        ),
    );
}