Coverage Report

Created: 2026-01-09 07:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/av-scenechange-0.14.1/src/analyze/fast.rs
Line
Count
Source
1
use std::{cmp, sync::Arc};
2
3
use log::debug;
4
use v_frame::{frame::Frame, pixel::Pixel, plane::Plane};
5
6
use super::{fast_idiv, ScaleFunction, SceneChangeDetector, ScenecutResult};
7
use crate::{data::sad::sad_plane, SceneDetectionSpeed};
8
9
/// Experiments have determined this to be an optimal threshold
10
pub(super) const FAST_THRESHOLD: f64 = 18.0;
11
12
impl<T: Pixel> SceneChangeDetector<T> {
13
    /// The fast algorithm detects fast cuts using a raw difference
14
    /// in pixel values between the scaled frames.
15
0
    pub(super) fn fast_scenecut(
16
0
        &mut self,
17
0
        frame1: Arc<Frame<T>>,
18
0
        frame2: Arc<Frame<T>>,
19
0
    ) -> ScenecutResult {
20
0
        if let Some(scale_func) = &self.scale_func {
21
            // downscale both frames for faster comparison
22
0
            if let Some(frame_buffer) = &mut self.downscaled_frame_buffer {
23
0
                frame_buffer.swap(0, 1);
24
0
                (scale_func.downscale_in_place)(&frame2.planes[0], &mut frame_buffer[1]);
25
0
            } else {
26
0
                self.downscaled_frame_buffer = Some([
27
0
                    (scale_func.downscale)(&frame1.planes[0]),
28
0
                    (scale_func.downscale)(&frame2.planes[0]),
29
0
                ]);
30
0
            }
31
32
0
            if let Some(frame_buffer) = &self.downscaled_frame_buffer {
33
0
                let &[first, second] = &frame_buffer;
34
0
                let delta = self.delta_in_planes(first, second);
35
36
0
                ScenecutResult {
37
0
                    threshold: self.threshold,
38
0
                    inter_cost: delta,
39
0
                    imp_block_cost: delta,
40
0
                    forward_adjusted_cost: delta,
41
0
                    backward_adjusted_cost: delta,
42
0
                }
43
            } else {
44
0
                unreachable!()
45
            }
46
        } else {
47
0
            let delta = self.delta_in_planes(&frame1.planes[0], &frame2.planes[0]);
48
49
0
            ScenecutResult {
50
0
                threshold: self.threshold,
51
0
                inter_cost: delta,
52
0
                imp_block_cost: delta,
53
0
                backward_adjusted_cost: delta,
54
0
                forward_adjusted_cost: delta,
55
0
            }
56
        }
57
0
    }
Unexecuted instantiation: <av_scenechange::analyze::SceneChangeDetector<u16>>::fast_scenecut
Unexecuted instantiation: <av_scenechange::analyze::SceneChangeDetector<u8>>::fast_scenecut
Unexecuted instantiation: <av_scenechange::analyze::SceneChangeDetector<_>>::fast_scenecut
58
59
    /// Calculates the average sum of absolute difference (SAD) per pixel
60
    /// between 2 planes
61
0
    fn delta_in_planes(&self, plane1: &Plane<T>, plane2: &Plane<T>) -> f64 {
62
0
        let delta = sad_plane(plane1, plane2, self.cpu_feature_level);
63
64
0
        delta as f64 / self.scaled_pixels as f64
65
0
    }
Unexecuted instantiation: <av_scenechange::analyze::SceneChangeDetector<u16>>::delta_in_planes
Unexecuted instantiation: <av_scenechange::analyze::SceneChangeDetector<u8>>::delta_in_planes
Unexecuted instantiation: <av_scenechange::analyze::SceneChangeDetector<_>>::delta_in_planes
66
}
67
68
/// Scaling factor for frame in scene detection
69
0
pub(super) fn detect_scale_factor<T: Pixel>(
70
0
    resolution: (usize, usize),
71
0
    speed_mode: SceneDetectionSpeed,
72
0
) -> Option<ScaleFunction<T>> {
73
0
    let small_edge = cmp::min(resolution.0, resolution.1);
74
0
    let scale_func = if speed_mode == SceneDetectionSpeed::Fast {
75
0
        match small_edge {
76
0
            0..=240 => None,
77
0
            241..=480 => Some(ScaleFunction::from_scale::<2>()),
78
0
            481..=720 => Some(ScaleFunction::from_scale::<4>()),
79
0
            721..=1080 => Some(ScaleFunction::from_scale::<8>()),
80
0
            1081..=1600 => Some(ScaleFunction::from_scale::<16>()),
81
0
            1601..=usize::MAX => Some(ScaleFunction::from_scale::<32>()),
82
0
            _ => None,
83
        }
84
    } else {
85
0
        None
86
    };
87
88
0
    if let Some(scale_factor) = scale_func.as_ref().map(|x| x.factor) {
89
0
        debug!(
90
0
            "Scene detection scale factor {}, [{},{}] -> [{},{}]",
91
            scale_factor,
92
            resolution.0,
93
            resolution.1,
94
0
            fast_idiv(resolution.0, scale_factor),
95
0
            fast_idiv(resolution.1, scale_factor)
96
        );
97
0
    }
98
99
0
    scale_func
100
0
}
Unexecuted instantiation: av_scenechange::analyze::fast::detect_scale_factor::<u8>
Unexecuted instantiation: av_scenechange::analyze::fast::detect_scale_factor::<u16>
Unexecuted instantiation: av_scenechange::analyze::fast::detect_scale_factor::<_>