#![allow(clippy::unwrap_used, reason = "allow in test files")]
use std::num::{NonZeroU8, NonZeroUsize};
use crate::{
filters::analyse::{Analyse, AnalyseOptions, SuperClipInfo},
frame::{Frame, FramePlane},
params::{DctMode, DivideMode, MVPlaneSet, MotionFlags, PenaltyScaling, SearchType, Subpel},
video::{ColorFamily, Resolution, SampleType, VideoFormat, VideoInfo},
};
fn yuv420p8_super_info() -> (VideoInfo, SuperClipInfo) {
let 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: 1,
sub_sampling_h: 1,
};
let info = VideoInfo {
format,
resolution: Resolution {
width: 672,
height: 2750,
},
num_frames: 10,
};
let super_info = SuperClipInfo {
height: NonZeroUsize::new(480).unwrap(),
hpad: 16,
vpad: 16,
pel: Subpel::Half,
mode_yuv: MVPlaneSet::YUVPLANES,
levels: 8,
};
(info, super_info)
}
#[test]
fn analyse_new_defaults_match_vapoursynth_filter_defaults() {
let (info, super_info) = yuv420p8_super_info();
let analyse = Analyse::new(info, super_info, AnalyseOptions::default()).unwrap();
assert_eq!(analyse.search_type(), SearchType::Hex2);
assert_eq!(analyse.search_type_coarse(), SearchType::Exhaustive);
assert_eq!(analyse.search_param(), 2);
assert_eq!(analyse.pel_search(), 2);
assert_eq!(analyse.penalty_level(), PenaltyScaling::Linear);
assert!(analyse.global());
assert_eq!(analyse.penalty_new(), 50);
assert_eq!(analyse.penalty_zero(), 50);
assert_eq!(analyse.penalty_global(), 0);
assert_eq!(analyse.dct_mode(), DctMode::Spatial);
assert_eq!(analyse.divide_extra(), DivideMode::None);
assert_eq!(analyse.bad_range(), 24);
assert!(analyse.meander());
assert!(!analyse.try_many());
assert!(!analyse.fields());
assert_eq!(analyse.tff(), None);
assert_eq!(analyse.lambda(), 1000);
assert_eq!(analyse.lambda_sad(), 1200);
assert_eq!(analyse.bad_sad(), 10_000);
let data = analyse.analysis_data();
assert_eq!(data.blk_size_x.get(), 8);
assert_eq!(data.blk_size_y.get(), 8);
assert_eq!(data.pel, Subpel::Half);
assert_eq!(data.delta_frame, 1);
assert!(!data.is_backward);
assert_eq!(data.motion_flags, MotionFlags::USE_CHROMA_MOTION);
assert_eq!(data.width.get(), 640);
assert_eq!(data.height.get(), 480);
assert_eq!(data.h_padding, 16);
assert_eq!(data.v_padding, 16);
assert!(analyse.analysis_data_divided().is_none());
}
#[test]
fn analyse_new_rejects_invalid_block_size() {
let (info, super_info) = yuv420p8_super_info();
let options = AnalyseOptions {
blk_size_x: Some(3),
blk_size_y: Some(3),
..AnalyseOptions::default()
};
let err = Analyse::new(info, super_info, options).unwrap_err();
assert!(err.to_string().contains("block size must be"));
}
#[test]
fn analyse_new_divide_builds_divided_analysis_data() {
let (info, super_info) = yuv420p8_super_info();
let options = AnalyseOptions {
divide_extra: Some(DivideMode::Original),
..AnalyseOptions::default()
};
let analyse = Analyse::new(info, super_info, options).unwrap();
let divided = analyse.analysis_data_divided().unwrap();
assert_eq!(divided.blk_size_x.get(), 4);
assert_eq!(divided.blk_size_y.get(), 4);
assert_eq!(divided.blk_x.get(), analyse.analysis_data().blk_x.get() * 2);
assert_eq!(divided.blk_y.get(), analyse.analysis_data().blk_y.get() * 2);
assert_eq!(divided.level_count, analyse.analysis_data().level_count + 1);
}
fn tiny_super_frame() -> Frame<u8> {
let y = FramePlane::new(
vec![0u8; 672 * 2750].into_boxed_slice(),
NonZeroUsize::new(672).unwrap(),
NonZeroUsize::new(2750).unwrap(),
NonZeroUsize::new(672).unwrap(),
)
.unwrap();
let u = FramePlane::new(
vec![0u8; 336 * 1375].into_boxed_slice(),
NonZeroUsize::new(336).unwrap(),
NonZeroUsize::new(1375).unwrap(),
NonZeroUsize::new(336).unwrap(),
)
.unwrap();
let v = FramePlane::new(
vec![0u8; 336 * 1375].into_boxed_slice(),
NonZeroUsize::new(336).unwrap(),
NonZeroUsize::new(1375).unwrap(),
NonZeroUsize::new(336).unwrap(),
)
.unwrap();
Frame::new([Some(y), Some(u), Some(v)])
}
#[test]
fn reference_frame_number_matches_forward_and_backward_modes() {
let (info, super_info) = yuv420p8_super_info();
let forward = Analyse::new(info, super_info, AnalyseOptions::default()).unwrap();
let backward = Analyse::new(
info,
super_info,
AnalyseOptions {
is_backward: true,
..AnalyseOptions::default()
},
)
.unwrap();
assert_eq!(forward.reference_frame_number(0), None);
assert_eq!(forward.reference_frame_number(1), Some(0));
assert_eq!(backward.reference_frame_number(8), Some(9));
assert_eq!(backward.reference_frame_number(9), None);
}
#[test]
fn analyse_frame_without_reference_returns_default_vectors_and_analysis_data() {
let (info, super_info) = yuv420p8_super_info();
let analyse = Analyse::new(info, super_info, AnalyseOptions::default()).unwrap();
let frame = tiny_super_frame();
let view = frame.as_view().unwrap();
let output = analyse.analyse_frame(0, &view, None, None, None).unwrap();
assert_eq!(output.analysis_data, analyse.analysis_data());
assert!(!output.vectors.validity);
}
#[test]
fn analyse_frame_with_reference_returns_valid_vectors() {
let (info, super_info) = yuv420p8_super_info();
let analyse = Analyse::new(info, super_info, AnalyseOptions::default()).unwrap();
let src = tiny_super_frame();
let reference = tiny_super_frame();
let src_view = src.as_view().unwrap();
let reference_view = reference.as_view().unwrap();
let output = analyse
.analyse_frame(
1,
&src_view,
Some(&reference_view),
Some(false),
Some(false),
)
.unwrap();
assert_eq!(output.analysis_data, analyse.analysis_data());
assert!(output.vectors.validity);
}