Coverage Report

Created: 2025-10-10 07:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/rav1e-0.7.1/src/api/lookahead.rs
Line
Count
Source
1
use crate::api::internal::InterConfig;
2
use crate::config::EncoderConfig;
3
use crate::context::{BlockOffset, FrameBlocks, TileBlockOffset};
4
use crate::cpu_features::CpuFeatureLevel;
5
use crate::dist::get_satd;
6
use crate::encoder::{
7
  FrameInvariants, FrameState, Sequence, IMPORTANCE_BLOCK_SIZE,
8
};
9
use crate::frame::{AsRegion, PlaneOffset};
10
use crate::me::{estimate_tile_motion, RefMEStats};
11
use crate::partition::{get_intra_edges, BlockSize};
12
use crate::predict::{IntraParam, PredictionMode};
13
use crate::tiling::{Area, PlaneRegion, TileRect};
14
use crate::transform::TxSize;
15
use crate::util::Aligned;
16
use crate::Pixel;
17
use rayon::iter::*;
18
use std::sync::Arc;
19
use v_frame::frame::Frame;
20
use v_frame::pixel::CastFromPrimitive;
21
use v_frame::plane::Plane;
22
23
pub(crate) const IMP_BLOCK_MV_UNITS_PER_PIXEL: i64 = 8;
24
pub(crate) const IMP_BLOCK_SIZE_IN_MV_UNITS: i64 =
25
  IMPORTANCE_BLOCK_SIZE as i64 * IMP_BLOCK_MV_UNITS_PER_PIXEL;
26
pub(crate) const IMP_BLOCK_AREA_IN_MV_UNITS: i64 =
27
  IMP_BLOCK_SIZE_IN_MV_UNITS * IMP_BLOCK_SIZE_IN_MV_UNITS;
28
29
#[profiling::function]
30
pub(crate) fn estimate_intra_costs<T: Pixel>(
31
  temp_plane: &mut Plane<T>, frame: &Frame<T>, bit_depth: usize,
32
  cpu_feature_level: CpuFeatureLevel,
33
) -> Box<[u32]> {
34
  let plane = &frame.planes[0];
35
  let plane_after_prediction = temp_plane;
36
37
  let bsize = BlockSize::from_width_and_height(
38
    IMPORTANCE_BLOCK_SIZE,
39
    IMPORTANCE_BLOCK_SIZE,
40
  );
41
  let tx_size = bsize.tx_size();
42
43
  let h_in_imp_b = plane.cfg.height / IMPORTANCE_BLOCK_SIZE;
44
  let w_in_imp_b = plane.cfg.width / IMPORTANCE_BLOCK_SIZE;
45
  let mut intra_costs = Vec::with_capacity(h_in_imp_b * w_in_imp_b);
46
47
  for y in 0..h_in_imp_b {
48
    for x in 0..w_in_imp_b {
49
      let plane_org = plane.region(Area::Rect {
50
        x: (x * IMPORTANCE_BLOCK_SIZE) as isize,
51
        y: (y * IMPORTANCE_BLOCK_SIZE) as isize,
52
        width: IMPORTANCE_BLOCK_SIZE,
53
        height: IMPORTANCE_BLOCK_SIZE,
54
      });
55
56
      // TODO: other intra prediction modes.
57
      let mut edge_buf = Aligned::uninit_array();
58
      let edge_buf = get_intra_edges(
59
        &mut edge_buf,
60
        &plane.as_region(),
61
        TileBlockOffset(BlockOffset { x, y }),
62
        0,
63
        0,
64
        bsize,
65
        PlaneOffset {
66
          x: (x * IMPORTANCE_BLOCK_SIZE) as isize,
67
          y: (y * IMPORTANCE_BLOCK_SIZE) as isize,
68
        },
69
        TxSize::TX_8X8,
70
        bit_depth,
71
        Some(PredictionMode::DC_PRED),
72
        false,
73
        IntraParam::None,
74
      );
75
76
      let mut plane_after_prediction_region = plane_after_prediction
77
        .region_mut(Area::Rect {
78
          x: (x * IMPORTANCE_BLOCK_SIZE) as isize,
79
          y: (y * IMPORTANCE_BLOCK_SIZE) as isize,
80
          width: IMPORTANCE_BLOCK_SIZE,
81
          height: IMPORTANCE_BLOCK_SIZE,
82
        });
83
84
      PredictionMode::DC_PRED.predict_intra(
85
        TileRect {
86
          x: x * IMPORTANCE_BLOCK_SIZE,
87
          y: y * IMPORTANCE_BLOCK_SIZE,
88
          width: IMPORTANCE_BLOCK_SIZE,
89
          height: IMPORTANCE_BLOCK_SIZE,
90
        },
91
        &mut plane_after_prediction_region,
92
        tx_size,
93
        bit_depth,
94
        &[], // Not used by DC_PRED
95
        IntraParam::None,
96
        None, // Not used by DC_PRED
97
        &edge_buf,
98
        cpu_feature_level,
99
      );
100
101
      let plane_after_prediction_region =
102
        plane_after_prediction.region(Area::Rect {
103
          x: (x * IMPORTANCE_BLOCK_SIZE) as isize,
104
          y: (y * IMPORTANCE_BLOCK_SIZE) as isize,
105
          width: IMPORTANCE_BLOCK_SIZE,
106
          height: IMPORTANCE_BLOCK_SIZE,
107
        });
108
109
      let intra_cost = get_satd(
110
        &plane_org,
111
        &plane_after_prediction_region,
112
        bsize.width(),
113
        bsize.height(),
114
        bit_depth,
115
        cpu_feature_level,
116
      );
117
118
      intra_costs.push(intra_cost);
119
    }
120
  }
121
122
  intra_costs.into_boxed_slice()
123
}
124
125
#[profiling::function]
126
pub(crate) fn estimate_importance_block_difference<T: Pixel>(
127
  frame: Arc<Frame<T>>, ref_frame: Arc<Frame<T>>,
128
) -> f64 {
129
  let plane_org = &frame.planes[0];
130
  let plane_ref = &ref_frame.planes[0];
131
  let h_in_imp_b = plane_org.cfg.height / IMPORTANCE_BLOCK_SIZE;
132
  let w_in_imp_b = plane_org.cfg.width / IMPORTANCE_BLOCK_SIZE;
133
134
  let mut imp_block_costs = 0;
135
136
0
  (0..h_in_imp_b).for_each(|y| {
137
0
    (0..w_in_imp_b).for_each(|x| {
138
      // Coordinates of the top-left corner of the reference block, in MV
139
      // units.
140
0
      let region_org = plane_org.region(Area::Rect {
141
0
        x: (x * IMPORTANCE_BLOCK_SIZE) as isize,
142
0
        y: (y * IMPORTANCE_BLOCK_SIZE) as isize,
143
0
        width: IMPORTANCE_BLOCK_SIZE,
144
0
        height: IMPORTANCE_BLOCK_SIZE,
145
0
      });
146
147
0
      let region_ref = plane_ref.region(Area::Rect {
148
0
        x: (x * IMPORTANCE_BLOCK_SIZE) as isize,
149
0
        y: (y * IMPORTANCE_BLOCK_SIZE) as isize,
150
0
        width: IMPORTANCE_BLOCK_SIZE,
151
0
        height: IMPORTANCE_BLOCK_SIZE,
152
0
      });
153
154
0
      let sum_8x8_block = |region: &PlaneRegion<T>| {
155
0
        region
156
0
          .rows_iter()
157
0
          .map(|row| {
158
            // 16-bit precision is sufficient for an 8px row, as IMPORTANCE_BLOCK_SIZE * (2^12 - 1) < 2^16 - 1,
159
            // so overflow is not possible
160
0
            row.iter().map(|pixel| u16::cast_from(*pixel)).sum::<u16>() as i64
Unexecuted instantiation: rav1e::api::lookahead::estimate_importance_block_difference::<u16>::{closure#0}::{closure#0}::{closure#0}::{closure#0}::{closure#0}
Unexecuted instantiation: rav1e::api::lookahead::estimate_importance_block_difference::<u8>::{closure#0}::{closure#0}::{closure#0}::{closure#0}::{closure#0}
161
0
          })
Unexecuted instantiation: rav1e::api::lookahead::estimate_importance_block_difference::<u16>::{closure#0}::{closure#0}::{closure#0}::{closure#0}
Unexecuted instantiation: rav1e::api::lookahead::estimate_importance_block_difference::<u8>::{closure#0}::{closure#0}::{closure#0}::{closure#0}
162
0
          .sum::<i64>()
163
0
      };
Unexecuted instantiation: rav1e::api::lookahead::estimate_importance_block_difference::<u16>::{closure#0}::{closure#0}::{closure#0}
Unexecuted instantiation: rav1e::api::lookahead::estimate_importance_block_difference::<u8>::{closure#0}::{closure#0}::{closure#0}
164
165
0
      let histogram_org_sum = sum_8x8_block(&region_org);
166
0
      let histogram_ref_sum = sum_8x8_block(&region_ref);
167
168
0
      let count = (IMPORTANCE_BLOCK_SIZE * IMPORTANCE_BLOCK_SIZE) as i64;
169
170
0
      let mean = (((histogram_org_sum + count / 2) / count)
171
0
        - ((histogram_ref_sum + count / 2) / count))
172
0
        .abs();
173
174
0
      imp_block_costs += mean as u64;
175
0
    });
Unexecuted instantiation: rav1e::api::lookahead::estimate_importance_block_difference::<u16>::{closure#0}::{closure#0}
Unexecuted instantiation: rav1e::api::lookahead::estimate_importance_block_difference::<u8>::{closure#0}::{closure#0}
176
0
  });
Unexecuted instantiation: rav1e::api::lookahead::estimate_importance_block_difference::<u16>::{closure#0}
Unexecuted instantiation: rav1e::api::lookahead::estimate_importance_block_difference::<u8>::{closure#0}
177
178
  imp_block_costs as f64 / (w_in_imp_b * h_in_imp_b) as f64
179
}
180
181
#[profiling::function]
182
pub(crate) fn estimate_inter_costs<T: Pixel>(
183
  frame: Arc<Frame<T>>, ref_frame: Arc<Frame<T>>, bit_depth: usize,
184
  mut config: EncoderConfig, sequence: Arc<Sequence>, buffer: RefMEStats,
185
) -> f64 {
186
  config.low_latency = true;
187
  config.speed_settings.multiref = false;
188
  let inter_cfg = InterConfig::new(&config);
189
  let last_fi = FrameInvariants::new_key_frame(
190
    Arc::new(config),
191
    sequence,
192
    0,
193
    Box::new([]),
194
  );
195
  let mut fi = FrameInvariants::new_inter_frame(
196
    &last_fi,
197
    &inter_cfg,
198
    0,
199
    1,
200
    2,
201
    false,
202
    Box::new([]),
203
  )
204
  .unwrap();
205
206
  // Compute the motion vectors.
207
  let mut fs = FrameState::new_with_frame_and_me_stats_and_rec(
208
    &fi,
209
    Arc::clone(&frame),
210
    buffer,
211
    // We do not use this field, so we can avoid the expensive allocation
212
    Arc::new(Frame {
213
      planes: [
214
        Plane::new(0, 0, 0, 0, 0, 0),
215
        Plane::new(0, 0, 0, 0, 0, 0),
216
        Plane::new(0, 0, 0, 0, 0, 0),
217
      ],
218
    }),
219
  );
220
  compute_motion_vectors(&mut fi, &mut fs, &inter_cfg);
221
222
  // Estimate inter costs
223
  let plane_org = &frame.planes[0];
224
  let plane_ref = &ref_frame.planes[0];
225
  let h_in_imp_b = plane_org.cfg.height / IMPORTANCE_BLOCK_SIZE;
226
  let w_in_imp_b = plane_org.cfg.width / IMPORTANCE_BLOCK_SIZE;
227
  let stats = &fs.frame_me_stats.read().expect("poisoned lock")[0];
228
  let bsize = BlockSize::from_width_and_height(
229
    IMPORTANCE_BLOCK_SIZE,
230
    IMPORTANCE_BLOCK_SIZE,
231
  );
232
233
  let mut inter_costs = 0;
234
0
  (0..h_in_imp_b).for_each(|y| {
235
0
    (0..w_in_imp_b).for_each(|x| {
236
0
      let mv = stats[y * 2][x * 2].mv;
237
238
      // Coordinates of the top-left corner of the reference block, in MV
239
      // units.
240
0
      let reference_x = x as i64 * IMP_BLOCK_SIZE_IN_MV_UNITS + mv.col as i64;
241
0
      let reference_y = y as i64 * IMP_BLOCK_SIZE_IN_MV_UNITS + mv.row as i64;
242
243
0
      let region_org = plane_org.region(Area::Rect {
244
0
        x: (x * IMPORTANCE_BLOCK_SIZE) as isize,
245
0
        y: (y * IMPORTANCE_BLOCK_SIZE) as isize,
246
0
        width: IMPORTANCE_BLOCK_SIZE,
247
0
        height: IMPORTANCE_BLOCK_SIZE,
248
0
      });
249
250
0
      let region_ref = plane_ref.region(Area::Rect {
251
0
        x: reference_x as isize / IMP_BLOCK_MV_UNITS_PER_PIXEL as isize,
252
0
        y: reference_y as isize / IMP_BLOCK_MV_UNITS_PER_PIXEL as isize,
253
0
        width: IMPORTANCE_BLOCK_SIZE,
254
0
        height: IMPORTANCE_BLOCK_SIZE,
255
0
      });
256
257
0
      inter_costs += get_satd(
258
0
        &region_org,
259
0
        &region_ref,
260
0
        bsize.width(),
261
0
        bsize.height(),
262
0
        bit_depth,
263
0
        fi.cpu_feature_level,
264
0
      ) as u64;
265
0
    });
Unexecuted instantiation: rav1e::api::lookahead::estimate_inter_costs::<u16>::{closure#0}::{closure#0}
Unexecuted instantiation: rav1e::api::lookahead::estimate_inter_costs::<u8>::{closure#0}::{closure#0}
266
0
  });
Unexecuted instantiation: rav1e::api::lookahead::estimate_inter_costs::<u16>::{closure#0}
Unexecuted instantiation: rav1e::api::lookahead::estimate_inter_costs::<u8>::{closure#0}
267
  inter_costs as f64 / (w_in_imp_b * h_in_imp_b) as f64
268
}
269
270
#[profiling::function]
271
pub(crate) fn compute_motion_vectors<T: Pixel>(
272
  fi: &mut FrameInvariants<T>, fs: &mut FrameState<T>, inter_cfg: &InterConfig,
273
) {
274
  let mut blocks = FrameBlocks::new(fi.w_in_b, fi.h_in_b);
275
  fi.sequence
276
    .tiling
277
    .tile_iter_mut(fs, &mut blocks)
278
    .collect::<Vec<_>>()
279
    .into_par_iter()
280
0
    .for_each(|mut ctx| {
281
0
      let ts = &mut ctx.ts;
282
0
      estimate_tile_motion(fi, ts, inter_cfg);
283
0
    });
Unexecuted instantiation: rav1e::api::lookahead::compute_motion_vectors::<u16>::{closure#0}
Unexecuted instantiation: rav1e::api::lookahead::compute_motion_vectors::<u8>::{closure#0}
284
}