/rust/registry/src/index.crates.io-1949cf8c6b5b557f/av-scenechange-0.14.1/src/analyze/standard.rs
Line | Count | Source |
1 | | use std::sync::Arc; |
2 | | |
3 | | use v_frame::{frame::Frame, math::Fixed, pixel::Pixel}; |
4 | | |
5 | | use super::{SceneChangeDetector, ScenecutResult}; |
6 | | use crate::{ |
7 | | analyze::{ |
8 | | importance::estimate_importance_block_difference, |
9 | | inter::estimate_inter_costs, |
10 | | intra::estimate_intra_costs, |
11 | | }, |
12 | | data::motion::FrameMEStats, |
13 | | }; |
14 | | |
15 | | impl<T: Pixel> SceneChangeDetector<T> { |
16 | | /// Run a comparison between two frames to determine if they qualify for a |
17 | | /// scenecut. |
18 | | /// |
19 | | /// We gather both intra and inter costs for the frames, |
20 | | /// as well as an importance-block-based difference, |
21 | | /// and use all three metrics. |
22 | 0 | pub(super) fn cost_scenecut( |
23 | 0 | &mut self, |
24 | 0 | frame1: Arc<Frame<T>>, |
25 | 0 | frame2: Arc<Frame<T>>, |
26 | 0 | input_frameno: usize, |
27 | 0 | ) -> ScenecutResult { |
28 | 0 | let frame2_inter_ref = Arc::clone(&frame2); |
29 | 0 | let frame1_imp_ref = Arc::clone(&frame1); |
30 | 0 | let frame2_imp_ref = Arc::clone(&frame2); |
31 | | |
32 | 0 | let mut intra_cost = 0.0; |
33 | 0 | let mut mv_inter_cost = 0.0; |
34 | 0 | let mut imp_block_cost = 0.0; |
35 | | |
36 | 0 | let cols = 2 * self.resolution.0.align_power_of_two_and_shift(3); |
37 | 0 | let rows = 2 * self.resolution.1.align_power_of_two_and_shift(3); |
38 | | |
39 | 0 | let buffer = if let Some(buffer) = &self.frame_me_stats_buffer { |
40 | 0 | Arc::clone(buffer) |
41 | | } else { |
42 | 0 | let frame_me_stats = FrameMEStats::new_arc_array(cols, rows); |
43 | 0 | let clone = Arc::clone(&frame_me_stats); |
44 | 0 | self.frame_me_stats_buffer = Some(frame_me_stats); |
45 | 0 | clone |
46 | | }; |
47 | | |
48 | 0 | rayon::scope(|s| { |
49 | 0 | s.spawn(|_| { |
50 | 0 | let temp_plane = self |
51 | 0 | .temp_plane |
52 | 0 | .get_or_insert_with(|| frame2.planes[0].clone()); Unexecuted instantiation: <av_scenechange::analyze::SceneChangeDetector<u16>>::cost_scenecut::{closure#0}::{closure#0}::{closure#0}Unexecuted instantiation: <av_scenechange::analyze::SceneChangeDetector<u8>>::cost_scenecut::{closure#0}::{closure#0}::{closure#0}Unexecuted instantiation: <av_scenechange::analyze::SceneChangeDetector<_>>::cost_scenecut::{closure#0}::{closure#0}::{closure#0} |
53 | | |
54 | 0 | let intra_costs = estimate_intra_costs( |
55 | 0 | temp_plane, |
56 | 0 | &*frame2, |
57 | 0 | self.bit_depth, |
58 | 0 | self.cpu_feature_level, |
59 | | ); |
60 | 0 | if let Some(ref mut intra_cache) = self.intra_costs { |
61 | 0 | intra_cache.insert(input_frameno, intra_costs.clone()); |
62 | 0 | } |
63 | | |
64 | 0 | intra_cost = intra_costs.iter().map(|&cost| cost as u64).sum::<u64>() as f64 Unexecuted instantiation: <av_scenechange::analyze::SceneChangeDetector<u16>>::cost_scenecut::{closure#0}::{closure#0}::{closure#1}Unexecuted instantiation: <av_scenechange::analyze::SceneChangeDetector<u8>>::cost_scenecut::{closure#0}::{closure#0}::{closure#1}Unexecuted instantiation: <av_scenechange::analyze::SceneChangeDetector<_>>::cost_scenecut::{closure#0}::{closure#0}::{closure#1} |
65 | 0 | / intra_costs.len() as f64; |
66 | 0 | }); Unexecuted instantiation: <av_scenechange::analyze::SceneChangeDetector<u16>>::cost_scenecut::{closure#0}::{closure#0}Unexecuted instantiation: <av_scenechange::analyze::SceneChangeDetector<u8>>::cost_scenecut::{closure#0}::{closure#0}Unexecuted instantiation: <av_scenechange::analyze::SceneChangeDetector<_>>::cost_scenecut::{closure#0}::{closure#0} |
67 | 0 | s.spawn(|_| { |
68 | 0 | mv_inter_cost = estimate_inter_costs( |
69 | 0 | frame2_inter_ref, |
70 | 0 | frame1, |
71 | 0 | self.bit_depth, |
72 | 0 | self.frame_rate, |
73 | 0 | self.chroma_sampling, |
74 | 0 | buffer, |
75 | 0 | self.cpu_feature_level, |
76 | 0 | ); |
77 | 0 | }); Unexecuted instantiation: <av_scenechange::analyze::SceneChangeDetector<u16>>::cost_scenecut::{closure#0}::{closure#1}Unexecuted instantiation: <av_scenechange::analyze::SceneChangeDetector<u8>>::cost_scenecut::{closure#0}::{closure#1}Unexecuted instantiation: <av_scenechange::analyze::SceneChangeDetector<_>>::cost_scenecut::{closure#0}::{closure#1} |
78 | 0 | s.spawn(|_| { |
79 | 0 | imp_block_cost = |
80 | 0 | estimate_importance_block_difference(frame2_imp_ref, frame1_imp_ref); |
81 | 0 | }); Unexecuted instantiation: <av_scenechange::analyze::SceneChangeDetector<u16>>::cost_scenecut::{closure#0}::{closure#2}Unexecuted instantiation: <av_scenechange::analyze::SceneChangeDetector<u8>>::cost_scenecut::{closure#0}::{closure#2}Unexecuted instantiation: <av_scenechange::analyze::SceneChangeDetector<_>>::cost_scenecut::{closure#0}::{closure#2} |
82 | 0 | }); Unexecuted instantiation: <av_scenechange::analyze::SceneChangeDetector<u16>>::cost_scenecut::{closure#0}Unexecuted instantiation: <av_scenechange::analyze::SceneChangeDetector<u8>>::cost_scenecut::{closure#0}Unexecuted instantiation: <av_scenechange::analyze::SceneChangeDetector<_>>::cost_scenecut::{closure#0} |
83 | | |
84 | | // `BIAS` determines how likely we are |
85 | | // to choose a keyframe, between 0.0-1.0. |
86 | | // Higher values mean we are more likely to choose a keyframe. |
87 | | // This value was chosen based on trials using the new |
88 | | // adaptive scenecut code. |
89 | | const BIAS: f64 = 0.7; |
90 | 0 | let threshold = intra_cost * (1.0 - BIAS); |
91 | | |
92 | 0 | ScenecutResult { |
93 | 0 | inter_cost: mv_inter_cost, |
94 | 0 | imp_block_cost, |
95 | 0 | threshold, |
96 | 0 | backward_adjusted_cost: 0.0, |
97 | 0 | forward_adjusted_cost: 0.0, |
98 | 0 | } |
99 | 0 | } Unexecuted instantiation: <av_scenechange::analyze::SceneChangeDetector<u16>>::cost_scenecut Unexecuted instantiation: <av_scenechange::analyze::SceneChangeDetector<u8>>::cost_scenecut Unexecuted instantiation: <av_scenechange::analyze::SceneChangeDetector<_>>::cost_scenecut |
100 | | } |