Coverage Report

Created: 2025-12-05 07:37

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/data/frame.rs
Line
Count
Source
1
use std::sync::Arc;
2
3
use v_frame::{frame::Frame, math::Fixed, pixel::Pixel, plane::Plane};
4
5
use crate::data::motion::{RefMEStats, ReferenceFramesSet};
6
7
pub const MAX_PLANES: usize = 3;
8
9
pub const ALLOWED_REF_FRAMES: &[RefType] = &[RefType::LAST_FRAME];
10
pub const INTER_REFS_PER_FRAME: usize = 7;
11
12
#[derive(Debug, Clone)]
13
pub struct FrameState<T: Pixel> {
14
    pub input: Arc<Frame<T>>,
15
    pub input_hres: Arc<Plane<T>>, // half-resolution version of input luma
16
    pub input_qres: Arc<Plane<T>>, // quarter-resolution version of input luma
17
    pub frame_me_stats: RefMEStats,
18
}
19
20
impl<T: Pixel> FrameState<T> {
21
    /// Similar to [`FrameState::new_with_frame`], but takes an `me_stats`
22
    /// and `rec` to enable reusing the same underlying allocations to create
23
    /// a `FrameState`
24
    ///
25
    /// This function primarily exists for [`estimate_inter_costs`], and so
26
    /// it does not create hres or qres versions of `frame` as downscaling is
27
    /// somewhat expensive and are not needed for [`estimate_inter_costs`].
28
0
    pub fn new_with_frame_and_me_stats_and_rec(frame: Arc<Frame<T>>, me_stats: RefMEStats) -> Self {
29
0
        let hres = Plane::new(0, 0, 0, 0, 0, 0);
30
0
        let qres = Plane::new(0, 0, 0, 0, 0, 0);
31
32
0
        Self {
33
0
            input: frame,
34
0
            input_hres: Arc::new(hres),
35
0
            input_qres: Arc::new(qres),
36
0
            frame_me_stats: me_stats,
37
0
            // enc_stats: Default::default(),
38
0
        }
39
0
    }
Unexecuted instantiation: <av_scenechange::data::frame::FrameState<u16>>::new_with_frame_and_me_stats_and_rec
Unexecuted instantiation: <av_scenechange::data::frame::FrameState<u8>>::new_with_frame_and_me_stats_and_rec
Unexecuted instantiation: <av_scenechange::data::frame::FrameState<_>>::new_with_frame_and_me_stats_and_rec
40
}
41
42
// LAST_FRAME through ALTREF_FRAME correspond to slots 0-6.
43
#[allow(non_camel_case_types)]
44
#[allow(dead_code)]
45
#[derive(PartialEq, Eq, PartialOrd, Copy, Clone, Debug)]
46
pub enum RefType {
47
    INTRA_FRAME = 0,
48
    LAST_FRAME = 1,
49
    LAST2_FRAME = 2,
50
    LAST3_FRAME = 3,
51
    GOLDEN_FRAME = 4,
52
    BWDREF_FRAME = 5,
53
    ALTREF2_FRAME = 6,
54
    ALTREF_FRAME = 7,
55
    NONE_FRAME = 8,
56
}
57
58
impl RefType {
59
    /// convert to a ref list index, 0-6 (`INTER_REFS_PER_FRAME`)
60
    ///
61
    /// # Panics
62
    ///
63
    /// - If the ref type is a None or Intra frame
64
0
    pub fn to_index(self) -> usize {
65
        use self::RefType::*;
66
67
0
        match self {
68
            NONE_FRAME => {
69
0
                panic!("Tried to get slot of NONE_FRAME");
70
            }
71
            INTRA_FRAME => {
72
0
                panic!("Tried to get slot of INTRA_FRAME");
73
            }
74
0
            _ => (self as usize) - 1,
75
        }
76
0
    }
77
}
78
79
// Frame Invariants are invariant inside a frame
80
#[allow(dead_code)]
81
#[derive(Debug, Clone)]
82
pub struct FrameInvariants<T: Pixel> {
83
    pub w_in_b: usize,
84
    pub h_in_b: usize,
85
    pub ref_frames: [u8; INTER_REFS_PER_FRAME],
86
    pub rec_buffer: ReferenceFramesSet<T>,
87
}
88
89
impl<T: Pixel> FrameInvariants<T> {
90
0
    pub fn new(width: usize, height: usize) -> Self {
91
0
        let w_in_b = 2 * width.align_power_of_two_and_shift(3); // MiCols, ((width+7)/8)<<3 >> MI_SIZE_LOG2
92
0
        let h_in_b = 2 * height.align_power_of_two_and_shift(3); // MiRows, ((height+7)/8)<<3 >> MI_SIZE_LOG2
93
94
0
        Self {
95
0
            w_in_b,
96
0
            h_in_b,
97
0
            ref_frames: [0; INTER_REFS_PER_FRAME],
98
0
            rec_buffer: ReferenceFramesSet::new(),
99
0
        }
100
0
    }
Unexecuted instantiation: <av_scenechange::data::frame::FrameInvariants<u16>>::new
Unexecuted instantiation: <av_scenechange::data::frame::FrameInvariants<u8>>::new
Unexecuted instantiation: <av_scenechange::data::frame::FrameInvariants<_>>::new
101
102
0
    pub fn new_key_frame(width: usize, height: usize) -> Self {
103
0
        Self::new(width, height)
104
0
    }
Unexecuted instantiation: <av_scenechange::data::frame::FrameInvariants<u16>>::new_key_frame
Unexecuted instantiation: <av_scenechange::data::frame::FrameInvariants<u8>>::new_key_frame
Unexecuted instantiation: <av_scenechange::data::frame::FrameInvariants<_>>::new_key_frame
105
106
    /// Returns the created `FrameInvariants`, or `None` if this should be
107
    /// a placeholder frame.
108
0
    pub(crate) fn new_inter_frame(
109
0
        previous_coded_fi: &Self,
110
0
        output_frameno_in_gop: u64,
111
0
    ) -> Option<Self> {
112
0
        let mut fi = previous_coded_fi.clone();
113
0
        let idx_in_group_output = get_idx_in_group_output(output_frameno_in_gop);
114
0
        let order_hint = get_order_hint(output_frameno_in_gop, idx_in_group_output);
115
116
        // this is the slot that the current frame is going to be saved into
117
0
        let slot_idx = get_slot_idx(0, order_hint);
118
119
        // level 0 has no forward references
120
        // default to last P frame
121
        //
122
        // calculations done relative to the slot_idx for this frame.
123
        // the last four frames can be found by subtracting from the current
124
        //
125
        // add 4 to prevent underflow
126
        // TODO: maybe use order_hint here like in get_slot_idx?
127
        // this is the previous P frame
128
0
        fi.ref_frames = [(slot_idx + 4 - 1) as u8 % 4; INTER_REFS_PER_FRAME];
129
130
0
        Some(fi)
131
0
    }
Unexecuted instantiation: <av_scenechange::data::frame::FrameInvariants<u16>>::new_inter_frame
Unexecuted instantiation: <av_scenechange::data::frame::FrameInvariants<u8>>::new_inter_frame
Unexecuted instantiation: <av_scenechange::data::frame::FrameInvariants<_>>::new_inter_frame
132
}
133
134
// All the stuff below is ripped from InterCfg but assumes
135
// reordering and multiref are off, so pyramid depth is always 0
136
0
const fn get_slot_idx(level: u64, order_hint: u32) -> u32 {
137
    // Frames with level == 0 are stored in slots 0..4, and frames with higher
138
    //  values of level in slots 4..8
139
0
    if level == 0 {
140
0
        order_hint & 3
141
    } else {
142
        // This only works with pyramid_depth <= 4.
143
0
        3 + level as u32
144
    }
145
0
}
146
147
/// Get the index of an output frame in its re-ordering group given the output
148
///  frame number of the frame in the current keyframe gop.
149
/// When re-ordering is disabled, this always returns 0.
150
0
fn get_idx_in_group_output(output_frameno_in_gop: u64) -> u64 {
151
    // The first frame in the GOP should be a keyframe and is not re-ordered,
152
    // so we should not be calling this function on it.
153
0
    debug_assert!(output_frameno_in_gop > 0);
154
155
0
    output_frameno_in_gop - 1
156
0
}
157
158
/// Get the order-hint of an output frame given the output frame number of the
159
///  frame in the current keyframe gop and the index of that output frame
160
///  in its re-ordering gorup.
161
0
fn get_order_hint(output_frameno_in_gop: u64, idx_in_group_output: u64) -> u32 {
162
    // The first frame in the GOP should be a keyframe, but currently this
163
    //  function only handles inter frames.
164
    // We could return 0 for keyframes if keyframe support is needed.
165
0
    debug_assert!(output_frameno_in_gop > 0);
166
167
    // Which P-frame group in the current gop is this output frame in?
168
    // Subtract 1 because the first frame in the gop is always a keyframe.
169
0
    let group_idx = output_frameno_in_gop - 1;
170
    // Get the offset to the corresponding input frame.
171
0
    let offset = idx_in_group_output + 1;
172
    // Construct the final order hint relative to the start of the group.
173
0
    (group_idx + offset) as u32
174
0
}