mirror of
https://github.com/storytold/effectcraft.git
synced 2026-10-25 10:36:56 -06:00
Media: tests for the averaged MP4 frame rate (#1442)
This commit is contained in:
@@ -306,3 +306,48 @@ fn averaged_rate(timescale: u32, durations: impl Iterator<Item = u32>) -> Option
|
||||
.map(|(r, _)| r)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
/// Durations (in 1/`timescale` s) of `n` frames at `rate` whose times are rounded to the timescale.
|
||||
fn rounded(rate: FrameRate, timescale: i64, n: i64) -> Vec<u32> {
|
||||
let at = |k: i64| (2 * k * timescale * rate.den + rate.num) / (2 * rate.num);
|
||||
(0..n).map(|k| (at(k + 1) - at(k)) as u32).collect()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn millisecond_rounded_frame_times_average_to_their_rate() {
|
||||
assert_eq!(rounded(FrameRate::FPS_30, 1000, 6), [33, 34, 33, 33, 34, 33]);
|
||||
assert_eq!(averaged_rate(1000, rounded(FrameRate::FPS_30, 1000, 120).into_iter()), Some(FrameRate::FPS_30));
|
||||
assert_eq!(averaged_rate(1000, rounded(FrameRate::FPS_60, 1000, 240).into_iter()), Some(FrameRate::FPS_60));
|
||||
// NTSC rates stay NTSC, not the round rate next to them.
|
||||
for r in [FrameRate::FPS_23_976, FrameRate::FPS_29_97, FrameRate::FPS_59_94] {
|
||||
assert_eq!(averaged_rate(1000, rounded(r, 1000, 240).into_iter()), Some(r), "{r:?}");
|
||||
}
|
||||
// A short clip: its few frames average to the rate as well.
|
||||
assert_eq!(averaged_rate(1000, [33, 34, 33].into_iter()), Some(FrameRate::FPS_30));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exact_and_variable_rates_keep_the_readers_estimate() {
|
||||
// A median that is a standard rate already reads right.
|
||||
assert_eq!(averaged_rate(30000, rounded(FrameRate::FPS_29_97, 30000, 240).into_iter()), None);
|
||||
assert_eq!(averaged_rate(90000, [3000; 10].into_iter()), None);
|
||||
assert_eq!(averaged_rate(600, [20, 20, 19, 21, 20].into_iter()), None);
|
||||
// Durations averaging to no standard rate (22.2 fps).
|
||||
assert_eq!(averaged_rate(1000, [40, 45, 50].repeat(20).into_iter()), None);
|
||||
// A truly 30.3 fps clip is not pulled to 30 (1 % off).
|
||||
assert_eq!(averaged_rate(1000, [33; 30].into_iter()), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn degenerate_durations_have_no_rate() {
|
||||
assert_eq!(averaged_rate(1000, std::iter::empty()), None);
|
||||
assert_eq!(averaged_rate(1000, [0, 0, 0].into_iter()), None);
|
||||
assert_eq!(averaged_rate(0, [33, 34, 33].into_iter()), None);
|
||||
assert_eq!(averaged_rate(u32::MAX, [u32::MAX, u32::MAX - 1, 1, 0].into_iter()), None);
|
||||
assert_eq!(averaged_rate(u32::MAX, [u32::MAX; 300].into_iter()), None);
|
||||
assert_eq!(video_rate(b"not a movie"), None);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user