#![allow(clippy::indexing_slicing, reason = "allow in test files")]
#![allow(clippy::unwrap_used, reason = "allow in test files")]
use std::num::{NonZeroU8, NonZeroUsize};
use crate::{
analysis::MVAnalysisData,
fake::group_of_planes::FakeGroupOfPlanes,
frame::{FramePlanes, FramePlanesMut, FrameView, PlaneRef, PlaneSizeTuple},
mv::MotionVector,
params::{MotionFlags, Subpel},
video::{ColorFamily, Resolution, SampleType, VideoFormat, VideoInfo},
};
use super::{Flow, FlowMode, FlowOptions};
static Y_REFERENCE: [u8; 4] = [10, 20, 40, 80];
static U_REFERENCE: [u8; 4] = [1, 5, 13, 29];
static V_REFERENCE: [u8; 4] = [4, 8, 20, 32];
fn yuv444_info() -> VideoInfo {
VideoInfo {
format: VideoFormat {
color_family: ColorFamily::Yuv,
sample_type: SampleType::Integer,
bits_per_sample: NonZeroU8::new(8).unwrap(),
bytes_per_sample: NonZeroU8::new(1).unwrap(),
sub_sampling_w: 0,
sub_sampling_h: 0,
},
resolution: Resolution {
width: 2,
height: 1,
},
num_frames: 10,
}
}
fn analysis_data() -> MVAnalysisData {
MVAnalysisData {
blk_size_x: NonZeroUsize::new(1).unwrap(),
blk_size_y: NonZeroUsize::new(1).unwrap(),
pel: Subpel::Full,
level_count: 1,
delta_frame: 1,
is_backward: false,
motion_flags: MotionFlags::empty(),
width: NonZeroUsize::new(2).unwrap(),
height: NonZeroUsize::new(1).unwrap(),
overlap_x: 0,
overlap_y: 0,
blk_x: NonZeroUsize::new(2).unwrap(),
blk_y: NonZeroUsize::new(1).unwrap(),
bits_per_sample: NonZeroU8::new(8).unwrap(),
y_ratio_uv: NonZeroU8::new(1).unwrap(),
x_ratio_uv: NonZeroU8::new(1).unwrap(),
h_padding: 1,
v_padding: 0,
}
}
fn fake_vectors(vector: MotionVector, validity: bool) -> FakeGroupOfPlanes {
let mut fake_gop = FakeGroupOfPlanes::new(&analysis_data());
for block in &mut fake_gop.plane_mut(0).blocks {
block.vector = vector;
}
fake_gop.set_validity(validity);
fake_gop
}
fn padded_reference_view() -> FrameView<'static, u8> {
FrameView::new(
FramePlanes::new([
Some(PlaneRef::new(&Y_REFERENCE)),
Some(PlaneRef::new(&U_REFERENCE)),
Some(PlaneRef::new(&V_REFERENCE)),
]),
plane_sizes(3),
)
}
fn plane_sizes(stride: usize) -> PlaneSizeTuple {
let stride = NonZeroUsize::new(stride).unwrap();
(stride, Some(stride), Some(stride))
}
#[test]
fn flow_render_frame_fetch_uses_motion_vectors_on_all_planes() {
let flow = Flow::new(
yuv444_info(),
analysis_data(),
FlowOptions {
time: 100.0,
mode: FlowMode::Fetch,
},
)
.unwrap();
let reference = padded_reference_view();
let vectors = fake_vectors(MotionVector { x: 1, y: 0, sad: 0 }, true);
let mut y = [0u8; 2];
let mut u = [0u8; 2];
let mut v = [0u8; 2];
let mut output = FramePlanesMut::new([Some(&mut y), Some(&mut u), Some(&mut v)]);
flow.render_frame(&reference, &mut output, plane_sizes(2), &vectors, 0)
.unwrap();
assert_eq!(y, [40, 40]);
assert_eq!(u, [13, 13]);
assert_eq!(v, [20, 20]);
}
#[test]
fn flow_render_frame_shift_moves_pixels_and_fills_holes() {
let flow = Flow::new(
yuv444_info(),
analysis_data(),
FlowOptions {
time: 100.0,
mode: FlowMode::Shift,
},
)
.unwrap();
let reference = padded_reference_view();
let vectors = fake_vectors(MotionVector { x: 1, y: 0, sad: 0 }, true);
let mut y = [0u8; 2];
let mut u = [0u8; 2];
let mut v = [0u8; 2];
let mut output = FramePlanesMut::new([Some(&mut y), Some(&mut u), Some(&mut v)]);
flow.render_frame(&reference, &mut output, plane_sizes(2), &vectors, 0)
.unwrap();
assert_eq!(y, [255, 40]);
assert_eq!(u, [255, 13]);
assert_eq!(v, [255, 20]);
}
#[test]
fn flow_vectors_are_not_usable_when_scene_change_marks_vectors_invalid() {
let flow = Flow::new(
yuv444_info(),
analysis_data(),
FlowOptions {
time: 100.0,
mode: FlowMode::Fetch,
},
)
.unwrap();
let vectors = fake_vectors(MotionVector { x: 1, y: 0, sad: 0 }, false);
assert!(!flow.vectors_are_usable(&vectors, 400, 130));
}