/rust/registry/src/index.crates.io-6f17d22bba15001f/rav1e-0.7.1/src/encoder.rs
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (c) 2018-2023, The rav1e contributors. All rights reserved |
2 | | // |
3 | | // This source code is subject to the terms of the BSD 2 Clause License and |
4 | | // the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License |
5 | | // was not distributed with this source code in the LICENSE file, you can |
6 | | // obtain it at www.aomedia.org/license/software. If the Alliance for Open |
7 | | // Media Patent License 1.0 was not distributed with this source code in the |
8 | | // PATENTS file, you can obtain it at www.aomedia.org/license/patent. |
9 | | |
10 | | use crate::activity::*; |
11 | | use crate::api::config::GrainTableSegment; |
12 | | use crate::api::*; |
13 | | use crate::cdef::*; |
14 | | use crate::context::*; |
15 | | use crate::deblock::*; |
16 | | use crate::ec::*; |
17 | | use crate::frame::*; |
18 | | use crate::header::*; |
19 | | use crate::lrf::*; |
20 | | use crate::mc::{FilterMode, MotionVector}; |
21 | | use crate::me::*; |
22 | | use crate::partition::PartitionType::*; |
23 | | use crate::partition::RefType::*; |
24 | | use crate::partition::*; |
25 | | use crate::predict::{ |
26 | | luma_ac, AngleDelta, IntraEdgeFilterParameters, IntraParam, PredictionMode, |
27 | | }; |
28 | | use crate::quantize::*; |
29 | | use crate::rate::{ |
30 | | QuantizerParameters, FRAME_SUBTYPE_I, FRAME_SUBTYPE_P, QSCALE, |
31 | | }; |
32 | | use crate::rdo::*; |
33 | | use crate::segmentation::*; |
34 | | use crate::serialize::{Deserialize, Serialize}; |
35 | | use crate::stats::EncoderStats; |
36 | | use crate::tiling::*; |
37 | | use crate::transform::*; |
38 | | use crate::util::*; |
39 | | use crate::wasm_bindgen::*; |
40 | | |
41 | | use arg_enum_proc_macro::ArgEnum; |
42 | | use arrayvec::*; |
43 | | use bitstream_io::{BigEndian, BitWrite, BitWriter}; |
44 | | use rayon::iter::*; |
45 | | |
46 | | use std::collections::VecDeque; |
47 | | use std::io::Write; |
48 | | use std::mem::MaybeUninit; |
49 | | use std::sync::Arc; |
50 | | use std::{fmt, io, mem}; |
51 | | |
52 | | #[allow(dead_code)] |
53 | | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
54 | | pub enum CDEFSearchMethod { |
55 | | PickFromQ, |
56 | | FastSearch, |
57 | | FullSearch, |
58 | | } |
59 | | |
60 | | #[inline(always)] |
61 | 0 | fn poly2(q: f32, a: f32, b: f32, c: f32, max: i32) -> i32 { |
62 | 0 | clamp((q * q).mul_add(a, q.mul_add(b, c)).round() as i32, 0, max) |
63 | 0 | } |
64 | | |
65 | | pub static TEMPORAL_DELIMITER: [u8; 2] = [0x12, 0x00]; |
66 | | |
67 | | const MAX_NUM_TEMPORAL_LAYERS: usize = 8; |
68 | | const MAX_NUM_SPATIAL_LAYERS: usize = 4; |
69 | | const MAX_NUM_OPERATING_POINTS: usize = |
70 | | MAX_NUM_TEMPORAL_LAYERS * MAX_NUM_SPATIAL_LAYERS; |
71 | | |
72 | | /// Size of blocks for the importance computation, in pixels. |
73 | | pub const IMPORTANCE_BLOCK_SIZE: usize = |
74 | | 1 << (IMPORTANCE_BLOCK_TO_BLOCK_SHIFT + BLOCK_TO_PLANE_SHIFT); |
75 | | |
76 | | #[derive(Debug, Clone)] |
77 | | pub struct ReferenceFrame<T: Pixel> { |
78 | | pub order_hint: u32, |
79 | | pub width: u32, |
80 | | pub height: u32, |
81 | | pub render_width: u32, |
82 | | pub render_height: u32, |
83 | | pub frame: Arc<Frame<T>>, |
84 | | pub input_hres: Arc<Plane<T>>, |
85 | | pub input_qres: Arc<Plane<T>>, |
86 | | pub cdfs: CDFContext, |
87 | | pub frame_me_stats: RefMEStats, |
88 | | pub output_frameno: u64, |
89 | | pub segmentation: SegmentationState, |
90 | | } |
91 | | |
92 | | #[derive(Debug, Clone, Default)] |
93 | | pub struct ReferenceFramesSet<T: Pixel> { |
94 | | pub frames: [Option<Arc<ReferenceFrame<T>>>; REF_FRAMES], |
95 | | pub deblock: [DeblockState; REF_FRAMES], |
96 | | } |
97 | | |
98 | | impl<T: Pixel> ReferenceFramesSet<T> { |
99 | 0 | pub fn new() -> Self { |
100 | 0 | Self { frames: Default::default(), deblock: Default::default() } |
101 | 0 | } Unexecuted instantiation: <rav1e::encoder::ReferenceFramesSet<u16>>::new Unexecuted instantiation: <rav1e::encoder::ReferenceFramesSet<u8>>::new |
102 | | } |
103 | | |
104 | | #[wasm_bindgen] |
105 | | #[derive( |
106 | 0 | ArgEnum, Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Default, Unexecuted instantiation: <rav1e::encoder::Tune as core::str::traits::FromStr>::from_str Unexecuted instantiation: <rav1e::encoder::Tune as core::fmt::Display>::fmt Unexecuted instantiation: <rav1e::encoder::Tune>::variants Unexecuted instantiation: <rav1e::encoder::Tune>::descriptions |
107 | | )] |
108 | | #[repr(C)] |
109 | | pub enum Tune { |
110 | | Psnr, |
111 | | #[default] |
112 | | Psychovisual, |
113 | | } |
114 | | |
115 | | const FRAME_ID_LENGTH: u32 = 15; |
116 | | const DELTA_FRAME_ID_LENGTH: u32 = 14; |
117 | | |
118 | | #[derive(Copy, Clone, Debug)] |
119 | | pub struct Sequence { |
120 | | /// OBU Sequence header of AV1 |
121 | | pub profile: u8, |
122 | | pub num_bits_width: u32, |
123 | | pub num_bits_height: u32, |
124 | | pub bit_depth: usize, |
125 | | pub chroma_sampling: ChromaSampling, |
126 | | pub chroma_sample_position: ChromaSamplePosition, |
127 | | pub pixel_range: PixelRange, |
128 | | pub color_description: Option<ColorDescription>, |
129 | | pub mastering_display: Option<MasteringDisplay>, |
130 | | pub content_light: Option<ContentLight>, |
131 | | pub max_frame_width: u32, |
132 | | pub max_frame_height: u32, |
133 | | pub frame_id_numbers_present_flag: bool, |
134 | | pub frame_id_length: u32, |
135 | | pub delta_frame_id_length: u32, |
136 | | pub use_128x128_superblock: bool, |
137 | | pub order_hint_bits_minus_1: u32, |
138 | | /// 0 - force off |
139 | | /// 1 - force on |
140 | | /// 2 - adaptive |
141 | | pub force_screen_content_tools: u32, |
142 | | /// 0 - Not to force. MV can be in 1/4 or 1/8 |
143 | | /// 1 - force to integer |
144 | | /// 2 - adaptive |
145 | | pub force_integer_mv: u32, |
146 | | /// Video is a single frame still picture |
147 | | pub still_picture: bool, |
148 | | /// Use reduced header for still picture |
149 | | pub reduced_still_picture_hdr: bool, |
150 | | /// enables/disables filter_intra |
151 | | pub enable_filter_intra: bool, |
152 | | /// enables/disables corner/edge filtering and upsampling |
153 | | pub enable_intra_edge_filter: bool, |
154 | | /// enables/disables interintra_compound |
155 | | pub enable_interintra_compound: bool, |
156 | | /// enables/disables masked compound |
157 | | pub enable_masked_compound: bool, |
158 | | /// 0 - disable dual interpolation filter |
159 | | /// 1 - enable vert/horiz filter selection |
160 | | pub enable_dual_filter: bool, |
161 | | /// 0 - disable order hint, and related tools |
162 | | /// jnt_comp, ref_frame_mvs, frame_sign_bias |
163 | | /// if 0, enable_jnt_comp and |
164 | | /// enable_ref_frame_mvs must be set zs 0. |
165 | | pub enable_order_hint: bool, |
166 | | /// 0 - disable joint compound modes |
167 | | /// 1 - enable it |
168 | | pub enable_jnt_comp: bool, |
169 | | /// 0 - disable ref frame mvs |
170 | | /// 1 - enable it |
171 | | pub enable_ref_frame_mvs: bool, |
172 | | /// 0 - disable warped motion for sequence |
173 | | /// 1 - enable it for the sequence |
174 | | pub enable_warped_motion: bool, |
175 | | /// 0 - Disable superres for the sequence, and disable |
176 | | /// transmitting per-frame superres enabled flag. |
177 | | /// 1 - Enable superres for the sequence, and also |
178 | | /// enable per-frame flag to denote if superres is |
179 | | /// enabled for that frame. |
180 | | pub enable_superres: bool, |
181 | | /// To turn on/off CDEF |
182 | | pub enable_cdef: bool, |
183 | | /// To turn on/off loop restoration |
184 | | pub enable_restoration: bool, |
185 | | /// To turn on/off larger-than-superblock loop restoration units |
186 | | pub enable_large_lru: bool, |
187 | | /// allow encoder to delay loop filter RDO/coding until after frame reconstruciton is complete |
188 | | pub enable_delayed_loopfilter_rdo: bool, |
189 | | pub operating_points_cnt_minus_1: usize, |
190 | | pub operating_point_idc: [u16; MAX_NUM_OPERATING_POINTS], |
191 | | pub display_model_info_present_flag: bool, |
192 | | pub decoder_model_info_present_flag: bool, |
193 | | pub level_idx: [u8; MAX_NUM_OPERATING_POINTS], |
194 | | /// seq_tier in the spec. One bit: 0 or 1. |
195 | | pub tier: [usize; MAX_NUM_OPERATING_POINTS], |
196 | | pub film_grain_params_present: bool, |
197 | | pub timing_info_present: bool, |
198 | | pub tiling: TilingInfo, |
199 | | pub time_base: Rational, |
200 | | } |
201 | | |
202 | | impl Sequence { |
203 | | /// # Panics |
204 | | /// |
205 | | /// Panics if the resulting tile sizes would be too large. |
206 | 0 | pub fn new(config: &EncoderConfig) -> Sequence { |
207 | 0 | let width_bits = 32 - (config.width as u32).leading_zeros(); |
208 | 0 | let height_bits = 32 - (config.height as u32).leading_zeros(); |
209 | 0 | assert!(width_bits <= 16); |
210 | 0 | assert!(height_bits <= 16); |
211 | | |
212 | 0 | let profile = if config.bit_depth == 12 |
213 | 0 | || config.chroma_sampling == ChromaSampling::Cs422 |
214 | | { |
215 | 0 | 2 |
216 | | } else { |
217 | 0 | u8::from(config.chroma_sampling == ChromaSampling::Cs444) |
218 | | }; |
219 | | |
220 | 0 | let operating_point_idc: [u16; MAX_NUM_OPERATING_POINTS] = |
221 | 0 | [0; MAX_NUM_OPERATING_POINTS]; |
222 | 0 | let level_idx: [u8; MAX_NUM_OPERATING_POINTS] = |
223 | 0 | if let Some(level_idx) = config.level_idx { |
224 | 0 | [level_idx; MAX_NUM_OPERATING_POINTS] |
225 | | } else { |
226 | 0 | [31; MAX_NUM_OPERATING_POINTS] |
227 | | }; |
228 | 0 | let tier: [usize; MAX_NUM_OPERATING_POINTS] = |
229 | 0 | [0; MAX_NUM_OPERATING_POINTS]; |
230 | | |
231 | | // Restoration filters are not useful for very small frame sizes, |
232 | | // so disable them in that case. |
233 | 0 | let enable_restoration_filters = config.width >= 32 && config.height >= 32; |
234 | 0 | let use_128x128_superblock = false; |
235 | 0 |
|
236 | 0 | let frame_rate = config.frame_rate(); |
237 | 0 | let sb_size_log2 = Self::sb_size_log2(use_128x128_superblock); |
238 | 0 |
|
239 | 0 | let mut tiling = TilingInfo::from_target_tiles( |
240 | 0 | sb_size_log2, |
241 | 0 | config.width, |
242 | 0 | config.height, |
243 | 0 | frame_rate, |
244 | 0 | TilingInfo::tile_log2(1, config.tile_cols).unwrap(), |
245 | 0 | TilingInfo::tile_log2(1, config.tile_rows).unwrap(), |
246 | 0 | config.chroma_sampling == ChromaSampling::Cs422, |
247 | 0 | ); |
248 | 0 |
|
249 | 0 | if config.tiles > 0 { |
250 | 0 | let mut tile_rows_log2 = 0; |
251 | 0 | let mut tile_cols_log2 = 0; |
252 | 0 | while (tile_rows_log2 < tiling.max_tile_rows_log2) |
253 | 0 | || (tile_cols_log2 < tiling.max_tile_cols_log2) |
254 | | { |
255 | 0 | tiling = TilingInfo::from_target_tiles( |
256 | 0 | sb_size_log2, |
257 | 0 | config.width, |
258 | 0 | config.height, |
259 | 0 | frame_rate, |
260 | 0 | tile_cols_log2, |
261 | 0 | tile_rows_log2, |
262 | 0 | config.chroma_sampling == ChromaSampling::Cs422, |
263 | 0 | ); |
264 | 0 |
|
265 | 0 | if tiling.rows * tiling.cols >= config.tiles { |
266 | 0 | break; |
267 | 0 | }; |
268 | 0 |
|
269 | 0 | if ((tiling.tile_height_sb >= tiling.tile_width_sb) |
270 | 0 | && (tiling.tile_rows_log2 < tiling.max_tile_rows_log2)) |
271 | 0 | || (tile_cols_log2 >= tiling.max_tile_cols_log2) |
272 | 0 | { |
273 | 0 | tile_rows_log2 += 1; |
274 | 0 | } else { |
275 | 0 | tile_cols_log2 += 1; |
276 | 0 | } |
277 | | } |
278 | 0 | } |
279 | | |
280 | | Sequence { |
281 | 0 | tiling, |
282 | 0 | profile, |
283 | 0 | num_bits_width: width_bits, |
284 | 0 | num_bits_height: height_bits, |
285 | 0 | bit_depth: config.bit_depth, |
286 | 0 | chroma_sampling: config.chroma_sampling, |
287 | 0 | chroma_sample_position: config.chroma_sample_position, |
288 | 0 | pixel_range: config.pixel_range, |
289 | 0 | color_description: config.color_description, |
290 | 0 | mastering_display: config.mastering_display, |
291 | 0 | content_light: config.content_light, |
292 | 0 | max_frame_width: config.width as u32, |
293 | 0 | max_frame_height: config.height as u32, |
294 | 0 | frame_id_numbers_present_flag: false, |
295 | 0 | frame_id_length: FRAME_ID_LENGTH, |
296 | 0 | delta_frame_id_length: DELTA_FRAME_ID_LENGTH, |
297 | 0 | use_128x128_superblock, |
298 | 0 | order_hint_bits_minus_1: 5, |
299 | 0 | force_screen_content_tools: if config.still_picture { 2 } else { 0 }, |
300 | | force_integer_mv: 2, |
301 | 0 | still_picture: config.still_picture, |
302 | 0 | reduced_still_picture_hdr: config.still_picture, |
303 | 0 | enable_filter_intra: false, |
304 | 0 | enable_intra_edge_filter: true, |
305 | 0 | enable_interintra_compound: false, |
306 | 0 | enable_masked_compound: false, |
307 | 0 | enable_dual_filter: false, |
308 | 0 | enable_order_hint: !config.still_picture, |
309 | 0 | enable_jnt_comp: false, |
310 | 0 | enable_ref_frame_mvs: false, |
311 | 0 | enable_warped_motion: false, |
312 | 0 | enable_superres: false, |
313 | 0 | enable_cdef: config.speed_settings.cdef && enable_restoration_filters, |
314 | 0 | enable_restoration: config.speed_settings.lrf |
315 | 0 | && enable_restoration_filters, |
316 | | enable_large_lru: true, |
317 | | enable_delayed_loopfilter_rdo: true, |
318 | | operating_points_cnt_minus_1: 0, |
319 | 0 | operating_point_idc, |
320 | 0 | display_model_info_present_flag: false, |
321 | 0 | decoder_model_info_present_flag: false, |
322 | 0 | level_idx, |
323 | 0 | tier, |
324 | 0 | film_grain_params_present: config |
325 | 0 | .film_grain_params |
326 | 0 | .as_ref() |
327 | 0 | .map(|entries| !entries.is_empty()) |
328 | 0 | .unwrap_or(false), |
329 | 0 | timing_info_present: config.enable_timing_info, |
330 | 0 | time_base: config.time_base, |
331 | 0 | } |
332 | 0 | } |
333 | | |
334 | 0 | pub const fn get_relative_dist(&self, a: u32, b: u32) -> i32 { |
335 | 0 | let diff = a as i32 - b as i32; |
336 | 0 | let m = 1 << self.order_hint_bits_minus_1; |
337 | 0 | (diff & (m - 1)) - (diff & m) |
338 | 0 | } |
339 | | |
340 | 0 | pub fn get_skip_mode_allowed<T: Pixel>( |
341 | 0 | &self, fi: &FrameInvariants<T>, inter_cfg: &InterConfig, |
342 | 0 | reference_select: bool, |
343 | 0 | ) -> bool { |
344 | 0 | if fi.intra_only || !reference_select || !self.enable_order_hint { |
345 | 0 | return false; |
346 | 0 | } |
347 | 0 |
|
348 | 0 | let mut forward_idx: isize = -1; |
349 | 0 | let mut backward_idx: isize = -1; |
350 | 0 | let mut forward_hint = 0; |
351 | 0 | let mut backward_hint = 0; |
352 | | |
353 | 0 | for i in inter_cfg.allowed_ref_frames().iter().map(|rf| rf.to_index()) { Unexecuted instantiation: <rav1e::encoder::Sequence>::get_skip_mode_allowed::<u16>::{closure#0} Unexecuted instantiation: <rav1e::encoder::Sequence>::get_skip_mode_allowed::<u8>::{closure#0} |
354 | 0 | if let Some(ref rec) = fi.rec_buffer.frames[fi.ref_frames[i] as usize] { |
355 | 0 | let ref_hint = rec.order_hint; |
356 | 0 |
|
357 | 0 | if self.get_relative_dist(ref_hint, fi.order_hint) < 0 { |
358 | 0 | if forward_idx < 0 |
359 | 0 | || self.get_relative_dist(ref_hint, forward_hint) > 0 |
360 | 0 | { |
361 | 0 | forward_idx = i as isize; |
362 | 0 | forward_hint = ref_hint; |
363 | 0 | } |
364 | 0 | } else if self.get_relative_dist(ref_hint, fi.order_hint) > 0 |
365 | 0 | && (backward_idx < 0 |
366 | 0 | || self.get_relative_dist(ref_hint, backward_hint) > 0) |
367 | 0 | { |
368 | 0 | backward_idx = i as isize; |
369 | 0 | backward_hint = ref_hint; |
370 | 0 | } |
371 | 0 | } |
372 | | } |
373 | | |
374 | 0 | if forward_idx < 0 { |
375 | 0 | false |
376 | 0 | } else if backward_idx >= 0 { |
377 | | // set skip_mode_frame |
378 | 0 | true |
379 | | } else { |
380 | 0 | let mut second_forward_idx: isize = -1; |
381 | 0 | let mut second_forward_hint = 0; |
382 | | |
383 | 0 | for i in inter_cfg.allowed_ref_frames().iter().map(|rf| rf.to_index()) { Unexecuted instantiation: <rav1e::encoder::Sequence>::get_skip_mode_allowed::<u16>::{closure#1} Unexecuted instantiation: <rav1e::encoder::Sequence>::get_skip_mode_allowed::<u8>::{closure#1} |
384 | 0 | if let Some(ref rec) = fi.rec_buffer.frames[fi.ref_frames[i] as usize] |
385 | | { |
386 | 0 | let ref_hint = rec.order_hint; |
387 | 0 |
|
388 | 0 | if self.get_relative_dist(ref_hint, forward_hint) < 0 |
389 | 0 | && (second_forward_idx < 0 |
390 | 0 | || self.get_relative_dist(ref_hint, second_forward_hint) > 0) |
391 | 0 | { |
392 | 0 | second_forward_idx = i as isize; |
393 | 0 | second_forward_hint = ref_hint; |
394 | 0 | } |
395 | 0 | } |
396 | | } |
397 | | |
398 | | // TODO: Set skip_mode_frame, when second_forward_idx is not less than 0. |
399 | 0 | second_forward_idx >= 0 |
400 | | } |
401 | 0 | } Unexecuted instantiation: <rav1e::encoder::Sequence>::get_skip_mode_allowed::<u16> Unexecuted instantiation: <rav1e::encoder::Sequence>::get_skip_mode_allowed::<u8> |
402 | | |
403 | | #[inline(always)] |
404 | 0 | const fn sb_size_log2(use_128x128_superblock: bool) -> usize { |
405 | 0 | 6 + (use_128x128_superblock as usize) |
406 | 0 | } |
407 | | } |
408 | | |
409 | | #[derive(Debug, Clone)] |
410 | | pub struct FrameState<T: Pixel> { |
411 | | pub sb_size_log2: usize, |
412 | | pub input: Arc<Frame<T>>, |
413 | | pub input_hres: Arc<Plane<T>>, // half-resolution version of input luma |
414 | | pub input_qres: Arc<Plane<T>>, // quarter-resolution version of input luma |
415 | | pub rec: Arc<Frame<T>>, |
416 | | pub cdfs: CDFContext, |
417 | | pub context_update_tile_id: usize, // tile id used for the CDFontext |
418 | | pub max_tile_size_bytes: u32, |
419 | | pub deblock: DeblockState, |
420 | | pub segmentation: SegmentationState, |
421 | | pub restoration: RestorationState, |
422 | | // Because we only reference these within a tile context, |
423 | | // these are stored per-tile for easier access. |
424 | | pub frame_me_stats: RefMEStats, |
425 | | pub enc_stats: EncoderStats, |
426 | | } |
427 | | |
428 | | impl<T: Pixel> FrameState<T> { |
429 | 0 | pub fn new(fi: &FrameInvariants<T>) -> Self { |
430 | 0 | // TODO(negge): Use fi.cfg.chroma_sampling when we store VideoDetails in FrameInvariants |
431 | 0 | FrameState::new_with_frame( |
432 | 0 | fi, |
433 | 0 | Arc::new(Frame::new(fi.width, fi.height, fi.sequence.chroma_sampling)), |
434 | 0 | ) |
435 | 0 | } |
436 | | |
437 | | /// Similar to [`FrameState::new_with_frame`], but takes an `me_stats` |
438 | | /// and `rec` to enable reusing the same underlying allocations to create |
439 | | /// a `FrameState` |
440 | | /// |
441 | | /// This function primarily exists for [`estimate_inter_costs`], and so |
442 | | /// it does not create hres or qres versions of `frame` as downscaling is |
443 | | /// somewhat expensive and are not needed for [`estimate_inter_costs`]. |
444 | 0 | pub fn new_with_frame_and_me_stats_and_rec( |
445 | 0 | fi: &FrameInvariants<T>, frame: Arc<Frame<T>>, me_stats: RefMEStats, |
446 | 0 | rec: Arc<Frame<T>>, |
447 | 0 | ) -> Self { |
448 | 0 | let rs = RestorationState::new(fi, &frame); |
449 | 0 |
|
450 | 0 | let hres = Plane::new(0, 0, 0, 0, 0, 0); |
451 | 0 | let qres = Plane::new(0, 0, 0, 0, 0, 0); |
452 | 0 |
|
453 | 0 | Self { |
454 | 0 | sb_size_log2: fi.sb_size_log2(), |
455 | 0 | input: frame, |
456 | 0 | input_hres: Arc::new(hres), |
457 | 0 | input_qres: Arc::new(qres), |
458 | 0 | rec, |
459 | 0 | cdfs: CDFContext::new(0), |
460 | 0 | context_update_tile_id: 0, |
461 | 0 | max_tile_size_bytes: 0, |
462 | 0 | deblock: Default::default(), |
463 | 0 | segmentation: Default::default(), |
464 | 0 | restoration: rs, |
465 | 0 | frame_me_stats: me_stats, |
466 | 0 | enc_stats: Default::default(), |
467 | 0 | } |
468 | 0 | } Unexecuted instantiation: <rav1e::encoder::FrameState<u16>>::new_with_frame_and_me_stats_and_rec Unexecuted instantiation: <rav1e::encoder::FrameState<u8>>::new_with_frame_and_me_stats_and_rec |
469 | | |
470 | 0 | pub fn new_with_frame( |
471 | 0 | fi: &FrameInvariants<T>, frame: Arc<Frame<T>>, |
472 | 0 | ) -> Self { |
473 | 0 | let rs = RestorationState::new(fi, &frame); |
474 | 0 | let luma_width = frame.planes[0].cfg.width; |
475 | 0 | let luma_height = frame.planes[0].cfg.height; |
476 | 0 |
|
477 | 0 | let hres = frame.planes[0].downsampled(fi.width, fi.height); |
478 | 0 | let qres = hres.downsampled(fi.width, fi.height); |
479 | 0 |
|
480 | 0 | Self { |
481 | 0 | sb_size_log2: fi.sb_size_log2(), |
482 | 0 | input: frame, |
483 | 0 | input_hres: Arc::new(hres), |
484 | 0 | input_qres: Arc::new(qres), |
485 | 0 | rec: Arc::new(Frame::new( |
486 | 0 | luma_width, |
487 | 0 | luma_height, |
488 | 0 | fi.sequence.chroma_sampling, |
489 | 0 | )), |
490 | 0 | cdfs: CDFContext::new(0), |
491 | 0 | context_update_tile_id: 0, |
492 | 0 | max_tile_size_bytes: 0, |
493 | 0 | deblock: Default::default(), |
494 | 0 | segmentation: Default::default(), |
495 | 0 | restoration: rs, |
496 | 0 | frame_me_stats: FrameMEStats::new_arc_array(fi.w_in_b, fi.h_in_b), |
497 | 0 | enc_stats: Default::default(), |
498 | 0 | } |
499 | 0 | } Unexecuted instantiation: <rav1e::encoder::FrameState<u16>>::new_with_frame Unexecuted instantiation: <rav1e::encoder::FrameState<u8>>::new_with_frame |
500 | | |
501 | 0 | pub fn apply_tile_state_mut<F, R>(&mut self, f: F) -> R |
502 | 0 | where |
503 | 0 | F: FnOnce(&mut TileStateMut<'_, T>) -> R, |
504 | 0 | { |
505 | 0 | let PlaneConfig { width, height, .. } = self.rec.planes[0].cfg; |
506 | 0 | let sbo_0 = PlaneSuperBlockOffset(SuperBlockOffset { x: 0, y: 0 }); |
507 | 0 | let frame_me_stats = self.frame_me_stats.clone(); |
508 | 0 | let frame_me_stats = &mut *frame_me_stats.write().expect("poisoned lock"); |
509 | 0 | let ts = &mut TileStateMut::new( |
510 | 0 | self, |
511 | 0 | sbo_0, |
512 | 0 | self.sb_size_log2, |
513 | 0 | width, |
514 | 0 | height, |
515 | 0 | frame_me_stats, |
516 | 0 | ); |
517 | 0 |
|
518 | 0 | f(ts) |
519 | 0 | } Unexecuted instantiation: <rav1e::encoder::FrameState<u16>>::apply_tile_state_mut::<rav1e::encoder::encode_tile_group<u16>::{closure#2}, ()> Unexecuted instantiation: <rav1e::encoder::FrameState<u16>>::apply_tile_state_mut::<rav1e::encoder::encode_tile_group<u16>::{closure#3}, ()> Unexecuted instantiation: <rav1e::encoder::FrameState<u16>>::apply_tile_state_mut::<rav1e::encoder::encode_tile_group<u16>::{closure#4}, ()> Unexecuted instantiation: <rav1e::encoder::FrameState<u16>>::apply_tile_state_mut::<rav1e::encoder::encode_tile_group<u16>::{closure#1}, [u8; 4]> Unexecuted instantiation: <rav1e::encoder::FrameState<u8>>::apply_tile_state_mut::<rav1e::encoder::encode_tile_group<u8>::{closure#2}, ()> Unexecuted instantiation: <rav1e::encoder::FrameState<u8>>::apply_tile_state_mut::<rav1e::encoder::encode_tile_group<u8>::{closure#3}, ()> Unexecuted instantiation: <rav1e::encoder::FrameState<u8>>::apply_tile_state_mut::<rav1e::encoder::encode_tile_group<u8>::{closure#4}, ()> Unexecuted instantiation: <rav1e::encoder::FrameState<u8>>::apply_tile_state_mut::<rav1e::encoder::encode_tile_group<u8>::{closure#1}, [u8; 4]> |
520 | | } |
521 | | |
522 | | #[derive(Copy, Clone, Debug)] |
523 | | pub struct DeblockState { |
524 | | pub levels: [u8; MAX_PLANES + 1], // Y vertical edges, Y horizontal, U, V |
525 | | pub sharpness: u8, |
526 | | pub deltas_enabled: bool, |
527 | | pub delta_updates_enabled: bool, |
528 | | pub ref_deltas: [i8; REF_FRAMES], |
529 | | pub mode_deltas: [i8; 2], |
530 | | pub block_deltas_enabled: bool, |
531 | | pub block_delta_shift: u8, |
532 | | pub block_delta_multi: bool, |
533 | | } |
534 | | |
535 | | impl Default for DeblockState { |
536 | 0 | fn default() -> Self { |
537 | 0 | DeblockState { |
538 | 0 | levels: [8, 8, 4, 4], |
539 | 0 | sharpness: 0, |
540 | 0 | deltas_enabled: false, // requires delta_q_enabled |
541 | 0 | delta_updates_enabled: false, |
542 | 0 | ref_deltas: [1, 0, 0, 0, 0, -1, -1, -1], |
543 | 0 | mode_deltas: [0, 0], |
544 | 0 | block_deltas_enabled: false, |
545 | 0 | block_delta_shift: 0, |
546 | 0 | block_delta_multi: false, |
547 | 0 | } |
548 | 0 | } |
549 | | } |
550 | | |
551 | | #[derive(Copy, Clone, Debug, Default)] |
552 | | pub struct SegmentationState { |
553 | | pub enabled: bool, |
554 | | pub update_data: bool, |
555 | | pub update_map: bool, |
556 | | pub preskip: bool, |
557 | | pub last_active_segid: u8, |
558 | | pub features: [[bool; SegLvl::SEG_LVL_MAX as usize]; 8], |
559 | | pub data: [[i16; SegLvl::SEG_LVL_MAX as usize]; 8], |
560 | | pub threshold: [DistortionScale; 7], |
561 | | pub min_segment: u8, |
562 | | pub max_segment: u8, |
563 | | } |
564 | | |
565 | | impl SegmentationState { |
566 | 0 | #[profiling::function] |
567 | | pub fn update_threshold(&mut self, base_q_idx: u8, bd: usize) { |
568 | | let base_ac_q = ac_q(base_q_idx, 0, bd).get() as u64; |
569 | | let real_ac_q = ArrayVec::<_, MAX_SEGMENTS>::from_iter( |
570 | 0 | self.data[..=self.max_segment as usize].iter().map(|data| { |
571 | 0 | ac_q(base_q_idx, data[SegLvl::SEG_LVL_ALT_Q as usize] as i8, bd).get() |
572 | 0 | as u64 |
573 | 0 | }), |
574 | | ); |
575 | | self.threshold.fill(DistortionScale(0)); |
576 | | for ((q1, q2), threshold) in |
577 | | real_ac_q.iter().skip(1).zip(&real_ac_q).zip(&mut self.threshold) |
578 | | { |
579 | | *threshold = DistortionScale::new(base_ac_q.pow(2), q1 * q2); |
580 | | } |
581 | | } |
582 | | |
583 | | #[cfg(feature = "dump_lookahead_data")] |
584 | | pub fn dump_threshold( |
585 | | &self, data_location: std::path::PathBuf, input_frameno: u64, |
586 | | ) { |
587 | | use byteorder::{NativeEndian, WriteBytesExt}; |
588 | | let file_name = format!("{:010}-thresholds", input_frameno); |
589 | | let max_segment = self.max_segment; |
590 | | // dynamic allocation: debugging only |
591 | | let mut buf = vec![]; |
592 | | buf.write_u64::<NativeEndian>(max_segment as u64).unwrap(); |
593 | | for &v in &self.threshold[..max_segment as usize] { |
594 | | buf.write_u32::<NativeEndian>(v.0).unwrap(); |
595 | | } |
596 | | ::std::fs::write(data_location.join(file_name).with_extension("bin"), buf) |
597 | | .unwrap(); |
598 | | } |
599 | | } |
600 | | |
601 | | // Frame Invariants are invariant inside a frame |
602 | | #[allow(dead_code)] |
603 | | #[derive(Debug, Clone)] |
604 | | pub struct FrameInvariants<T: Pixel> { |
605 | | pub sequence: Arc<Sequence>, |
606 | | pub config: Arc<EncoderConfig>, |
607 | | pub width: usize, |
608 | | pub height: usize, |
609 | | pub render_width: u32, |
610 | | pub render_height: u32, |
611 | | pub frame_size_override_flag: bool, |
612 | | pub render_and_frame_size_different: bool, |
613 | | pub sb_width: usize, |
614 | | pub sb_height: usize, |
615 | | pub w_in_b: usize, |
616 | | pub h_in_b: usize, |
617 | | pub input_frameno: u64, |
618 | | pub order_hint: u32, |
619 | | pub show_frame: bool, |
620 | | pub showable_frame: bool, |
621 | | pub error_resilient: bool, |
622 | | pub intra_only: bool, |
623 | | pub allow_high_precision_mv: bool, |
624 | | pub frame_type: FrameType, |
625 | | pub frame_to_show_map_idx: u32, |
626 | | pub use_reduced_tx_set: bool, |
627 | | pub reference_mode: ReferenceMode, |
628 | | pub use_prev_frame_mvs: bool, |
629 | | pub partition_range: PartitionRange, |
630 | | pub globalmv_transformation_type: [GlobalMVMode; INTER_REFS_PER_FRAME], |
631 | | pub num_tg: usize, |
632 | | pub large_scale_tile: bool, |
633 | | pub disable_cdf_update: bool, |
634 | | pub allow_screen_content_tools: u32, |
635 | | pub force_integer_mv: u32, |
636 | | pub primary_ref_frame: u32, |
637 | | pub refresh_frame_flags: u32, // a bitmask that specifies which |
638 | | // reference frame slots will be updated with the current frame |
639 | | // after it is decoded. |
640 | | pub allow_intrabc: bool, |
641 | | pub use_ref_frame_mvs: bool, |
642 | | pub is_filter_switchable: bool, |
643 | | pub is_motion_mode_switchable: bool, |
644 | | pub disable_frame_end_update_cdf: bool, |
645 | | pub allow_warped_motion: bool, |
646 | | pub cdef_search_method: CDEFSearchMethod, |
647 | | pub cdef_damping: u8, |
648 | | pub cdef_bits: u8, |
649 | | pub cdef_y_strengths: [u8; 8], |
650 | | pub cdef_uv_strengths: [u8; 8], |
651 | | pub delta_q_present: bool, |
652 | | pub ref_frames: [u8; INTER_REFS_PER_FRAME], |
653 | | pub ref_frame_sign_bias: [bool; INTER_REFS_PER_FRAME], |
654 | | pub rec_buffer: ReferenceFramesSet<T>, |
655 | | pub base_q_idx: u8, |
656 | | pub dc_delta_q: [i8; 3], |
657 | | pub ac_delta_q: [i8; 3], |
658 | | pub lambda: f64, |
659 | | pub me_lambda: f64, |
660 | | pub dist_scale: [DistortionScale; 3], |
661 | | pub me_range_scale: u8, |
662 | | pub use_tx_domain_distortion: bool, |
663 | | pub use_tx_domain_rate: bool, |
664 | | pub idx_in_group_output: u64, |
665 | | pub pyramid_level: u64, |
666 | | pub enable_early_exit: bool, |
667 | | pub tx_mode_select: bool, |
668 | | pub enable_inter_txfm_split: bool, |
669 | | pub default_filter: FilterMode, |
670 | | pub enable_segmentation: bool, |
671 | | pub t35_metadata: Box<[T35]>, |
672 | | /// Target CPU feature level. |
673 | | pub cpu_feature_level: crate::cpu_features::CpuFeatureLevel, |
674 | | |
675 | | // These will be set if this is a coded (non-SEF) frame. |
676 | | // We do not need them for SEFs. |
677 | | pub coded_frame_data: Option<CodedFrameData<T>>, |
678 | | } |
679 | | |
680 | | /// These frame invariants are only used on coded frames, i.e. non-SEFs. |
681 | | /// They are stored separately to avoid useless allocations |
682 | | /// when we do not need them. |
683 | | /// |
684 | | /// Currently this consists only of lookahaed data. |
685 | | /// This may change in the future. |
686 | | #[derive(Debug, Clone)] |
687 | | pub struct CodedFrameData<T: Pixel> { |
688 | | /// The lookahead version of `rec_buffer`, used for storing and propagating |
689 | | /// the original reference frames (rather than reconstructed ones). The |
690 | | /// lookahead uses both `rec_buffer` and `lookahead_rec_buffer`, where |
691 | | /// `rec_buffer` contains the current frame's reference frames and |
692 | | /// `lookahead_rec_buffer` contains the next frame's reference frames. |
693 | | pub lookahead_rec_buffer: ReferenceFramesSet<T>, |
694 | | /// Frame width in importance blocks. |
695 | | pub w_in_imp_b: usize, |
696 | | /// Frame height in importance blocks. |
697 | | pub h_in_imp_b: usize, |
698 | | /// Intra prediction cost estimations for each importance block. |
699 | | pub lookahead_intra_costs: Box<[u32]>, |
700 | | /// Future importance values for each importance block. That is, a value |
701 | | /// indicating how much future frames depend on the block (for example, via |
702 | | /// inter-prediction). |
703 | | pub block_importances: Box<[f32]>, |
704 | | /// Pre-computed distortion_scale. |
705 | | pub distortion_scales: Box<[DistortionScale]>, |
706 | | /// Pre-computed activity_scale. |
707 | | pub activity_scales: Box<[DistortionScale]>, |
708 | | pub activity_mask: ActivityMask, |
709 | | /// Combined metric of activity and distortion |
710 | | pub spatiotemporal_scores: Box<[DistortionScale]>, |
711 | | } |
712 | | |
713 | | impl<T: Pixel> CodedFrameData<T> { |
714 | 0 | pub fn new(fi: &FrameInvariants<T>) -> CodedFrameData<T> { |
715 | 0 | // Width and height are padded to 8×8 block size. |
716 | 0 | let w_in_imp_b = fi.w_in_b / 2; |
717 | 0 | let h_in_imp_b = fi.h_in_b / 2; |
718 | 0 |
|
719 | 0 | CodedFrameData { |
720 | 0 | lookahead_rec_buffer: ReferenceFramesSet::new(), |
721 | 0 | w_in_imp_b, |
722 | 0 | h_in_imp_b, |
723 | 0 | // This is never used before it is assigned |
724 | 0 | lookahead_intra_costs: Box::new([]), |
725 | 0 | // dynamic allocation: once per frame |
726 | 0 | block_importances: vec![0.; w_in_imp_b * h_in_imp_b].into_boxed_slice(), |
727 | 0 | distortion_scales: vec![ |
728 | 0 | DistortionScale::default(); |
729 | 0 | w_in_imp_b * h_in_imp_b |
730 | 0 | ] |
731 | 0 | .into_boxed_slice(), |
732 | 0 | activity_scales: vec![ |
733 | 0 | DistortionScale::default(); |
734 | 0 | w_in_imp_b * h_in_imp_b |
735 | 0 | ] |
736 | 0 | .into_boxed_slice(), |
737 | 0 | activity_mask: Default::default(), |
738 | 0 | spatiotemporal_scores: Default::default(), |
739 | 0 | } |
740 | 0 | } Unexecuted instantiation: <rav1e::encoder::CodedFrameData<u16>>::new Unexecuted instantiation: <rav1e::encoder::CodedFrameData<u8>>::new |
741 | | |
742 | | // Assumes that we have already computed activity scales and distortion scales |
743 | | // Returns -0.5 log2(mean(scale)) |
744 | 0 | #[profiling::function] Unexecuted instantiation: <rav1e::encoder::CodedFrameData<u16>>::compute_spatiotemporal_scores Unexecuted instantiation: <rav1e::encoder::CodedFrameData<u8>>::compute_spatiotemporal_scores |
745 | | pub fn compute_spatiotemporal_scores(&mut self) -> i64 { |
746 | | let mut scores = self |
747 | | .distortion_scales |
748 | | .iter() |
749 | | .zip(self.activity_scales.iter()) |
750 | 0 | .map(|(&d, &a)| d * a) Unexecuted instantiation: <rav1e::encoder::CodedFrameData<u16>>::compute_spatiotemporal_scores::{closure#0} Unexecuted instantiation: <rav1e::encoder::CodedFrameData<u8>>::compute_spatiotemporal_scores::{closure#0} |
751 | | .collect::<Box<_>>(); |
752 | | |
753 | | let inv_mean = DistortionScale::inv_mean(&scores); |
754 | | |
755 | | for score in scores.iter_mut() { |
756 | | *score *= inv_mean; |
757 | | } |
758 | | |
759 | | for scale in self.distortion_scales.iter_mut() { |
760 | | *scale *= inv_mean; |
761 | | } |
762 | | |
763 | | self.spatiotemporal_scores = scores; |
764 | | |
765 | | inv_mean.blog64() >> 1 |
766 | | } |
767 | | |
768 | | // Assumes that we have already computed distortion_scales |
769 | | // Returns -0.5 log2(mean(scale)) |
770 | 0 | #[profiling::function] Unexecuted instantiation: <rav1e::encoder::CodedFrameData<u16>>::compute_temporal_scores Unexecuted instantiation: <rav1e::encoder::CodedFrameData<u8>>::compute_temporal_scores |
771 | | pub fn compute_temporal_scores(&mut self) -> i64 { |
772 | | let inv_mean = DistortionScale::inv_mean(&self.distortion_scales); |
773 | | for scale in self.distortion_scales.iter_mut() { |
774 | | *scale *= inv_mean; |
775 | | } |
776 | | self.spatiotemporal_scores = self.distortion_scales.clone(); |
777 | | inv_mean.blog64() >> 1 |
778 | | } |
779 | | |
780 | | #[cfg(feature = "dump_lookahead_data")] |
781 | | pub fn dump_scales( |
782 | | &self, data_location: std::path::PathBuf, scales: Scales, |
783 | | input_frameno: u64, |
784 | | ) { |
785 | | use byteorder::{NativeEndian, WriteBytesExt}; |
786 | | let file_name = format!( |
787 | | "{:010}-{}", |
788 | | input_frameno, |
789 | | match scales { |
790 | | Scales::ActivityScales => "activity_scales", |
791 | | Scales::DistortionScales => "distortion_scales", |
792 | | Scales::SpatiotemporalScales => "spatiotemporal_scales", |
793 | | } |
794 | | ); |
795 | | // dynamic allocation: debugging only |
796 | | let mut buf = vec![]; |
797 | | buf.write_u64::<NativeEndian>(self.w_in_imp_b as u64).unwrap(); |
798 | | buf.write_u64::<NativeEndian>(self.h_in_imp_b as u64).unwrap(); |
799 | | for &v in match scales { |
800 | | Scales::ActivityScales => &self.activity_scales[..], |
801 | | Scales::DistortionScales => &self.distortion_scales[..], |
802 | | Scales::SpatiotemporalScales => &self.spatiotemporal_scores[..], |
803 | | } { |
804 | | buf.write_u32::<NativeEndian>(v.0).unwrap(); |
805 | | } |
806 | | ::std::fs::write(data_location.join(file_name).with_extension("bin"), buf) |
807 | | .unwrap(); |
808 | | } |
809 | | } |
810 | | |
811 | | #[cfg(feature = "dump_lookahead_data")] |
812 | | pub enum Scales { |
813 | | ActivityScales, |
814 | | DistortionScales, |
815 | | SpatiotemporalScales, |
816 | | } |
817 | | |
818 | 0 | pub(crate) const fn pos_to_lvl(pos: u64, pyramid_depth: u64) -> u64 { |
819 | 0 | // Derive level within pyramid for a frame with a given coding order position |
820 | 0 | // For example, with a pyramid of depth 2, the 2 least significant bits of the |
821 | 0 | // position determine the level: |
822 | 0 | // 00 -> 0 |
823 | 0 | // 01 -> 2 |
824 | 0 | // 10 -> 1 |
825 | 0 | // 11 -> 2 |
826 | 0 | pyramid_depth - (pos | (1 << pyramid_depth)).trailing_zeros() as u64 |
827 | 0 | } |
828 | | |
829 | | impl<T: Pixel> FrameInvariants<T> { |
830 | | #[allow(clippy::erasing_op, clippy::identity_op)] |
831 | | /// # Panics |
832 | | /// |
833 | | /// - If the size of `T` does not match the sequence's bit depth |
834 | 0 | pub fn new(config: Arc<EncoderConfig>, sequence: Arc<Sequence>) -> Self { |
835 | 0 | assert!( |
836 | 0 | sequence.bit_depth <= mem::size_of::<T>() * 8, |
837 | 0 | "bit depth cannot fit into u8" |
838 | | ); |
839 | | |
840 | 0 | let (width, height) = (config.width, config.height); |
841 | 0 | let frame_size_override_flag = width as u32 != sequence.max_frame_width |
842 | 0 | || height as u32 != sequence.max_frame_height; |
843 | | |
844 | 0 | let (render_width, render_height) = config.render_size(); |
845 | 0 | let render_and_frame_size_different = |
846 | 0 | render_width != width || render_height != height; |
847 | | |
848 | 0 | let use_reduced_tx_set = config.speed_settings.transform.reduced_tx_set; |
849 | 0 | let use_tx_domain_distortion = config.tune == Tune::Psnr |
850 | 0 | && config.speed_settings.transform.tx_domain_distortion; |
851 | 0 | let use_tx_domain_rate = config.speed_settings.transform.tx_domain_rate; |
852 | 0 |
|
853 | 0 | let w_in_b = 2 * config.width.align_power_of_two_and_shift(3); // MiCols, ((width+7)/8)<<3 >> MI_SIZE_LOG2 |
854 | 0 | let h_in_b = 2 * config.height.align_power_of_two_and_shift(3); // MiRows, ((height+7)/8)<<3 >> MI_SIZE_LOG2 |
855 | 0 |
|
856 | 0 | Self { |
857 | 0 | width, |
858 | 0 | height, |
859 | 0 | render_width: render_width as u32, |
860 | 0 | render_height: render_height as u32, |
861 | 0 | frame_size_override_flag, |
862 | 0 | render_and_frame_size_different, |
863 | 0 | sb_width: width.align_power_of_two_and_shift(6), |
864 | 0 | sb_height: height.align_power_of_two_and_shift(6), |
865 | 0 | w_in_b, |
866 | 0 | h_in_b, |
867 | 0 | input_frameno: 0, |
868 | 0 | order_hint: 0, |
869 | 0 | show_frame: true, |
870 | 0 | showable_frame: !sequence.reduced_still_picture_hdr, |
871 | 0 | error_resilient: false, |
872 | 0 | intra_only: true, |
873 | 0 | allow_high_precision_mv: false, |
874 | 0 | frame_type: FrameType::KEY, |
875 | 0 | frame_to_show_map_idx: 0, |
876 | 0 | use_reduced_tx_set, |
877 | 0 | reference_mode: ReferenceMode::SINGLE, |
878 | 0 | use_prev_frame_mvs: false, |
879 | 0 | partition_range: config.speed_settings.partition.partition_range, |
880 | 0 | globalmv_transformation_type: [GlobalMVMode::IDENTITY; |
881 | 0 | INTER_REFS_PER_FRAME], |
882 | 0 | num_tg: 1, |
883 | 0 | large_scale_tile: false, |
884 | 0 | disable_cdf_update: false, |
885 | 0 | allow_screen_content_tools: sequence.force_screen_content_tools, |
886 | 0 | force_integer_mv: 1, |
887 | 0 | primary_ref_frame: PRIMARY_REF_NONE, |
888 | 0 | refresh_frame_flags: ALL_REF_FRAMES_MASK, |
889 | 0 | allow_intrabc: false, |
890 | 0 | use_ref_frame_mvs: false, |
891 | 0 | is_filter_switchable: false, |
892 | 0 | is_motion_mode_switchable: false, // 0: only the SIMPLE motion mode will be used. |
893 | 0 | disable_frame_end_update_cdf: sequence.reduced_still_picture_hdr, |
894 | 0 | allow_warped_motion: false, |
895 | 0 | cdef_search_method: CDEFSearchMethod::PickFromQ, |
896 | 0 | cdef_damping: 3, |
897 | 0 | cdef_bits: 0, |
898 | 0 | cdef_y_strengths: [ |
899 | 0 | 0 * 4 + 0, |
900 | 0 | 1 * 4 + 0, |
901 | 0 | 2 * 4 + 1, |
902 | 0 | 3 * 4 + 1, |
903 | 0 | 5 * 4 + 2, |
904 | 0 | 7 * 4 + 3, |
905 | 0 | 10 * 4 + 3, |
906 | 0 | 13 * 4 + 3, |
907 | 0 | ], |
908 | 0 | cdef_uv_strengths: [ |
909 | 0 | 0 * 4 + 0, |
910 | 0 | 1 * 4 + 0, |
911 | 0 | 2 * 4 + 1, |
912 | 0 | 3 * 4 + 1, |
913 | 0 | 5 * 4 + 2, |
914 | 0 | 7 * 4 + 3, |
915 | 0 | 10 * 4 + 3, |
916 | 0 | 13 * 4 + 3, |
917 | 0 | ], |
918 | 0 | delta_q_present: false, |
919 | 0 | ref_frames: [0; INTER_REFS_PER_FRAME], |
920 | 0 | ref_frame_sign_bias: [false; INTER_REFS_PER_FRAME], |
921 | 0 | rec_buffer: ReferenceFramesSet::new(), |
922 | 0 | base_q_idx: config.quantizer as u8, |
923 | 0 | dc_delta_q: [0; 3], |
924 | 0 | ac_delta_q: [0; 3], |
925 | 0 | lambda: 0.0, |
926 | 0 | dist_scale: Default::default(), |
927 | 0 | me_lambda: 0.0, |
928 | 0 | me_range_scale: 1, |
929 | 0 | use_tx_domain_distortion, |
930 | 0 | use_tx_domain_rate, |
931 | 0 | idx_in_group_output: 0, |
932 | 0 | pyramid_level: 0, |
933 | 0 | enable_early_exit: true, |
934 | 0 | tx_mode_select: false, |
935 | 0 | default_filter: FilterMode::REGULAR, |
936 | 0 | cpu_feature_level: Default::default(), |
937 | 0 | enable_segmentation: config.speed_settings.segmentation |
938 | 0 | != SegmentationLevel::Disabled, |
939 | 0 | enable_inter_txfm_split: config |
940 | 0 | .speed_settings |
941 | 0 | .transform |
942 | 0 | .enable_inter_tx_split, |
943 | 0 | t35_metadata: Box::new([]), |
944 | 0 | sequence, |
945 | 0 | config, |
946 | 0 | coded_frame_data: None, |
947 | 0 | } |
948 | 0 | } Unexecuted instantiation: <rav1e::encoder::FrameInvariants<u16>>::new Unexecuted instantiation: <rav1e::encoder::FrameInvariants<u8>>::new |
949 | | |
950 | 0 | pub fn new_key_frame( |
951 | 0 | config: Arc<EncoderConfig>, sequence: Arc<Sequence>, |
952 | 0 | gop_input_frameno_start: u64, t35_metadata: Box<[T35]>, |
953 | 0 | ) -> Self { |
954 | 0 | let tx_mode_select = config.speed_settings.transform.rdo_tx_decision; |
955 | 0 | let mut fi = Self::new(config, sequence); |
956 | 0 | fi.input_frameno = gop_input_frameno_start; |
957 | 0 | fi.tx_mode_select = tx_mode_select; |
958 | 0 | fi.coded_frame_data = Some(CodedFrameData::new(&fi)); |
959 | 0 | fi.t35_metadata = t35_metadata; |
960 | 0 | fi |
961 | 0 | } Unexecuted instantiation: <rav1e::encoder::FrameInvariants<u16>>::new_key_frame Unexecuted instantiation: <rav1e::encoder::FrameInvariants<u8>>::new_key_frame |
962 | | |
963 | | /// Returns the created `FrameInvariants`, or `None` if this should be |
964 | | /// a placeholder frame. |
965 | 0 | pub(crate) fn new_inter_frame( |
966 | 0 | previous_coded_fi: &Self, inter_cfg: &InterConfig, |
967 | 0 | gop_input_frameno_start: u64, output_frameno_in_gop: u64, |
968 | 0 | next_keyframe_input_frameno: u64, error_resilient: bool, |
969 | 0 | t35_metadata: Box<[T35]>, |
970 | 0 | ) -> Option<Self> { |
971 | 0 | let input_frameno = inter_cfg |
972 | 0 | .get_input_frameno(output_frameno_in_gop, gop_input_frameno_start); |
973 | 0 | if input_frameno >= next_keyframe_input_frameno { |
974 | | // This is an invalid frame. We set it as a placeholder in the FI list. |
975 | 0 | return None; |
976 | 0 | } |
977 | 0 |
|
978 | 0 | // We have this special thin clone method to avoid cloning the |
979 | 0 | // quite large lookahead data for SEFs, when it is not needed. |
980 | 0 | let mut fi = previous_coded_fi.clone_without_coded_data(); |
981 | 0 | fi.intra_only = false; |
982 | 0 | fi.force_integer_mv = 0; // note: should be 1 if fi.intra_only is true |
983 | 0 | fi.idx_in_group_output = |
984 | 0 | inter_cfg.get_idx_in_group_output(output_frameno_in_gop); |
985 | 0 | fi.tx_mode_select = fi.enable_inter_txfm_split; |
986 | 0 |
|
987 | 0 | let show_existing_frame = |
988 | 0 | inter_cfg.get_show_existing_frame(fi.idx_in_group_output); |
989 | 0 | if !show_existing_frame { |
990 | 0 | fi.coded_frame_data = previous_coded_fi.coded_frame_data.clone(); |
991 | 0 | } |
992 | | |
993 | 0 | fi.order_hint = |
994 | 0 | inter_cfg.get_order_hint(output_frameno_in_gop, fi.idx_in_group_output); |
995 | 0 |
|
996 | 0 | fi.pyramid_level = inter_cfg.get_level(fi.idx_in_group_output); |
997 | 0 |
|
998 | 0 | fi.frame_type = if (inter_cfg.switch_frame_interval > 0) |
999 | 0 | && (output_frameno_in_gop % inter_cfg.switch_frame_interval == 0) |
1000 | 0 | && (fi.pyramid_level == 0) |
1001 | | { |
1002 | 0 | FrameType::SWITCH |
1003 | | } else { |
1004 | 0 | FrameType::INTER |
1005 | | }; |
1006 | | fi.error_resilient = |
1007 | 0 | if fi.frame_type == FrameType::SWITCH { true } else { error_resilient }; |
1008 | | |
1009 | 0 | fi.frame_size_override_flag = if fi.frame_type == FrameType::SWITCH { |
1010 | 0 | true |
1011 | 0 | } else if fi.sequence.reduced_still_picture_hdr { |
1012 | 0 | false |
1013 | 0 | } else if fi.frame_type == FrameType::INTER |
1014 | 0 | && !fi.error_resilient |
1015 | 0 | && fi.render_and_frame_size_different |
1016 | | { |
1017 | | // force frame_size_with_refs() code path if render size != frame size |
1018 | 0 | true |
1019 | | } else { |
1020 | 0 | fi.width as u32 != fi.sequence.max_frame_width |
1021 | 0 | || fi.height as u32 != fi.sequence.max_frame_height |
1022 | | }; |
1023 | | |
1024 | | // this is the slot that the current frame is going to be saved into |
1025 | 0 | let slot_idx = inter_cfg.get_slot_idx(fi.pyramid_level, fi.order_hint); |
1026 | 0 | fi.show_frame = inter_cfg.get_show_frame(fi.idx_in_group_output); |
1027 | 0 | fi.t35_metadata = if fi.show_frame { t35_metadata } else { Box::new([]) }; |
1028 | 0 | fi.frame_to_show_map_idx = slot_idx; |
1029 | 0 | fi.refresh_frame_flags = if fi.frame_type == FrameType::SWITCH { |
1030 | 0 | ALL_REF_FRAMES_MASK |
1031 | 0 | } else if fi.is_show_existing_frame() { |
1032 | 0 | 0 |
1033 | | } else { |
1034 | 0 | 1 << slot_idx |
1035 | | }; |
1036 | | |
1037 | 0 | let second_ref_frame = |
1038 | 0 | if fi.idx_in_group_output == 0 { LAST2_FRAME } else { ALTREF_FRAME }; |
1039 | 0 | let ref_in_previous_group = LAST3_FRAME; |
1040 | 0 |
|
1041 | 0 | // reuse probability estimates from previous frames only in top level frames |
1042 | 0 | fi.primary_ref_frame = if fi.error_resilient || (fi.pyramid_level > 2) { |
1043 | 0 | PRIMARY_REF_NONE |
1044 | | } else { |
1045 | 0 | (ref_in_previous_group.to_index()) as u32 |
1046 | | }; |
1047 | | |
1048 | 0 | if fi.pyramid_level == 0 { |
1049 | | // level 0 has no forward references |
1050 | | // default to last P frame |
1051 | 0 | fi.ref_frames = [ |
1052 | 0 | // calculations done relative to the slot_idx for this frame. |
1053 | 0 | // the last four frames can be found by subtracting from the current slot_idx |
1054 | 0 | // add 4 to prevent underflow |
1055 | 0 | // TODO: maybe use order_hint here like in get_slot_idx? |
1056 | 0 | // this is the previous P frame |
1057 | 0 | (slot_idx + 4 - 1) as u8 % 4 |
1058 | 0 | ; INTER_REFS_PER_FRAME]; |
1059 | 0 | if inter_cfg.multiref { |
1060 | 0 | // use the second-previous p frame as a second reference frame |
1061 | 0 | fi.ref_frames[second_ref_frame.to_index()] = |
1062 | 0 | (slot_idx + 4 - 2) as u8 % 4; |
1063 | 0 | } |
1064 | | } else { |
1065 | 0 | debug_assert!(inter_cfg.multiref); |
1066 | | |
1067 | | // fill in defaults |
1068 | | // default to backwards reference in lower level |
1069 | | fi.ref_frames = [{ |
1070 | 0 | let oh = fi.order_hint |
1071 | 0 | - (inter_cfg.group_input_len as u32 >> fi.pyramid_level); |
1072 | 0 | let lvl1 = pos_to_lvl(oh as u64, inter_cfg.pyramid_depth); |
1073 | 0 | if lvl1 == 0 { |
1074 | 0 | ((oh >> inter_cfg.pyramid_depth) % 4) as u8 |
1075 | | } else { |
1076 | 0 | 3 + lvl1 as u8 |
1077 | | } |
1078 | | }; INTER_REFS_PER_FRAME]; |
1079 | | // use forward reference in lower level as a second reference frame |
1080 | 0 | fi.ref_frames[second_ref_frame.to_index()] = { |
1081 | 0 | let oh = fi.order_hint |
1082 | 0 | + (inter_cfg.group_input_len as u32 >> fi.pyramid_level); |
1083 | 0 | let lvl2 = pos_to_lvl(oh as u64, inter_cfg.pyramid_depth); |
1084 | 0 | if lvl2 == 0 { |
1085 | 0 | ((oh >> inter_cfg.pyramid_depth) % 4) as u8 |
1086 | | } else { |
1087 | 0 | 3 + lvl2 as u8 |
1088 | | } |
1089 | | }; |
1090 | | // use a reference to the previous frame in the same level |
1091 | | // (horizontally) as a third reference |
1092 | 0 | fi.ref_frames[ref_in_previous_group.to_index()] = slot_idx as u8; |
1093 | | } |
1094 | | |
1095 | 0 | fi.set_ref_frame_sign_bias(); |
1096 | 0 |
|
1097 | 0 | fi.reference_mode = if inter_cfg.multiref && fi.idx_in_group_output != 0 { |
1098 | 0 | ReferenceMode::SELECT |
1099 | | } else { |
1100 | 0 | ReferenceMode::SINGLE |
1101 | | }; |
1102 | 0 | fi.input_frameno = input_frameno; |
1103 | 0 | fi.me_range_scale = (inter_cfg.group_input_len >> fi.pyramid_level) as u8; |
1104 | 0 |
|
1105 | 0 | if fi.show_frame || fi.showable_frame { |
1106 | 0 | let cur_frame_time = fi.frame_timestamp(); |
1107 | | // Increment the film grain seed for the next frame |
1108 | 0 | if let Some(params) = |
1109 | 0 | Arc::make_mut(&mut fi.config).get_film_grain_mut_at(cur_frame_time) |
1110 | | { |
1111 | 0 | params.random_seed = params.random_seed.wrapping_add(3248); |
1112 | 0 | if params.random_seed == 0 { |
1113 | 0 | params.random_seed = DEFAULT_GRAIN_SEED; |
1114 | 0 | } |
1115 | 0 | } |
1116 | 0 | } |
1117 | | |
1118 | 0 | Some(fi) |
1119 | 0 | } Unexecuted instantiation: <rav1e::encoder::FrameInvariants<u16>>::new_inter_frame Unexecuted instantiation: <rav1e::encoder::FrameInvariants<u8>>::new_inter_frame |
1120 | | |
1121 | 0 | pub fn is_show_existing_frame(&self) -> bool { |
1122 | 0 | self.coded_frame_data.is_none() |
1123 | 0 | } Unexecuted instantiation: <rav1e::encoder::FrameInvariants<u16>>::is_show_existing_frame Unexecuted instantiation: <rav1e::encoder::FrameInvariants<u8>>::is_show_existing_frame |
1124 | | |
1125 | 0 | pub fn clone_without_coded_data(&self) -> Self { |
1126 | 0 | Self { |
1127 | 0 | coded_frame_data: None, |
1128 | 0 |
|
1129 | 0 | sequence: self.sequence.clone(), |
1130 | 0 | config: self.config.clone(), |
1131 | 0 | width: self.width, |
1132 | 0 | height: self.height, |
1133 | 0 | render_width: self.render_width, |
1134 | 0 | render_height: self.render_height, |
1135 | 0 | frame_size_override_flag: self.frame_size_override_flag, |
1136 | 0 | render_and_frame_size_different: self.render_and_frame_size_different, |
1137 | 0 | sb_width: self.sb_width, |
1138 | 0 | sb_height: self.sb_height, |
1139 | 0 | w_in_b: self.w_in_b, |
1140 | 0 | h_in_b: self.h_in_b, |
1141 | 0 | input_frameno: self.input_frameno, |
1142 | 0 | order_hint: self.order_hint, |
1143 | 0 | show_frame: self.show_frame, |
1144 | 0 | showable_frame: self.showable_frame, |
1145 | 0 | error_resilient: self.error_resilient, |
1146 | 0 | intra_only: self.intra_only, |
1147 | 0 | allow_high_precision_mv: self.allow_high_precision_mv, |
1148 | 0 | frame_type: self.frame_type, |
1149 | 0 | frame_to_show_map_idx: self.frame_to_show_map_idx, |
1150 | 0 | use_reduced_tx_set: self.use_reduced_tx_set, |
1151 | 0 | reference_mode: self.reference_mode, |
1152 | 0 | use_prev_frame_mvs: self.use_prev_frame_mvs, |
1153 | 0 | partition_range: self.partition_range, |
1154 | 0 | globalmv_transformation_type: self.globalmv_transformation_type, |
1155 | 0 | num_tg: self.num_tg, |
1156 | 0 | large_scale_tile: self.large_scale_tile, |
1157 | 0 | disable_cdf_update: self.disable_cdf_update, |
1158 | 0 | allow_screen_content_tools: self.allow_screen_content_tools, |
1159 | 0 | force_integer_mv: self.force_integer_mv, |
1160 | 0 | primary_ref_frame: self.primary_ref_frame, |
1161 | 0 | refresh_frame_flags: self.refresh_frame_flags, |
1162 | 0 | allow_intrabc: self.allow_intrabc, |
1163 | 0 | use_ref_frame_mvs: self.use_ref_frame_mvs, |
1164 | 0 | is_filter_switchable: self.is_filter_switchable, |
1165 | 0 | is_motion_mode_switchable: self.is_motion_mode_switchable, |
1166 | 0 | disable_frame_end_update_cdf: self.disable_frame_end_update_cdf, |
1167 | 0 | allow_warped_motion: self.allow_warped_motion, |
1168 | 0 | cdef_search_method: self.cdef_search_method, |
1169 | 0 | cdef_damping: self.cdef_damping, |
1170 | 0 | cdef_bits: self.cdef_bits, |
1171 | 0 | cdef_y_strengths: self.cdef_y_strengths, |
1172 | 0 | cdef_uv_strengths: self.cdef_uv_strengths, |
1173 | 0 | delta_q_present: self.delta_q_present, |
1174 | 0 | ref_frames: self.ref_frames, |
1175 | 0 | ref_frame_sign_bias: self.ref_frame_sign_bias, |
1176 | 0 | rec_buffer: self.rec_buffer.clone(), |
1177 | 0 | base_q_idx: self.base_q_idx, |
1178 | 0 | dc_delta_q: self.dc_delta_q, |
1179 | 0 | ac_delta_q: self.ac_delta_q, |
1180 | 0 | lambda: self.lambda, |
1181 | 0 | me_lambda: self.me_lambda, |
1182 | 0 | dist_scale: self.dist_scale, |
1183 | 0 | me_range_scale: self.me_range_scale, |
1184 | 0 | use_tx_domain_distortion: self.use_tx_domain_distortion, |
1185 | 0 | use_tx_domain_rate: self.use_tx_domain_rate, |
1186 | 0 | idx_in_group_output: self.idx_in_group_output, |
1187 | 0 | pyramid_level: self.pyramid_level, |
1188 | 0 | enable_early_exit: self.enable_early_exit, |
1189 | 0 | tx_mode_select: self.tx_mode_select, |
1190 | 0 | enable_inter_txfm_split: self.enable_inter_txfm_split, |
1191 | 0 | default_filter: self.default_filter, |
1192 | 0 | enable_segmentation: self.enable_segmentation, |
1193 | 0 | t35_metadata: self.t35_metadata.clone(), |
1194 | 0 | cpu_feature_level: self.cpu_feature_level, |
1195 | 0 | } |
1196 | 0 | } Unexecuted instantiation: <rav1e::encoder::FrameInvariants<u16>>::clone_without_coded_data Unexecuted instantiation: <rav1e::encoder::FrameInvariants<u8>>::clone_without_coded_data |
1197 | | |
1198 | 0 | pub fn set_ref_frame_sign_bias(&mut self) { |
1199 | 0 | for i in 0..INTER_REFS_PER_FRAME { |
1200 | 0 | self.ref_frame_sign_bias[i] = if !self.sequence.enable_order_hint { |
1201 | 0 | false |
1202 | 0 | } else if let Some(ref rec) = |
1203 | 0 | self.rec_buffer.frames[self.ref_frames[i] as usize] |
1204 | | { |
1205 | 0 | let hint = rec.order_hint; |
1206 | 0 | self.sequence.get_relative_dist(hint, self.order_hint) > 0 |
1207 | | } else { |
1208 | 0 | false |
1209 | | }; |
1210 | | } |
1211 | 0 | } Unexecuted instantiation: <rav1e::encoder::FrameInvariants<u16>>::set_ref_frame_sign_bias Unexecuted instantiation: <rav1e::encoder::FrameInvariants<u8>>::set_ref_frame_sign_bias |
1212 | | |
1213 | 0 | pub fn get_frame_subtype(&self) -> usize { |
1214 | 0 | if self.frame_type == FrameType::KEY { |
1215 | 0 | FRAME_SUBTYPE_I |
1216 | | } else { |
1217 | 0 | FRAME_SUBTYPE_P + (self.pyramid_level as usize) |
1218 | | } |
1219 | 0 | } Unexecuted instantiation: <rav1e::encoder::FrameInvariants<u16>>::get_frame_subtype Unexecuted instantiation: <rav1e::encoder::FrameInvariants<u8>>::get_frame_subtype |
1220 | | |
1221 | 0 | fn pick_strength_from_q(&mut self, qps: &QuantizerParameters) { |
1222 | 0 | self.cdef_damping = 3 + (self.base_q_idx >> 6); |
1223 | 0 | let q = bexp64(qps.log_target_q + q57(QSCALE)) as f32; |
1224 | | /* These coefficients were trained on libaom. */ |
1225 | 0 | let (y_f1, y_f2, uv_f1, uv_f2) = if !self.intra_only { |
1226 | 0 | ( |
1227 | 0 | poly2(q, -0.0000023593946_f32, 0.0068615186_f32, 0.02709886_f32, 15), |
1228 | 0 | poly2(q, -0.00000057629734_f32, 0.0013993345_f32, 0.03831067_f32, 3), |
1229 | 0 | poly2(q, -0.0000007095069_f32, 0.0034628846_f32, 0.00887099_f32, 15), |
1230 | 0 | poly2(q, 0.00000023874085_f32, 0.00028223585_f32, 0.05576307_f32, 3), |
1231 | 0 | ) |
1232 | | } else { |
1233 | 0 | ( |
1234 | 0 | poly2(q, 0.0000033731974_f32, 0.008070594_f32, 0.0187634_f32, 15), |
1235 | 0 | poly2(q, 0.0000029167343_f32, 0.0027798624_f32, 0.0079405_f32, 3), |
1236 | 0 | poly2(q, -0.0000130790995_f32, 0.012892405_f32, -0.00748388_f32, 15), |
1237 | 0 | poly2(q, 0.0000032651783_f32, 0.00035520183_f32, 0.00228092_f32, 3), |
1238 | 0 | ) |
1239 | | }; |
1240 | 0 | self.cdef_y_strengths[0] = (y_f1 * CDEF_SEC_STRENGTHS as i32 + y_f2) as u8; |
1241 | 0 | self.cdef_uv_strengths[0] = |
1242 | 0 | (uv_f1 * CDEF_SEC_STRENGTHS as i32 + uv_f2) as u8; |
1243 | 0 | } Unexecuted instantiation: <rav1e::encoder::FrameInvariants<u16>>::pick_strength_from_q Unexecuted instantiation: <rav1e::encoder::FrameInvariants<u8>>::pick_strength_from_q |
1244 | | |
1245 | 0 | pub fn set_quantizers(&mut self, qps: &QuantizerParameters) { |
1246 | 0 | self.base_q_idx = qps.ac_qi[0]; |
1247 | 0 | let base_q_idx = self.base_q_idx as i32; |
1248 | 0 | for pi in 0..3 { |
1249 | 0 | self.dc_delta_q[pi] = (qps.dc_qi[pi] as i32 - base_q_idx) as i8; |
1250 | 0 | self.ac_delta_q[pi] = (qps.ac_qi[pi] as i32 - base_q_idx) as i8; |
1251 | 0 | } |
1252 | 0 | self.lambda = |
1253 | 0 | qps.lambda * ((1 << (2 * (self.sequence.bit_depth - 8))) as f64); |
1254 | 0 | self.me_lambda = self.lambda.sqrt(); |
1255 | 0 | self.dist_scale = qps.dist_scale.map(DistortionScale::from); |
1256 | 0 |
|
1257 | 0 | match self.cdef_search_method { |
1258 | 0 | CDEFSearchMethod::PickFromQ => { |
1259 | 0 | self.pick_strength_from_q(qps); |
1260 | 0 | } |
1261 | | // TODO: implement FastSearch and FullSearch |
1262 | 0 | _ => unreachable!(), |
1263 | | } |
1264 | 0 | } Unexecuted instantiation: <rav1e::encoder::FrameInvariants<u16>>::set_quantizers Unexecuted instantiation: <rav1e::encoder::FrameInvariants<u8>>::set_quantizers |
1265 | | |
1266 | | #[inline(always)] |
1267 | 0 | pub fn sb_size_log2(&self) -> usize { |
1268 | 0 | self.sequence.tiling.sb_size_log2 |
1269 | 0 | } Unexecuted instantiation: <rav1e::encoder::FrameInvariants<u16>>::sb_size_log2 Unexecuted instantiation: <rav1e::encoder::FrameInvariants<u8>>::sb_size_log2 |
1270 | | |
1271 | 0 | pub fn film_grain_params(&self) -> Option<&GrainTableSegment> { |
1272 | 0 | if !(self.show_frame || self.showable_frame) { |
1273 | 0 | return None; |
1274 | 0 | } |
1275 | 0 | let cur_frame_time = self.frame_timestamp(); |
1276 | 0 | self.config.get_film_grain_at(cur_frame_time) |
1277 | 0 | } Unexecuted instantiation: <rav1e::encoder::FrameInvariants<u16>>::film_grain_params Unexecuted instantiation: <rav1e::encoder::FrameInvariants<u8>>::film_grain_params |
1278 | | |
1279 | 0 | pub fn frame_timestamp(&self) -> u64 { |
1280 | | // I don't know why this is the base unit for a timestamp but it is. 1/10000000 of a second. |
1281 | | const TIMESTAMP_BASE_UNIT: u64 = 10_000_000; |
1282 | | |
1283 | 0 | self.input_frameno * TIMESTAMP_BASE_UNIT * self.sequence.time_base.num |
1284 | 0 | / self.sequence.time_base.den |
1285 | 0 | } Unexecuted instantiation: <rav1e::encoder::FrameInvariants<u16>>::frame_timestamp Unexecuted instantiation: <rav1e::encoder::FrameInvariants<u8>>::frame_timestamp |
1286 | | } |
1287 | | |
1288 | | impl<T: Pixel> fmt::Display for FrameInvariants<T> { |
1289 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
1290 | 0 | write!(f, "Input Frame {} - {}", self.input_frameno, self.frame_type) |
1291 | 0 | } |
1292 | | } |
1293 | | |
1294 | | /// # Errors |
1295 | | /// |
1296 | | /// - If the frame packet cannot be written to |
1297 | 0 | pub fn write_temporal_delimiter(packet: &mut dyn io::Write) -> io::Result<()> { |
1298 | 0 | packet.write_all(&TEMPORAL_DELIMITER)?; |
1299 | 0 | Ok(()) |
1300 | 0 | } |
1301 | | |
1302 | 0 | fn write_key_frame_obus<T: Pixel>( |
1303 | 0 | packet: &mut dyn io::Write, fi: &FrameInvariants<T>, obu_extension: u32, |
1304 | 0 | ) -> io::Result<()> { |
1305 | 0 | let mut buf1 = Vec::new(); |
1306 | 0 | let mut buf2 = Vec::new(); |
1307 | 0 | { |
1308 | 0 | let mut bw2 = BitWriter::endian(&mut buf2, BigEndian); |
1309 | 0 | bw2.write_sequence_header_obu(fi)?; |
1310 | 0 | bw2.write_bit(true)?; // trailing bit |
1311 | 0 | bw2.byte_align()?; |
1312 | | } |
1313 | | |
1314 | | { |
1315 | 0 | let mut bw1 = BitWriter::endian(&mut buf1, BigEndian); |
1316 | 0 | bw1.write_obu_header(ObuType::OBU_SEQUENCE_HEADER, obu_extension)?; |
1317 | | } |
1318 | 0 | packet.write_all(&buf1).unwrap(); |
1319 | 0 | buf1.clear(); |
1320 | 0 |
|
1321 | 0 | { |
1322 | 0 | let mut bw1 = BitWriter::endian(&mut buf1, BigEndian); |
1323 | 0 | bw1.write_uleb128(buf2.len() as u64)?; |
1324 | | } |
1325 | | |
1326 | 0 | packet.write_all(&buf1).unwrap(); |
1327 | 0 | buf1.clear(); |
1328 | 0 |
|
1329 | 0 | packet.write_all(&buf2).unwrap(); |
1330 | 0 | buf2.clear(); |
1331 | 0 |
|
1332 | 0 | if fi.sequence.content_light.is_some() { |
1333 | 0 | let mut bw1 = BitWriter::endian(&mut buf1, BigEndian); |
1334 | 0 | bw1.write_sequence_metadata_obu( |
1335 | 0 | ObuMetaType::OBU_META_HDR_CLL, |
1336 | 0 | &fi.sequence, |
1337 | 0 | )?; |
1338 | 0 | packet.write_all(&buf1).unwrap(); |
1339 | 0 | buf1.clear(); |
1340 | 0 | } |
1341 | | |
1342 | 0 | if fi.sequence.mastering_display.is_some() { |
1343 | 0 | let mut bw1 = BitWriter::endian(&mut buf1, BigEndian); |
1344 | 0 | bw1.write_sequence_metadata_obu( |
1345 | 0 | ObuMetaType::OBU_META_HDR_MDCV, |
1346 | 0 | &fi.sequence, |
1347 | 0 | )?; |
1348 | 0 | packet.write_all(&buf1).unwrap(); |
1349 | 0 | buf1.clear(); |
1350 | 0 | } |
1351 | | |
1352 | 0 | Ok(()) |
1353 | 0 | } Unexecuted instantiation: rav1e::encoder::write_key_frame_obus::<u16> Unexecuted instantiation: rav1e::encoder::write_key_frame_obus::<u8> |
1354 | | |
1355 | | /// Write into `dst` the difference between the blocks at `src1` and `src2` |
1356 | 0 | fn diff<T: Pixel>( |
1357 | 0 | dst: &mut [MaybeUninit<i16>], src1: &PlaneRegion<'_, T>, |
1358 | 0 | src2: &PlaneRegion<'_, T>, |
1359 | 0 | ) { |
1360 | 0 | debug_assert!(dst.len() % src1.rect().width == 0); |
1361 | 0 | debug_assert_eq!(src1.rows_iter().count(), src1.rect().height); |
1362 | | |
1363 | 0 | let width = src1.rect().width; |
1364 | 0 | let height = src1.rect().height; |
1365 | 0 |
|
1366 | 0 | if width == 0 |
1367 | 0 | || width != src2.rect().width |
1368 | 0 | || height == 0 |
1369 | 0 | || src1.rows_iter().len() != src2.rows_iter().len() |
1370 | | { |
1371 | 0 | debug_assert!(false); |
1372 | 0 | return; |
1373 | 0 | } |
1374 | | |
1375 | 0 | for ((l, s1), s2) in |
1376 | 0 | dst.chunks_exact_mut(width).zip(src1.rows_iter()).zip(src2.rows_iter()) |
1377 | | { |
1378 | 0 | for ((r, v1), v2) in l.iter_mut().zip(s1).zip(s2) { |
1379 | 0 | r.write(i16::cast_from(*v1) - i16::cast_from(*v2)); |
1380 | 0 | } |
1381 | | } |
1382 | 0 | } Unexecuted instantiation: rav1e::encoder::diff::<u16> Unexecuted instantiation: rav1e::encoder::diff::<u8> |
1383 | | |
1384 | 0 | fn get_qidx<T: Pixel>( |
1385 | 0 | fi: &FrameInvariants<T>, ts: &TileStateMut<'_, T>, cw: &ContextWriter, |
1386 | 0 | tile_bo: TileBlockOffset, |
1387 | 0 | ) -> u8 { |
1388 | 0 | let mut qidx = fi.base_q_idx; |
1389 | 0 | let sidx = cw.bc.blocks[tile_bo].segmentation_idx as usize; |
1390 | 0 | if ts.segmentation.features[sidx][SegLvl::SEG_LVL_ALT_Q as usize] { |
1391 | 0 | let delta = ts.segmentation.data[sidx][SegLvl::SEG_LVL_ALT_Q as usize]; |
1392 | 0 | qidx = clamp((qidx as i16) + delta, 0, 255) as u8; |
1393 | 0 | } |
1394 | 0 | qidx |
1395 | 0 | } Unexecuted instantiation: rav1e::encoder::get_qidx::<u16> Unexecuted instantiation: rav1e::encoder::get_qidx::<u8> |
1396 | | |
1397 | | /// For a transform block, |
1398 | | /// predict, transform, quantize, write coefficients to a bitstream, |
1399 | | /// dequantize, inverse-transform. |
1400 | | /// |
1401 | | /// # Panics |
1402 | | /// |
1403 | | /// - If the block size is invalid for subsampling |
1404 | | /// - If a tx type other than DCT is used for 64x64 blocks |
1405 | 0 | pub fn encode_tx_block<T: Pixel, W: Writer>( |
1406 | 0 | fi: &FrameInvariants<T>, |
1407 | 0 | ts: &mut TileStateMut<'_, T>, |
1408 | 0 | cw: &mut ContextWriter, |
1409 | 0 | w: &mut W, |
1410 | 0 | p: usize, |
1411 | 0 | // Offset in the luma plane of the partition enclosing this block. |
1412 | 0 | tile_partition_bo: TileBlockOffset, |
1413 | 0 | // tx block position within a partition, unit: tx block number |
1414 | 0 | bx: usize, |
1415 | 0 | by: usize, |
1416 | 0 | // Offset in the luma plane where this tx block is colocated. Note that for |
1417 | 0 | // a chroma block, this offset might be outside of the current partition. |
1418 | 0 | // For example in 4:2:0, four 4x4 luma partitions share one 4x4 chroma block, |
1419 | 0 | // this block is part of the last 4x4 partition, but its `tx_bo` offset |
1420 | 0 | // matches the offset of the first 4x4 partition. |
1421 | 0 | tx_bo: TileBlockOffset, |
1422 | 0 | mode: PredictionMode, |
1423 | 0 | tx_size: TxSize, |
1424 | 0 | tx_type: TxType, |
1425 | 0 | bsize: BlockSize, |
1426 | 0 | po: PlaneOffset, |
1427 | 0 | skip: bool, |
1428 | 0 | qidx: u8, |
1429 | 0 | ac: &[i16], |
1430 | 0 | pred_intra_param: IntraParam, |
1431 | 0 | rdo_type: RDOType, |
1432 | 0 | need_recon_pixel: bool, |
1433 | 0 | ) -> (bool, ScaledDistortion) { |
1434 | 0 | let PlaneConfig { xdec, ydec, .. } = ts.input.planes[p].cfg; |
1435 | 0 | let tile_rect = ts.tile_rect().decimated(xdec, ydec); |
1436 | 0 | let area = Area::BlockRect { |
1437 | 0 | bo: tx_bo.0, |
1438 | 0 | width: tx_size.width(), |
1439 | 0 | height: tx_size.height(), |
1440 | 0 | }; |
1441 | 0 |
|
1442 | 0 | if tx_bo.0.x >= ts.mi_width || tx_bo.0.y >= ts.mi_height { |
1443 | 0 | return (false, ScaledDistortion::zero()); |
1444 | 0 | } |
1445 | 0 |
|
1446 | 0 | debug_assert!(tx_bo.0.x < ts.mi_width); |
1447 | 0 | debug_assert!(tx_bo.0.y < ts.mi_height); |
1448 | | |
1449 | 0 | debug_assert!( |
1450 | 0 | tx_size.sqr() <= TxSize::TX_32X32 || tx_type == TxType::DCT_DCT |
1451 | | ); |
1452 | | |
1453 | 0 | let plane_bsize = bsize.subsampled_size(xdec, ydec).unwrap(); |
1454 | 0 |
|
1455 | 0 | debug_assert!(p != 0 || !mode.is_intra() || tx_size.block_size() == plane_bsize || need_recon_pixel, |
1456 | 0 | "mode.is_intra()={:#?}, plane={:#?}, tx_size.block_size()={:#?}, plane_bsize={:#?}, need_recon_pixel={:#?}", |
1457 | 0 | mode.is_intra(), p, tx_size.block_size(), plane_bsize, need_recon_pixel); |
1458 | | |
1459 | 0 | let ief_params = if mode.is_directional() |
1460 | 0 | && fi.sequence.enable_intra_edge_filter |
1461 | | { |
1462 | 0 | let (plane_xdec, plane_ydec) = if p == 0 { (0, 0) } else { (xdec, ydec) }; |
1463 | 0 | let above_block_info = |
1464 | 0 | ts.above_block_info(tile_partition_bo, plane_xdec, plane_ydec); |
1465 | 0 | let left_block_info = |
1466 | 0 | ts.left_block_info(tile_partition_bo, plane_xdec, plane_ydec); |
1467 | 0 | Some(IntraEdgeFilterParameters::new(p, above_block_info, left_block_info)) |
1468 | | } else { |
1469 | 0 | None |
1470 | | }; |
1471 | | |
1472 | 0 | let frame_bo = ts.to_frame_block_offset(tx_bo); |
1473 | 0 | let rec = &mut ts.rec.planes[p]; |
1474 | 0 |
|
1475 | 0 | if mode.is_intra() { |
1476 | 0 | let bit_depth = fi.sequence.bit_depth; |
1477 | 0 | let mut edge_buf = Aligned::uninit_array(); |
1478 | 0 | let edge_buf = get_intra_edges( |
1479 | 0 | &mut edge_buf, |
1480 | 0 | &rec.as_const(), |
1481 | 0 | tile_partition_bo, |
1482 | 0 | bx, |
1483 | 0 | by, |
1484 | 0 | bsize, |
1485 | 0 | po, |
1486 | 0 | tx_size, |
1487 | 0 | bit_depth, |
1488 | 0 | Some(mode), |
1489 | 0 | fi.sequence.enable_intra_edge_filter, |
1490 | 0 | pred_intra_param, |
1491 | 0 | ); |
1492 | 0 |
|
1493 | 0 | mode.predict_intra( |
1494 | 0 | tile_rect, |
1495 | 0 | &mut rec.subregion_mut(area), |
1496 | 0 | tx_size, |
1497 | 0 | bit_depth, |
1498 | 0 | ac, |
1499 | 0 | pred_intra_param, |
1500 | 0 | ief_params, |
1501 | 0 | &edge_buf, |
1502 | 0 | fi.cpu_feature_level, |
1503 | 0 | ); |
1504 | 0 | } |
1505 | | |
1506 | 0 | if skip { |
1507 | 0 | return (false, ScaledDistortion::zero()); |
1508 | 0 | } |
1509 | 0 |
|
1510 | 0 | let coded_tx_area = av1_get_coded_tx_size(tx_size).area(); |
1511 | 0 | let mut residual = Aligned::<[MaybeUninit<i16>; 64 * 64]>::uninit_array(); |
1512 | 0 | let mut coeffs = Aligned::<[MaybeUninit<T::Coeff>; 64 * 64]>::uninit_array(); |
1513 | 0 | let mut qcoeffs = |
1514 | 0 | Aligned::<[MaybeUninit<T::Coeff>; 32 * 32]>::uninit_array(); |
1515 | 0 | let mut rcoeffs = |
1516 | 0 | Aligned::<[MaybeUninit<T::Coeff>; 32 * 32]>::uninit_array(); |
1517 | 0 | let residual = &mut residual.data[..tx_size.area()]; |
1518 | 0 | let coeffs = &mut coeffs.data[..tx_size.area()]; |
1519 | 0 | let qcoeffs = init_slice_repeat_mut( |
1520 | 0 | &mut qcoeffs.data[..coded_tx_area], |
1521 | 0 | T::Coeff::cast_from(0), |
1522 | 0 | ); |
1523 | 0 | let rcoeffs = &mut rcoeffs.data[..coded_tx_area]; |
1524 | 0 |
|
1525 | 0 | let (visible_tx_w, visible_tx_h) = clip_visible_bsize( |
1526 | 0 | (fi.width + xdec) >> xdec, |
1527 | 0 | (fi.height + ydec) >> ydec, |
1528 | 0 | tx_size.block_size(), |
1529 | 0 | (frame_bo.0.x << MI_SIZE_LOG2) >> xdec, |
1530 | 0 | (frame_bo.0.y << MI_SIZE_LOG2) >> ydec, |
1531 | 0 | ); |
1532 | 0 |
|
1533 | 0 | if visible_tx_w != 0 && visible_tx_h != 0 { |
1534 | 0 | diff( |
1535 | 0 | residual, |
1536 | 0 | &ts.input_tile.planes[p].subregion(area), |
1537 | 0 | &rec.subregion(area), |
1538 | 0 | ); |
1539 | 0 | } else { |
1540 | 0 | residual.fill(MaybeUninit::new(0)); |
1541 | 0 | } |
1542 | | // SAFETY: `diff()` inits `tx_size.area()` elements when it matches size of `subregion(area)` |
1543 | 0 | let residual = unsafe { slice_assume_init_mut(residual) }; |
1544 | 0 |
|
1545 | 0 | forward_transform( |
1546 | 0 | residual, |
1547 | 0 | coeffs, |
1548 | 0 | tx_size.width(), |
1549 | 0 | tx_size, |
1550 | 0 | tx_type, |
1551 | 0 | fi.sequence.bit_depth, |
1552 | 0 | fi.cpu_feature_level, |
1553 | 0 | ); |
1554 | 0 | // SAFETY: forward_transform initialized coeffs |
1555 | 0 | let coeffs = unsafe { slice_assume_init_mut(coeffs) }; |
1556 | 0 |
|
1557 | 0 | let eob = ts.qc.quantize(coeffs, qcoeffs, tx_size, tx_type); |
1558 | | |
1559 | 0 | let has_coeff = if need_recon_pixel || rdo_type.needs_coeff_rate() { |
1560 | 0 | debug_assert!((((fi.w_in_b - frame_bo.0.x) << MI_SIZE_LOG2) >> xdec) >= 4); |
1561 | 0 | debug_assert!((((fi.h_in_b - frame_bo.0.y) << MI_SIZE_LOG2) >> ydec) >= 4); |
1562 | 0 | let frame_clipped_txw: usize = |
1563 | 0 | (((fi.w_in_b - frame_bo.0.x) << MI_SIZE_LOG2) >> xdec) |
1564 | 0 | .min(tx_size.width()); |
1565 | 0 | let frame_clipped_txh: usize = |
1566 | 0 | (((fi.h_in_b - frame_bo.0.y) << MI_SIZE_LOG2) >> ydec) |
1567 | 0 | .min(tx_size.height()); |
1568 | 0 |
|
1569 | 0 | cw.write_coeffs_lv_map( |
1570 | 0 | w, |
1571 | 0 | p, |
1572 | 0 | tx_bo, |
1573 | 0 | qcoeffs, |
1574 | 0 | eob, |
1575 | 0 | mode, |
1576 | 0 | tx_size, |
1577 | 0 | tx_type, |
1578 | 0 | plane_bsize, |
1579 | 0 | xdec, |
1580 | 0 | ydec, |
1581 | 0 | fi.use_reduced_tx_set, |
1582 | 0 | frame_clipped_txw, |
1583 | 0 | frame_clipped_txh, |
1584 | 0 | ) |
1585 | | } else { |
1586 | 0 | true |
1587 | | }; |
1588 | | |
1589 | | // Reconstruct |
1590 | 0 | dequantize( |
1591 | 0 | qidx, |
1592 | 0 | qcoeffs, |
1593 | 0 | eob, |
1594 | 0 | rcoeffs, |
1595 | 0 | tx_size, |
1596 | 0 | fi.sequence.bit_depth, |
1597 | 0 | fi.dc_delta_q[p], |
1598 | 0 | fi.ac_delta_q[p], |
1599 | 0 | fi.cpu_feature_level, |
1600 | 0 | ); |
1601 | 0 | // SAFETY: dequantize initialized rcoeffs |
1602 | 0 | let rcoeffs = unsafe { slice_assume_init_mut(rcoeffs) }; |
1603 | 0 |
|
1604 | 0 | if eob == 0 { |
1605 | 0 | // All zero coefficients is a no-op |
1606 | 0 | } else if !fi.use_tx_domain_distortion || need_recon_pixel { |
1607 | 0 | inverse_transform_add( |
1608 | 0 | rcoeffs, |
1609 | 0 | &mut rec.subregion_mut(area), |
1610 | 0 | eob, |
1611 | 0 | tx_size, |
1612 | 0 | tx_type, |
1613 | 0 | fi.sequence.bit_depth, |
1614 | 0 | fi.cpu_feature_level, |
1615 | 0 | ); |
1616 | 0 | } |
1617 | | |
1618 | 0 | let tx_dist = |
1619 | 0 | if rdo_type.needs_tx_dist() && visible_tx_w != 0 && visible_tx_h != 0 { |
1620 | | // Store tx-domain distortion of this block |
1621 | | // rcoeffs above 32 rows/cols aren't held in the array, because they are |
1622 | | // always 0. The first 32x32 is stored first in coeffs so we can iterate |
1623 | | // over coeffs and rcoeffs for the first 32 rows/cols. For the |
1624 | | // coefficients above 32 rows/cols, we iterate over the rest of coeffs |
1625 | | // with the assumption that rcoeff coefficients are zero. |
1626 | 0 | let mut raw_tx_dist = coeffs |
1627 | 0 | .iter() |
1628 | 0 | .zip(rcoeffs.iter()) |
1629 | 0 | .map(|(&a, &b)| { |
1630 | 0 | let c = i32::cast_from(a) - i32::cast_from(b); |
1631 | 0 | (c * c) as u64 |
1632 | 0 | }) Unexecuted instantiation: rav1e::encoder::encode_tx_block::<u16, rav1e::ec::WriterBase<rav1e::ec::WriterCounter>>::{closure#0} Unexecuted instantiation: rav1e::encoder::encode_tx_block::<u16, rav1e::ec::WriterBase<rav1e::ec::WriterRecorder>>::{closure#0} Unexecuted instantiation: rav1e::encoder::encode_tx_block::<u8, rav1e::ec::WriterBase<rav1e::ec::WriterCounter>>::{closure#0} Unexecuted instantiation: rav1e::encoder::encode_tx_block::<u8, rav1e::ec::WriterBase<rav1e::ec::WriterRecorder>>::{closure#0} |
1633 | 0 | .sum::<u64>() |
1634 | 0 | + coeffs[rcoeffs.len()..] |
1635 | 0 | .iter() |
1636 | 0 | .map(|&a| { |
1637 | 0 | let c = i32::cast_from(a); |
1638 | 0 | (c * c) as u64 |
1639 | 0 | }) Unexecuted instantiation: rav1e::encoder::encode_tx_block::<u16, rav1e::ec::WriterBase<rav1e::ec::WriterCounter>>::{closure#1} Unexecuted instantiation: rav1e::encoder::encode_tx_block::<u16, rav1e::ec::WriterBase<rav1e::ec::WriterRecorder>>::{closure#1} Unexecuted instantiation: rav1e::encoder::encode_tx_block::<u8, rav1e::ec::WriterBase<rav1e::ec::WriterCounter>>::{closure#1} Unexecuted instantiation: rav1e::encoder::encode_tx_block::<u8, rav1e::ec::WriterBase<rav1e::ec::WriterRecorder>>::{closure#1} |
1640 | 0 | .sum::<u64>(); |
1641 | 0 |
|
1642 | 0 | let tx_dist_scale_bits = 2 * (3 - get_log_tx_scale(tx_size)); |
1643 | 0 | let tx_dist_scale_rounding_offset = 1 << (tx_dist_scale_bits - 1); |
1644 | 0 |
|
1645 | 0 | raw_tx_dist = |
1646 | 0 | (raw_tx_dist + tx_dist_scale_rounding_offset) >> tx_dist_scale_bits; |
1647 | 0 |
|
1648 | 0 | if rdo_type == RDOType::TxDistEstRate { |
1649 | 0 | // look up rate and distortion in table |
1650 | 0 | let estimated_rate = |
1651 | 0 | estimate_rate(fi.base_q_idx, tx_size, raw_tx_dist); |
1652 | 0 | w.add_bits_frac(estimated_rate as u32); |
1653 | 0 | } |
1654 | | |
1655 | 0 | let bias = distortion_scale(fi, ts.to_frame_block_offset(tx_bo), bsize); |
1656 | 0 | RawDistortion::new(raw_tx_dist) * bias * fi.dist_scale[p] |
1657 | | } else { |
1658 | 0 | ScaledDistortion::zero() |
1659 | | }; |
1660 | | |
1661 | 0 | (has_coeff, tx_dist) |
1662 | 0 | } Unexecuted instantiation: rav1e::encoder::encode_tx_block::<u16, rav1e::ec::WriterBase<rav1e::ec::WriterCounter>> Unexecuted instantiation: rav1e::encoder::encode_tx_block::<u16, rav1e::ec::WriterBase<rav1e::ec::WriterRecorder>> Unexecuted instantiation: rav1e::encoder::encode_tx_block::<u8, rav1e::ec::WriterBase<rav1e::ec::WriterCounter>> Unexecuted instantiation: rav1e::encoder::encode_tx_block::<u8, rav1e::ec::WriterBase<rav1e::ec::WriterRecorder>> |
1663 | | |
1664 | | /// # Panics |
1665 | | /// |
1666 | | /// - If the block size is invalid for subsampling |
1667 | 0 | #[profiling::function] Unexecuted instantiation: rav1e::encoder::motion_compensate::<u16> Unexecuted instantiation: rav1e::encoder::motion_compensate::<u8> |
1668 | | pub fn motion_compensate<T: Pixel>( |
1669 | | fi: &FrameInvariants<T>, ts: &mut TileStateMut<'_, T>, |
1670 | | cw: &mut ContextWriter, luma_mode: PredictionMode, ref_frames: [RefType; 2], |
1671 | | mvs: [MotionVector; 2], bsize: BlockSize, tile_bo: TileBlockOffset, |
1672 | | luma_only: bool, |
1673 | | ) { |
1674 | | debug_assert!(!luma_mode.is_intra()); |
1675 | | |
1676 | | let PlaneConfig { xdec: u_xdec, ydec: u_ydec, .. } = ts.input.planes[1].cfg; |
1677 | | |
1678 | | // Inter mode prediction can take place once for a whole partition, |
1679 | | // instead of each tx-block. |
1680 | | let num_planes = 1 |
1681 | | + if !luma_only |
1682 | | && has_chroma( |
1683 | | tile_bo, |
1684 | | bsize, |
1685 | | u_xdec, |
1686 | | u_ydec, |
1687 | | fi.sequence.chroma_sampling, |
1688 | | ) { |
1689 | | 2 |
1690 | | } else { |
1691 | | 0 |
1692 | | }; |
1693 | | |
1694 | | let luma_tile_rect = ts.tile_rect(); |
1695 | | let compound_buffer = &mut ts.inter_compound_buffers; |
1696 | | for p in 0..num_planes { |
1697 | | let plane_bsize = if p == 0 { |
1698 | | bsize |
1699 | | } else { |
1700 | | bsize.subsampled_size(u_xdec, u_ydec).unwrap() |
1701 | | }; |
1702 | | |
1703 | | let rec = &mut ts.rec.planes[p]; |
1704 | | let po = tile_bo.plane_offset(rec.plane_cfg); |
1705 | | let &PlaneConfig { xdec, ydec, .. } = rec.plane_cfg; |
1706 | | let tile_rect = luma_tile_rect.decimated(xdec, ydec); |
1707 | | |
1708 | | let area = Area::BlockStartingAt { bo: tile_bo.0 }; |
1709 | | if p > 0 && bsize < BlockSize::BLOCK_8X8 { |
1710 | | let mut some_use_intra = false; |
1711 | | if bsize == BlockSize::BLOCK_4X4 || bsize == BlockSize::BLOCK_4X8 { |
1712 | | some_use_intra |= |
1713 | | cw.bc.blocks[tile_bo.with_offset(-1, 0)].mode.is_intra(); |
1714 | | }; |
1715 | | if !some_use_intra && bsize == BlockSize::BLOCK_4X4 |
1716 | | || bsize == BlockSize::BLOCK_8X4 |
1717 | | { |
1718 | | some_use_intra |= |
1719 | | cw.bc.blocks[tile_bo.with_offset(0, -1)].mode.is_intra(); |
1720 | | }; |
1721 | | if !some_use_intra && bsize == BlockSize::BLOCK_4X4 { |
1722 | | some_use_intra |= |
1723 | | cw.bc.blocks[tile_bo.with_offset(-1, -1)].mode.is_intra(); |
1724 | | }; |
1725 | | |
1726 | | if some_use_intra { |
1727 | | luma_mode.predict_inter( |
1728 | | fi, |
1729 | | tile_rect, |
1730 | | p, |
1731 | | po, |
1732 | | &mut rec.subregion_mut(area), |
1733 | | plane_bsize.width(), |
1734 | | plane_bsize.height(), |
1735 | | ref_frames, |
1736 | | mvs, |
1737 | | compound_buffer, |
1738 | | ); |
1739 | | } else { |
1740 | | assert!(u_xdec == 1 && u_ydec == 1); |
1741 | | // TODO: these are absolutely only valid for 4:2:0 |
1742 | | if bsize == BlockSize::BLOCK_4X4 { |
1743 | | let mv0 = cw.bc.blocks[tile_bo.with_offset(-1, -1)].mv; |
1744 | | let rf0 = cw.bc.blocks[tile_bo.with_offset(-1, -1)].ref_frames; |
1745 | | let mv1 = cw.bc.blocks[tile_bo.with_offset(0, -1)].mv; |
1746 | | let rf1 = cw.bc.blocks[tile_bo.with_offset(0, -1)].ref_frames; |
1747 | | let po1 = PlaneOffset { x: po.x + 2, y: po.y }; |
1748 | | let area1 = Area::StartingAt { x: po1.x, y: po1.y }; |
1749 | | let mv2 = cw.bc.blocks[tile_bo.with_offset(-1, 0)].mv; |
1750 | | let rf2 = cw.bc.blocks[tile_bo.with_offset(-1, 0)].ref_frames; |
1751 | | let po2 = PlaneOffset { x: po.x, y: po.y + 2 }; |
1752 | | let area2 = Area::StartingAt { x: po2.x, y: po2.y }; |
1753 | | let po3 = PlaneOffset { x: po.x + 2, y: po.y + 2 }; |
1754 | | let area3 = Area::StartingAt { x: po3.x, y: po3.y }; |
1755 | | luma_mode.predict_inter( |
1756 | | fi, |
1757 | | tile_rect, |
1758 | | p, |
1759 | | po, |
1760 | | &mut rec.subregion_mut(area), |
1761 | | 2, |
1762 | | 2, |
1763 | | rf0, |
1764 | | mv0, |
1765 | | compound_buffer, |
1766 | | ); |
1767 | | luma_mode.predict_inter( |
1768 | | fi, |
1769 | | tile_rect, |
1770 | | p, |
1771 | | po1, |
1772 | | &mut rec.subregion_mut(area1), |
1773 | | 2, |
1774 | | 2, |
1775 | | rf1, |
1776 | | mv1, |
1777 | | compound_buffer, |
1778 | | ); |
1779 | | luma_mode.predict_inter( |
1780 | | fi, |
1781 | | tile_rect, |
1782 | | p, |
1783 | | po2, |
1784 | | &mut rec.subregion_mut(area2), |
1785 | | 2, |
1786 | | 2, |
1787 | | rf2, |
1788 | | mv2, |
1789 | | compound_buffer, |
1790 | | ); |
1791 | | luma_mode.predict_inter( |
1792 | | fi, |
1793 | | tile_rect, |
1794 | | p, |
1795 | | po3, |
1796 | | &mut rec.subregion_mut(area3), |
1797 | | 2, |
1798 | | 2, |
1799 | | ref_frames, |
1800 | | mvs, |
1801 | | compound_buffer, |
1802 | | ); |
1803 | | } |
1804 | | if bsize == BlockSize::BLOCK_8X4 { |
1805 | | let mv1 = cw.bc.blocks[tile_bo.with_offset(0, -1)].mv; |
1806 | | let rf1 = cw.bc.blocks[tile_bo.with_offset(0, -1)].ref_frames; |
1807 | | luma_mode.predict_inter( |
1808 | | fi, |
1809 | | tile_rect, |
1810 | | p, |
1811 | | po, |
1812 | | &mut rec.subregion_mut(area), |
1813 | | 4, |
1814 | | 2, |
1815 | | rf1, |
1816 | | mv1, |
1817 | | compound_buffer, |
1818 | | ); |
1819 | | let po3 = PlaneOffset { x: po.x, y: po.y + 2 }; |
1820 | | let area3 = Area::StartingAt { x: po3.x, y: po3.y }; |
1821 | | luma_mode.predict_inter( |
1822 | | fi, |
1823 | | tile_rect, |
1824 | | p, |
1825 | | po3, |
1826 | | &mut rec.subregion_mut(area3), |
1827 | | 4, |
1828 | | 2, |
1829 | | ref_frames, |
1830 | | mvs, |
1831 | | compound_buffer, |
1832 | | ); |
1833 | | } |
1834 | | if bsize == BlockSize::BLOCK_4X8 { |
1835 | | let mv2 = cw.bc.blocks[tile_bo.with_offset(-1, 0)].mv; |
1836 | | let rf2 = cw.bc.blocks[tile_bo.with_offset(-1, 0)].ref_frames; |
1837 | | luma_mode.predict_inter( |
1838 | | fi, |
1839 | | tile_rect, |
1840 | | p, |
1841 | | po, |
1842 | | &mut rec.subregion_mut(area), |
1843 | | 2, |
1844 | | 4, |
1845 | | rf2, |
1846 | | mv2, |
1847 | | compound_buffer, |
1848 | | ); |
1849 | | let po3 = PlaneOffset { x: po.x + 2, y: po.y }; |
1850 | | let area3 = Area::StartingAt { x: po3.x, y: po3.y }; |
1851 | | luma_mode.predict_inter( |
1852 | | fi, |
1853 | | tile_rect, |
1854 | | p, |
1855 | | po3, |
1856 | | &mut rec.subregion_mut(area3), |
1857 | | 2, |
1858 | | 4, |
1859 | | ref_frames, |
1860 | | mvs, |
1861 | | compound_buffer, |
1862 | | ); |
1863 | | } |
1864 | | } |
1865 | | } else { |
1866 | | luma_mode.predict_inter( |
1867 | | fi, |
1868 | | tile_rect, |
1869 | | p, |
1870 | | po, |
1871 | | &mut rec.subregion_mut(area), |
1872 | | plane_bsize.width(), |
1873 | | plane_bsize.height(), |
1874 | | ref_frames, |
1875 | | mvs, |
1876 | | compound_buffer, |
1877 | | ); |
1878 | | } |
1879 | | } |
1880 | | } |
1881 | | |
1882 | 0 | pub fn save_block_motion<T: Pixel>( |
1883 | 0 | ts: &mut TileStateMut<'_, T>, bsize: BlockSize, tile_bo: TileBlockOffset, |
1884 | 0 | ref_frame: usize, mv: MotionVector, |
1885 | 0 | ) { |
1886 | 0 | let tile_me_stats = &mut ts.me_stats[ref_frame]; |
1887 | 0 | let tile_bo_x_end = (tile_bo.0.x + bsize.width_mi()).min(ts.mi_width); |
1888 | 0 | let tile_bo_y_end = (tile_bo.0.y + bsize.height_mi()).min(ts.mi_height); |
1889 | 0 | for mi_y in tile_bo.0.y..tile_bo_y_end { |
1890 | 0 | for mi_x in tile_bo.0.x..tile_bo_x_end { |
1891 | 0 | tile_me_stats[mi_y][mi_x].mv = mv; |
1892 | 0 | } |
1893 | | } |
1894 | 0 | } Unexecuted instantiation: rav1e::encoder::save_block_motion::<u16> Unexecuted instantiation: rav1e::encoder::save_block_motion::<u8> |
1895 | | |
1896 | 0 | #[profiling::function] Unexecuted instantiation: rav1e::encoder::encode_block_pre_cdef::<u16, rav1e::ec::WriterBase<rav1e::ec::WriterCounter>> Unexecuted instantiation: rav1e::encoder::encode_block_pre_cdef::<u16, rav1e::ec::WriterBase<rav1e::ec::WriterRecorder>> Unexecuted instantiation: rav1e::encoder::encode_block_pre_cdef::<u8, rav1e::ec::WriterBase<rav1e::ec::WriterCounter>> Unexecuted instantiation: rav1e::encoder::encode_block_pre_cdef::<u8, rav1e::ec::WriterBase<rav1e::ec::WriterRecorder>> |
1897 | | pub fn encode_block_pre_cdef<T: Pixel, W: Writer>( |
1898 | | seq: &Sequence, ts: &TileStateMut<'_, T>, cw: &mut ContextWriter, w: &mut W, |
1899 | | bsize: BlockSize, tile_bo: TileBlockOffset, skip: bool, |
1900 | | ) -> bool { |
1901 | | cw.bc.blocks.set_skip(tile_bo, bsize, skip); |
1902 | | if ts.segmentation.enabled |
1903 | | && ts.segmentation.update_map |
1904 | | && ts.segmentation.preskip |
1905 | | { |
1906 | | cw.write_segmentation( |
1907 | | w, |
1908 | | tile_bo, |
1909 | | bsize, |
1910 | | false, |
1911 | | ts.segmentation.last_active_segid, |
1912 | | ); |
1913 | | } |
1914 | | cw.write_skip(w, tile_bo, skip); |
1915 | | if ts.segmentation.enabled |
1916 | | && ts.segmentation.update_map |
1917 | | && !ts.segmentation.preskip |
1918 | | { |
1919 | | cw.write_segmentation( |
1920 | | w, |
1921 | | tile_bo, |
1922 | | bsize, |
1923 | | skip, |
1924 | | ts.segmentation.last_active_segid, |
1925 | | ); |
1926 | | } |
1927 | | if !skip && seq.enable_cdef { |
1928 | | cw.bc.cdef_coded = true; |
1929 | | } |
1930 | | cw.bc.cdef_coded |
1931 | | } |
1932 | | |
1933 | | /// # Panics |
1934 | | /// |
1935 | | /// - If chroma and luma do not match for inter modes |
1936 | | /// - If an invalid motion vector is found |
1937 | 0 | #[profiling::function] Unexecuted instantiation: rav1e::encoder::encode_block_post_cdef::<u16, rav1e::ec::WriterBase<rav1e::ec::WriterCounter>> Unexecuted instantiation: rav1e::encoder::encode_block_post_cdef::<u16, rav1e::ec::WriterBase<rav1e::ec::WriterRecorder>> Unexecuted instantiation: rav1e::encoder::encode_block_post_cdef::<u8, rav1e::ec::WriterBase<rav1e::ec::WriterCounter>> Unexecuted instantiation: rav1e::encoder::encode_block_post_cdef::<u8, rav1e::ec::WriterBase<rav1e::ec::WriterRecorder>> |
1938 | | pub fn encode_block_post_cdef<T: Pixel, W: Writer>( |
1939 | | fi: &FrameInvariants<T>, ts: &mut TileStateMut<'_, T>, |
1940 | | cw: &mut ContextWriter, w: &mut W, luma_mode: PredictionMode, |
1941 | | chroma_mode: PredictionMode, angle_delta: AngleDelta, |
1942 | | ref_frames: [RefType; 2], mvs: [MotionVector; 2], bsize: BlockSize, |
1943 | | tile_bo: TileBlockOffset, skip: bool, cfl: CFLParams, tx_size: TxSize, |
1944 | | tx_type: TxType, mode_context: usize, mv_stack: &[CandidateMV], |
1945 | | rdo_type: RDOType, need_recon_pixel: bool, |
1946 | | enc_stats: Option<&mut EncoderStats>, |
1947 | | ) -> (bool, ScaledDistortion) { |
1948 | | let planes = |
1949 | | if fi.sequence.chroma_sampling == ChromaSampling::Cs400 { 1 } else { 3 }; |
1950 | | let is_inter = !luma_mode.is_intra(); |
1951 | | if is_inter { |
1952 | | assert!(luma_mode == chroma_mode); |
1953 | | }; |
1954 | | let sb_size = if fi.sequence.use_128x128_superblock { |
1955 | | BlockSize::BLOCK_128X128 |
1956 | | } else { |
1957 | | BlockSize::BLOCK_64X64 |
1958 | | }; |
1959 | | let PlaneConfig { xdec, ydec, .. } = ts.input.planes[1].cfg; |
1960 | | if skip { |
1961 | | cw.bc.reset_skip_context( |
1962 | | tile_bo, |
1963 | | bsize, |
1964 | | xdec, |
1965 | | ydec, |
1966 | | fi.sequence.chroma_sampling, |
1967 | | ); |
1968 | | } |
1969 | | cw.bc.blocks.set_block_size(tile_bo, bsize); |
1970 | | cw.bc.blocks.set_mode(tile_bo, bsize, luma_mode); |
1971 | | cw.bc.blocks.set_tx_size(tile_bo, bsize, tx_size); |
1972 | | cw.bc.blocks.set_ref_frames(tile_bo, bsize, ref_frames); |
1973 | | cw.bc.blocks.set_motion_vectors(tile_bo, bsize, mvs); |
1974 | | |
1975 | | //write_q_deltas(); |
1976 | | if cw.bc.code_deltas |
1977 | | && ts.deblock.block_deltas_enabled |
1978 | | && (bsize < sb_size || !skip) |
1979 | | { |
1980 | | cw.write_block_deblock_deltas( |
1981 | | w, |
1982 | | tile_bo, |
1983 | | ts.deblock.block_delta_multi, |
1984 | | planes, |
1985 | | ); |
1986 | | } |
1987 | | cw.bc.code_deltas = false; |
1988 | | |
1989 | | if fi.frame_type.has_inter() { |
1990 | | cw.write_is_inter(w, tile_bo, is_inter); |
1991 | | if is_inter { |
1992 | | cw.fill_neighbours_ref_counts(tile_bo); |
1993 | | cw.write_ref_frames(w, fi, tile_bo); |
1994 | | |
1995 | | if luma_mode.is_compound() { |
1996 | | cw.write_compound_mode(w, luma_mode, mode_context); |
1997 | | } else { |
1998 | | cw.write_inter_mode(w, luma_mode, mode_context); |
1999 | | } |
2000 | | |
2001 | | let ref_mv_idx = 0; |
2002 | | let num_mv_found = mv_stack.len(); |
2003 | | |
2004 | | if luma_mode == PredictionMode::NEWMV |
2005 | | || luma_mode == PredictionMode::NEW_NEWMV |
2006 | | { |
2007 | | if luma_mode == PredictionMode::NEW_NEWMV { |
2008 | | assert!(num_mv_found >= 2); |
2009 | | } |
2010 | | for idx in 0..2 { |
2011 | | if num_mv_found > idx + 1 { |
2012 | | let drl_mode = ref_mv_idx > idx; |
2013 | | let ctx: usize = (mv_stack[idx].weight < REF_CAT_LEVEL) as usize |
2014 | | + (mv_stack[idx + 1].weight < REF_CAT_LEVEL) as usize; |
2015 | | cw.write_drl_mode(w, drl_mode, ctx); |
2016 | | if !drl_mode { |
2017 | | break; |
2018 | | } |
2019 | | } |
2020 | | } |
2021 | | } |
2022 | | |
2023 | | let ref_mvs = if num_mv_found > 0 { |
2024 | | [mv_stack[ref_mv_idx].this_mv, mv_stack[ref_mv_idx].comp_mv] |
2025 | | } else { |
2026 | | [MotionVector::default(); 2] |
2027 | | }; |
2028 | | |
2029 | | let mv_precision = if fi.force_integer_mv != 0 { |
2030 | | MvSubpelPrecision::MV_SUBPEL_NONE |
2031 | | } else if fi.allow_high_precision_mv { |
2032 | | MvSubpelPrecision::MV_SUBPEL_HIGH_PRECISION |
2033 | | } else { |
2034 | | MvSubpelPrecision::MV_SUBPEL_LOW_PRECISION |
2035 | | }; |
2036 | | |
2037 | | if luma_mode == PredictionMode::NEWMV |
2038 | | || luma_mode == PredictionMode::NEW_NEWMV |
2039 | | || luma_mode == PredictionMode::NEW_NEARESTMV |
2040 | | { |
2041 | | cw.write_mv(w, mvs[0], ref_mvs[0], mv_precision); |
2042 | | } |
2043 | | if luma_mode == PredictionMode::NEW_NEWMV |
2044 | | || luma_mode == PredictionMode::NEAREST_NEWMV |
2045 | | { |
2046 | | cw.write_mv(w, mvs[1], ref_mvs[1], mv_precision); |
2047 | | } |
2048 | | |
2049 | | if luma_mode.has_nearmv() { |
2050 | | let ref_mv_idx = luma_mode.ref_mv_idx(); |
2051 | | if luma_mode != PredictionMode::NEAR0MV { |
2052 | | assert!(num_mv_found > ref_mv_idx); |
2053 | | } |
2054 | | |
2055 | | for idx in 1..3 { |
2056 | | if num_mv_found > idx + 1 { |
2057 | | let drl_mode = ref_mv_idx > idx; |
2058 | | let ctx: usize = (mv_stack[idx].weight < REF_CAT_LEVEL) as usize |
2059 | | + (mv_stack[idx + 1].weight < REF_CAT_LEVEL) as usize; |
2060 | | |
2061 | | cw.write_drl_mode(w, drl_mode, ctx); |
2062 | | if !drl_mode { |
2063 | | break; |
2064 | | } |
2065 | | } |
2066 | | } |
2067 | | if mv_stack.len() > 1 { |
2068 | | assert!(mv_stack[ref_mv_idx].this_mv.row == mvs[0].row); |
2069 | | assert!(mv_stack[ref_mv_idx].this_mv.col == mvs[0].col); |
2070 | | } else { |
2071 | | assert!(0 == mvs[0].row); |
2072 | | assert!(0 == mvs[0].col); |
2073 | | } |
2074 | | } else if luma_mode == PredictionMode::NEARESTMV { |
2075 | | if mv_stack.is_empty() { |
2076 | | assert_eq!(mvs[0].row, 0); |
2077 | | assert_eq!(mvs[0].col, 0); |
2078 | | } else { |
2079 | | assert_eq!(mvs[0].row, mv_stack[0].this_mv.row); |
2080 | | assert_eq!(mvs[0].col, mv_stack[0].this_mv.col); |
2081 | | } |
2082 | | } |
2083 | | } else { |
2084 | | cw.write_intra_mode(w, bsize, luma_mode); |
2085 | | } |
2086 | | } else { |
2087 | | cw.write_intra_mode_kf(w, tile_bo, luma_mode); |
2088 | | } |
2089 | | |
2090 | | if !is_inter { |
2091 | | if luma_mode.is_directional() && bsize >= BlockSize::BLOCK_8X8 { |
2092 | | cw.write_angle_delta(w, angle_delta.y, luma_mode); |
2093 | | } |
2094 | | if has_chroma(tile_bo, bsize, xdec, ydec, fi.sequence.chroma_sampling) { |
2095 | | cw.write_intra_uv_mode(w, chroma_mode, luma_mode, bsize); |
2096 | | if chroma_mode.is_cfl() { |
2097 | | assert!(bsize.cfl_allowed()); |
2098 | | cw.write_cfl_alphas(w, cfl); |
2099 | | } |
2100 | | if chroma_mode.is_directional() && bsize >= BlockSize::BLOCK_8X8 { |
2101 | | cw.write_angle_delta(w, angle_delta.uv, chroma_mode); |
2102 | | } |
2103 | | } |
2104 | | |
2105 | | if fi.allow_screen_content_tools > 0 |
2106 | | && bsize >= BlockSize::BLOCK_8X8 |
2107 | | && bsize.width() <= 64 |
2108 | | && bsize.height() <= 64 |
2109 | | { |
2110 | | cw.write_use_palette_mode( |
2111 | | w, |
2112 | | false, |
2113 | | bsize, |
2114 | | tile_bo, |
2115 | | luma_mode, |
2116 | | chroma_mode, |
2117 | | xdec, |
2118 | | ydec, |
2119 | | fi.sequence.chroma_sampling, |
2120 | | ); |
2121 | | } |
2122 | | |
2123 | | if fi.sequence.enable_filter_intra |
2124 | | && luma_mode == PredictionMode::DC_PRED |
2125 | | && bsize.width() <= 32 |
2126 | | && bsize.height() <= 32 |
2127 | | { |
2128 | | cw.write_use_filter_intra(w, false, bsize); // turn off FILTER_INTRA |
2129 | | } |
2130 | | } |
2131 | | |
2132 | | // write tx_size here |
2133 | | if fi.tx_mode_select { |
2134 | | if bsize > BlockSize::BLOCK_4X4 && (!is_inter || !skip) { |
2135 | | if !is_inter { |
2136 | | cw.write_tx_size_intra(w, tile_bo, bsize, tx_size); |
2137 | | cw.bc.update_tx_size_context(tile_bo, bsize, tx_size, false); |
2138 | | } else { |
2139 | | // write var_tx_size |
2140 | | // if here, bsize > BLOCK_4X4 && is_inter && !skip && !Lossless |
2141 | | debug_assert!(fi.tx_mode_select); |
2142 | | debug_assert!(bsize > BlockSize::BLOCK_4X4); |
2143 | | debug_assert!(is_inter); |
2144 | | debug_assert!(!skip); |
2145 | | let max_tx_size = max_txsize_rect_lookup[bsize as usize]; |
2146 | | debug_assert!(max_tx_size.block_size() <= BlockSize::BLOCK_64X64); |
2147 | | |
2148 | | //TODO: "&& tx_size.block_size() < bsize" will be replaced with tx-split info for a partition |
2149 | | // once it is available. |
2150 | | let txfm_split = |
2151 | | fi.enable_inter_txfm_split && tx_size.block_size() < bsize; |
2152 | | |
2153 | | // TODO: Revise write_tx_size_inter() for txfm_split = true |
2154 | | cw.write_tx_size_inter( |
2155 | | w, |
2156 | | tile_bo, |
2157 | | bsize, |
2158 | | max_tx_size, |
2159 | | txfm_split, |
2160 | | 0, |
2161 | | 0, |
2162 | | 0, |
2163 | | ); |
2164 | | } |
2165 | | } else { |
2166 | | debug_assert!(bsize == BlockSize::BLOCK_4X4 || (is_inter && skip)); |
2167 | | cw.bc.update_tx_size_context(tile_bo, bsize, tx_size, is_inter && skip); |
2168 | | } |
2169 | | } |
2170 | | |
2171 | | if let Some(enc_stats) = enc_stats { |
2172 | | let pixels = tx_size.area(); |
2173 | | enc_stats.block_size_counts[bsize as usize] += pixels; |
2174 | | enc_stats.tx_type_counts[tx_type as usize] += pixels; |
2175 | | enc_stats.luma_pred_mode_counts[luma_mode as usize] += pixels; |
2176 | | enc_stats.chroma_pred_mode_counts[chroma_mode as usize] += pixels; |
2177 | | if skip { |
2178 | | enc_stats.skip_block_count += pixels; |
2179 | | } |
2180 | | } |
2181 | | |
2182 | | if fi.sequence.enable_intra_edge_filter { |
2183 | | for y in 0..bsize.height_mi() { |
2184 | | if tile_bo.0.y + y >= ts.mi_height { |
2185 | | continue; |
2186 | | } |
2187 | | for x in 0..bsize.width_mi() { |
2188 | | if tile_bo.0.x + x >= ts.mi_width { |
2189 | | continue; |
2190 | | } |
2191 | | let bi = &mut ts.coded_block_info[tile_bo.0.y + y][tile_bo.0.x + x]; |
2192 | | bi.luma_mode = luma_mode; |
2193 | | bi.chroma_mode = chroma_mode; |
2194 | | bi.reference_types = ref_frames; |
2195 | | } |
2196 | | } |
2197 | | } |
2198 | | |
2199 | | if is_inter { |
2200 | | motion_compensate( |
2201 | | fi, ts, cw, luma_mode, ref_frames, mvs, bsize, tile_bo, false, |
2202 | | ); |
2203 | | write_tx_tree( |
2204 | | fi, |
2205 | | ts, |
2206 | | cw, |
2207 | | w, |
2208 | | luma_mode, |
2209 | | angle_delta.y, |
2210 | | tile_bo, |
2211 | | bsize, |
2212 | | tx_size, |
2213 | | tx_type, |
2214 | | skip, |
2215 | | false, |
2216 | | rdo_type, |
2217 | | need_recon_pixel, |
2218 | | ) |
2219 | | } else { |
2220 | | write_tx_blocks( |
2221 | | fi, |
2222 | | ts, |
2223 | | cw, |
2224 | | w, |
2225 | | luma_mode, |
2226 | | chroma_mode, |
2227 | | angle_delta, |
2228 | | tile_bo, |
2229 | | bsize, |
2230 | | tx_size, |
2231 | | tx_type, |
2232 | | skip, |
2233 | | cfl, |
2234 | | false, |
2235 | | rdo_type, |
2236 | | need_recon_pixel, |
2237 | | ) |
2238 | | } |
2239 | | } |
2240 | | |
2241 | | /// # Panics |
2242 | | /// |
2243 | | /// - If attempting to encode a lossless block (not yet supported) |
2244 | 0 | pub fn write_tx_blocks<T: Pixel, W: Writer>( |
2245 | 0 | fi: &FrameInvariants<T>, ts: &mut TileStateMut<'_, T>, |
2246 | 0 | cw: &mut ContextWriter, w: &mut W, luma_mode: PredictionMode, |
2247 | 0 | chroma_mode: PredictionMode, angle_delta: AngleDelta, |
2248 | 0 | tile_bo: TileBlockOffset, bsize: BlockSize, tx_size: TxSize, |
2249 | 0 | tx_type: TxType, skip: bool, cfl: CFLParams, luma_only: bool, |
2250 | 0 | rdo_type: RDOType, need_recon_pixel: bool, |
2251 | 0 | ) -> (bool, ScaledDistortion) { |
2252 | 0 | let bw = bsize.width_mi() / tx_size.width_mi(); |
2253 | 0 | let bh = bsize.height_mi() / tx_size.height_mi(); |
2254 | 0 | let qidx = get_qidx(fi, ts, cw, tile_bo); |
2255 | 0 |
|
2256 | 0 | // TODO: Lossless is not yet supported. |
2257 | 0 | if !skip { |
2258 | 0 | assert_ne!(qidx, 0); |
2259 | 0 | } |
2260 | | |
2261 | 0 | let PlaneConfig { xdec, ydec, .. } = ts.input.planes[1].cfg; |
2262 | 0 | let mut ac = Aligned::<[MaybeUninit<i16>; 32 * 32]>::uninit_array(); |
2263 | 0 | let mut partition_has_coeff: bool = false; |
2264 | 0 | let mut tx_dist = ScaledDistortion::zero(); |
2265 | 0 | let do_chroma = |
2266 | 0 | has_chroma(tile_bo, bsize, xdec, ydec, fi.sequence.chroma_sampling); |
2267 | 0 |
|
2268 | 0 | ts.qc.update( |
2269 | 0 | qidx, |
2270 | 0 | tx_size, |
2271 | 0 | luma_mode.is_intra(), |
2272 | 0 | fi.sequence.bit_depth, |
2273 | 0 | fi.dc_delta_q[0], |
2274 | 0 | 0, |
2275 | 0 | ); |
2276 | | |
2277 | 0 | for by in 0..bh { |
2278 | 0 | for bx in 0..bw { |
2279 | 0 | let tx_bo = TileBlockOffset(BlockOffset { |
2280 | 0 | x: tile_bo.0.x + bx * tx_size.width_mi(), |
2281 | 0 | y: tile_bo.0.y + by * tx_size.height_mi(), |
2282 | 0 | }); |
2283 | 0 | if tx_bo.0.x >= ts.mi_width || tx_bo.0.y >= ts.mi_height { |
2284 | 0 | continue; |
2285 | 0 | } |
2286 | 0 | let po = tx_bo.plane_offset(&ts.input.planes[0].cfg); |
2287 | 0 | let (has_coeff, dist) = encode_tx_block( |
2288 | 0 | fi, |
2289 | 0 | ts, |
2290 | 0 | cw, |
2291 | 0 | w, |
2292 | 0 | 0, |
2293 | 0 | tile_bo, |
2294 | 0 | bx, |
2295 | 0 | by, |
2296 | 0 | tx_bo, |
2297 | 0 | luma_mode, |
2298 | 0 | tx_size, |
2299 | 0 | tx_type, |
2300 | 0 | bsize, |
2301 | 0 | po, |
2302 | 0 | skip, |
2303 | 0 | qidx, |
2304 | 0 | &[], |
2305 | 0 | IntraParam::AngleDelta(angle_delta.y), |
2306 | 0 | rdo_type, |
2307 | 0 | need_recon_pixel, |
2308 | 0 | ); |
2309 | 0 | partition_has_coeff |= has_coeff; |
2310 | 0 | tx_dist += dist; |
2311 | | } |
2312 | | } |
2313 | | |
2314 | 0 | if !do_chroma |
2315 | 0 | || luma_only |
2316 | 0 | || fi.sequence.chroma_sampling == ChromaSampling::Cs400 |
2317 | | { |
2318 | 0 | return (partition_has_coeff, tx_dist); |
2319 | 0 | }; |
2320 | 0 | debug_assert!(has_chroma( |
2321 | 0 | tile_bo, |
2322 | 0 | bsize, |
2323 | 0 | xdec, |
2324 | 0 | ydec, |
2325 | 0 | fi.sequence.chroma_sampling |
2326 | 0 | )); |
2327 | | |
2328 | 0 | let uv_tx_size = bsize.largest_chroma_tx_size(xdec, ydec); |
2329 | 0 |
|
2330 | 0 | let mut bw_uv = (bw * tx_size.width_mi()) >> xdec; |
2331 | 0 | let mut bh_uv = (bh * tx_size.height_mi()) >> ydec; |
2332 | 0 |
|
2333 | 0 | if bw_uv == 0 || bh_uv == 0 { |
2334 | 0 | bw_uv = 1; |
2335 | 0 | bh_uv = 1; |
2336 | 0 | } |
2337 | | |
2338 | 0 | bw_uv /= uv_tx_size.width_mi(); |
2339 | 0 | bh_uv /= uv_tx_size.height_mi(); |
2340 | | |
2341 | 0 | let ac_data = if chroma_mode.is_cfl() { |
2342 | 0 | luma_ac(&mut ac.data, ts, tile_bo, bsize, tx_size, fi) |
2343 | | } else { |
2344 | 0 | [].as_slice() |
2345 | | }; |
2346 | | |
2347 | 0 | let uv_tx_type = if uv_tx_size.width() >= 32 || uv_tx_size.height() >= 32 { |
2348 | 0 | TxType::DCT_DCT |
2349 | | } else { |
2350 | 0 | uv_intra_mode_to_tx_type_context(chroma_mode) |
2351 | | }; |
2352 | | |
2353 | 0 | for p in 1..3 { |
2354 | 0 | ts.qc.update( |
2355 | 0 | qidx, |
2356 | 0 | uv_tx_size, |
2357 | 0 | true, |
2358 | 0 | fi.sequence.bit_depth, |
2359 | 0 | fi.dc_delta_q[p], |
2360 | 0 | fi.ac_delta_q[p], |
2361 | 0 | ); |
2362 | 0 | let alpha = cfl.alpha(p - 1); |
2363 | 0 | for by in 0..bh_uv { |
2364 | 0 | for bx in 0..bw_uv { |
2365 | 0 | let tx_bo = TileBlockOffset(BlockOffset { |
2366 | 0 | x: tile_bo.0.x + ((bx * uv_tx_size.width_mi()) << xdec) |
2367 | 0 | - ((bw * tx_size.width_mi() == 1) as usize) * xdec, |
2368 | 0 | y: tile_bo.0.y + ((by * uv_tx_size.height_mi()) << ydec) |
2369 | 0 | - ((bh * tx_size.height_mi() == 1) as usize) * ydec, |
2370 | 0 | }); |
2371 | 0 |
|
2372 | 0 | let mut po = tile_bo.plane_offset(&ts.input.planes[p].cfg); |
2373 | 0 | po.x += (bx * uv_tx_size.width()) as isize; |
2374 | 0 | po.y += (by * uv_tx_size.height()) as isize; |
2375 | 0 | let (has_coeff, dist) = encode_tx_block( |
2376 | 0 | fi, |
2377 | 0 | ts, |
2378 | 0 | cw, |
2379 | 0 | w, |
2380 | 0 | p, |
2381 | 0 | tile_bo, |
2382 | 0 | bx, |
2383 | 0 | by, |
2384 | 0 | tx_bo, |
2385 | 0 | chroma_mode, |
2386 | 0 | uv_tx_size, |
2387 | 0 | uv_tx_type, |
2388 | 0 | bsize, |
2389 | 0 | po, |
2390 | 0 | skip, |
2391 | 0 | qidx, |
2392 | 0 | ac_data, |
2393 | 0 | if chroma_mode.is_cfl() { |
2394 | 0 | IntraParam::Alpha(alpha) |
2395 | | } else { |
2396 | 0 | IntraParam::AngleDelta(angle_delta.uv) |
2397 | | }, |
2398 | 0 | rdo_type, |
2399 | 0 | need_recon_pixel, |
2400 | 0 | ); |
2401 | 0 | partition_has_coeff |= has_coeff; |
2402 | 0 | tx_dist += dist; |
2403 | | } |
2404 | | } |
2405 | | } |
2406 | | |
2407 | 0 | (partition_has_coeff, tx_dist) |
2408 | 0 | } Unexecuted instantiation: rav1e::encoder::write_tx_blocks::<u16, rav1e::ec::WriterBase<rav1e::ec::WriterCounter>> Unexecuted instantiation: rav1e::encoder::write_tx_blocks::<u16, rav1e::ec::WriterBase<rav1e::ec::WriterRecorder>> Unexecuted instantiation: rav1e::encoder::write_tx_blocks::<u8, rav1e::ec::WriterBase<rav1e::ec::WriterCounter>> Unexecuted instantiation: rav1e::encoder::write_tx_blocks::<u8, rav1e::ec::WriterBase<rav1e::ec::WriterRecorder>> |
2409 | | |
2410 | 0 | pub fn write_tx_tree<T: Pixel, W: Writer>( |
2411 | 0 | fi: &FrameInvariants<T>, ts: &mut TileStateMut<'_, T>, |
2412 | 0 | cw: &mut ContextWriter, w: &mut W, luma_mode: PredictionMode, |
2413 | 0 | angle_delta_y: i8, tile_bo: TileBlockOffset, bsize: BlockSize, |
2414 | 0 | tx_size: TxSize, tx_type: TxType, skip: bool, luma_only: bool, |
2415 | 0 | rdo_type: RDOType, need_recon_pixel: bool, |
2416 | 0 | ) -> (bool, ScaledDistortion) { |
2417 | 0 | if skip { |
2418 | 0 | return (false, ScaledDistortion::zero()); |
2419 | 0 | } |
2420 | 0 | let bw = bsize.width_mi() / tx_size.width_mi(); |
2421 | 0 | let bh = bsize.height_mi() / tx_size.height_mi(); |
2422 | 0 | let qidx = get_qidx(fi, ts, cw, tile_bo); |
2423 | 0 |
|
2424 | 0 | let PlaneConfig { xdec, ydec, .. } = ts.input.planes[1].cfg; |
2425 | 0 | let ac = &[0i16; 0]; |
2426 | 0 | let mut partition_has_coeff: bool = false; |
2427 | 0 | let mut tx_dist = ScaledDistortion::zero(); |
2428 | 0 |
|
2429 | 0 | ts.qc.update( |
2430 | 0 | qidx, |
2431 | 0 | tx_size, |
2432 | 0 | luma_mode.is_intra(), |
2433 | 0 | fi.sequence.bit_depth, |
2434 | 0 | fi.dc_delta_q[0], |
2435 | 0 | 0, |
2436 | 0 | ); |
2437 | | |
2438 | | // TODO: If tx-parition more than only 1-level, this code does not work. |
2439 | | // It should recursively traverse the tx block that are split recursivelty by calling write_tx_tree(), |
2440 | | // as defined in https://aomediacodec.github.io/av1-spec/#transform-tree-syntax |
2441 | 0 | for by in 0..bh { |
2442 | 0 | for bx in 0..bw { |
2443 | 0 | let tx_bo = TileBlockOffset(BlockOffset { |
2444 | 0 | x: tile_bo.0.x + bx * tx_size.width_mi(), |
2445 | 0 | y: tile_bo.0.y + by * tx_size.height_mi(), |
2446 | 0 | }); |
2447 | 0 | if tx_bo.0.x >= ts.mi_width || tx_bo.0.y >= ts.mi_height { |
2448 | 0 | continue; |
2449 | 0 | } |
2450 | 0 |
|
2451 | 0 | let po = tx_bo.plane_offset(&ts.input.planes[0].cfg); |
2452 | 0 | let (has_coeff, dist) = encode_tx_block( |
2453 | 0 | fi, |
2454 | 0 | ts, |
2455 | 0 | cw, |
2456 | 0 | w, |
2457 | 0 | 0, |
2458 | 0 | tile_bo, |
2459 | 0 | 0, |
2460 | 0 | 0, |
2461 | 0 | tx_bo, |
2462 | 0 | luma_mode, |
2463 | 0 | tx_size, |
2464 | 0 | tx_type, |
2465 | 0 | bsize, |
2466 | 0 | po, |
2467 | 0 | skip, |
2468 | 0 | qidx, |
2469 | 0 | ac, |
2470 | 0 | IntraParam::AngleDelta(angle_delta_y), |
2471 | 0 | rdo_type, |
2472 | 0 | need_recon_pixel, |
2473 | 0 | ); |
2474 | 0 | partition_has_coeff |= has_coeff; |
2475 | 0 | tx_dist += dist; |
2476 | | } |
2477 | | } |
2478 | | |
2479 | 0 | if !has_chroma(tile_bo, bsize, xdec, ydec, fi.sequence.chroma_sampling) |
2480 | 0 | || luma_only |
2481 | 0 | || fi.sequence.chroma_sampling == ChromaSampling::Cs400 |
2482 | | { |
2483 | 0 | return (partition_has_coeff, tx_dist); |
2484 | 0 | }; |
2485 | 0 | debug_assert!(has_chroma( |
2486 | 0 | tile_bo, |
2487 | 0 | bsize, |
2488 | 0 | xdec, |
2489 | 0 | ydec, |
2490 | 0 | fi.sequence.chroma_sampling |
2491 | 0 | )); |
2492 | | |
2493 | 0 | let max_tx_size = max_txsize_rect_lookup[bsize as usize]; |
2494 | 0 | debug_assert!(max_tx_size.block_size() <= BlockSize::BLOCK_64X64); |
2495 | 0 | let uv_tx_size = bsize.largest_chroma_tx_size(xdec, ydec); |
2496 | 0 |
|
2497 | 0 | let mut bw_uv = max_tx_size.width_mi() >> xdec; |
2498 | 0 | let mut bh_uv = max_tx_size.height_mi() >> ydec; |
2499 | 0 |
|
2500 | 0 | if bw_uv == 0 || bh_uv == 0 { |
2501 | 0 | bw_uv = 1; |
2502 | 0 | bh_uv = 1; |
2503 | 0 | } |
2504 | | |
2505 | 0 | bw_uv /= uv_tx_size.width_mi(); |
2506 | 0 | bh_uv /= uv_tx_size.height_mi(); |
2507 | | |
2508 | 0 | let uv_tx_type = if partition_has_coeff { |
2509 | 0 | tx_type.uv_inter(uv_tx_size) |
2510 | | } else { |
2511 | 0 | TxType::DCT_DCT |
2512 | | }; |
2513 | | |
2514 | 0 | for p in 1..3 { |
2515 | 0 | ts.qc.update( |
2516 | 0 | qidx, |
2517 | 0 | uv_tx_size, |
2518 | 0 | false, |
2519 | 0 | fi.sequence.bit_depth, |
2520 | 0 | fi.dc_delta_q[p], |
2521 | 0 | fi.ac_delta_q[p], |
2522 | 0 | ); |
2523 | | |
2524 | 0 | for by in 0..bh_uv { |
2525 | 0 | for bx in 0..bw_uv { |
2526 | 0 | let tx_bo = TileBlockOffset(BlockOffset { |
2527 | 0 | x: tile_bo.0.x + ((bx * uv_tx_size.width_mi()) << xdec) |
2528 | 0 | - (max_tx_size.width_mi() == 1) as usize * xdec, |
2529 | 0 | y: tile_bo.0.y + ((by * uv_tx_size.height_mi()) << ydec) |
2530 | 0 | - (max_tx_size.height_mi() == 1) as usize * ydec, |
2531 | 0 | }); |
2532 | 0 |
|
2533 | 0 | let mut po = tile_bo.plane_offset(&ts.input.planes[p].cfg); |
2534 | 0 | po.x += (bx * uv_tx_size.width()) as isize; |
2535 | 0 | po.y += (by * uv_tx_size.height()) as isize; |
2536 | 0 | let (has_coeff, dist) = encode_tx_block( |
2537 | 0 | fi, |
2538 | 0 | ts, |
2539 | 0 | cw, |
2540 | 0 | w, |
2541 | 0 | p, |
2542 | 0 | tile_bo, |
2543 | 0 | bx, |
2544 | 0 | by, |
2545 | 0 | tx_bo, |
2546 | 0 | luma_mode, |
2547 | 0 | uv_tx_size, |
2548 | 0 | uv_tx_type, |
2549 | 0 | bsize, |
2550 | 0 | po, |
2551 | 0 | skip, |
2552 | 0 | qidx, |
2553 | 0 | ac, |
2554 | 0 | IntraParam::AngleDelta(angle_delta_y), |
2555 | 0 | rdo_type, |
2556 | 0 | need_recon_pixel, |
2557 | 0 | ); |
2558 | 0 | partition_has_coeff |= has_coeff; |
2559 | 0 | tx_dist += dist; |
2560 | 0 | } |
2561 | | } |
2562 | | } |
2563 | | |
2564 | 0 | (partition_has_coeff, tx_dist) |
2565 | 0 | } Unexecuted instantiation: rav1e::encoder::write_tx_tree::<u16, rav1e::ec::WriterBase<rav1e::ec::WriterCounter>> Unexecuted instantiation: rav1e::encoder::write_tx_tree::<u16, rav1e::ec::WriterBase<rav1e::ec::WriterRecorder>> Unexecuted instantiation: rav1e::encoder::write_tx_tree::<u8, rav1e::ec::WriterBase<rav1e::ec::WriterCounter>> Unexecuted instantiation: rav1e::encoder::write_tx_tree::<u8, rav1e::ec::WriterBase<rav1e::ec::WriterRecorder>> |
2566 | | |
2567 | 0 | #[profiling::function] Unexecuted instantiation: rav1e::encoder::encode_block_with_modes::<u16, rav1e::ec::WriterBase<rav1e::ec::WriterRecorder>> Unexecuted instantiation: rav1e::encoder::encode_block_with_modes::<u8, rav1e::ec::WriterBase<rav1e::ec::WriterRecorder>> |
2568 | | pub fn encode_block_with_modes<T: Pixel, W: Writer>( |
2569 | | fi: &FrameInvariants<T>, ts: &mut TileStateMut<'_, T>, |
2570 | | cw: &mut ContextWriter, w_pre_cdef: &mut W, w_post_cdef: &mut W, |
2571 | | bsize: BlockSize, tile_bo: TileBlockOffset, |
2572 | | mode_decision: &PartitionParameters, rdo_type: RDOType, |
2573 | | enc_stats: Option<&mut EncoderStats>, |
2574 | | ) { |
2575 | | let (mode_luma, mode_chroma) = |
2576 | | (mode_decision.pred_mode_luma, mode_decision.pred_mode_chroma); |
2577 | | let cfl = mode_decision.pred_cfl_params; |
2578 | | let ref_frames = mode_decision.ref_frames; |
2579 | | let mvs = mode_decision.mvs; |
2580 | | let mut skip = mode_decision.skip; |
2581 | | let mut cdef_coded = cw.bc.cdef_coded; |
2582 | | |
2583 | | // Set correct segmentation ID before encoding and before |
2584 | | // rdo_tx_size_type(). |
2585 | | cw.bc.blocks.set_segmentation_idx(tile_bo, bsize, mode_decision.sidx); |
2586 | | |
2587 | | let mut mv_stack = ArrayVec::<CandidateMV, 9>::new(); |
2588 | | let is_compound = ref_frames[1] != NONE_FRAME; |
2589 | | let mode_context = |
2590 | | cw.find_mvrefs(tile_bo, ref_frames, &mut mv_stack, bsize, fi, is_compound); |
2591 | | |
2592 | | let (tx_size, tx_type) = if !mode_decision.skip && !mode_decision.has_coeff { |
2593 | | skip = true; |
2594 | | rdo_tx_size_type( |
2595 | | fi, ts, cw, bsize, tile_bo, mode_luma, ref_frames, mvs, skip, |
2596 | | ) |
2597 | | } else { |
2598 | | (mode_decision.tx_size, mode_decision.tx_type) |
2599 | | }; |
2600 | | |
2601 | | cdef_coded = encode_block_pre_cdef( |
2602 | | &fi.sequence, |
2603 | | ts, |
2604 | | cw, |
2605 | | if cdef_coded { w_post_cdef } else { w_pre_cdef }, |
2606 | | bsize, |
2607 | | tile_bo, |
2608 | | skip, |
2609 | | ); |
2610 | | encode_block_post_cdef( |
2611 | | fi, |
2612 | | ts, |
2613 | | cw, |
2614 | | if cdef_coded { w_post_cdef } else { w_pre_cdef }, |
2615 | | mode_luma, |
2616 | | mode_chroma, |
2617 | | mode_decision.angle_delta, |
2618 | | ref_frames, |
2619 | | mvs, |
2620 | | bsize, |
2621 | | tile_bo, |
2622 | | skip, |
2623 | | cfl, |
2624 | | tx_size, |
2625 | | tx_type, |
2626 | | mode_context, |
2627 | | &mv_stack, |
2628 | | rdo_type, |
2629 | | true, |
2630 | | enc_stats, |
2631 | | ); |
2632 | | } |
2633 | | |
2634 | 0 | #[profiling::function] Unexecuted instantiation: rav1e::encoder::encode_partition_bottomup::<u16, rav1e::ec::WriterBase<rav1e::ec::WriterRecorder>> Unexecuted instantiation: rav1e::encoder::encode_partition_bottomup::<u8, rav1e::ec::WriterBase<rav1e::ec::WriterRecorder>> |
2635 | | fn encode_partition_bottomup<T: Pixel, W: Writer>( |
2636 | | fi: &FrameInvariants<T>, ts: &mut TileStateMut<'_, T>, |
2637 | | cw: &mut ContextWriter, w_pre_cdef: &mut W, w_post_cdef: &mut W, |
2638 | | bsize: BlockSize, tile_bo: TileBlockOffset, ref_rd_cost: f64, |
2639 | | inter_cfg: &InterConfig, enc_stats: &mut EncoderStats, |
2640 | | ) -> PartitionGroupParameters { |
2641 | | let rdo_type = RDOType::PixelDistRealRate; |
2642 | | let mut rd_cost = std::f64::MAX; |
2643 | | let mut best_rd = std::f64::MAX; |
2644 | | let mut rdo_output = PartitionGroupParameters { |
2645 | | rd_cost, |
2646 | | part_type: PartitionType::PARTITION_INVALID, |
2647 | | part_modes: ArrayVec::new(), |
2648 | | }; |
2649 | | |
2650 | | if tile_bo.0.x >= ts.mi_width || tile_bo.0.y >= ts.mi_height { |
2651 | | return rdo_output; |
2652 | | } |
2653 | | |
2654 | | let is_square = bsize.is_sqr(); |
2655 | | let hbs = bsize.width_mi() / 2; |
2656 | | let has_cols = tile_bo.0.x + hbs < ts.mi_width; |
2657 | | let has_rows = tile_bo.0.y + hbs < ts.mi_height; |
2658 | | let is_straddle_x = tile_bo.0.x + bsize.width_mi() > ts.mi_width; |
2659 | | let is_straddle_y = tile_bo.0.y + bsize.height_mi() > ts.mi_height; |
2660 | | |
2661 | | // TODO: Update for 128x128 superblocks |
2662 | | assert!(fi.partition_range.max <= BlockSize::BLOCK_64X64); |
2663 | | |
2664 | | let must_split = |
2665 | | is_square && (bsize > fi.partition_range.max || !has_cols || !has_rows); |
2666 | | |
2667 | | let can_split = // FIXME: sub-8x8 inter blocks not supported for non-4:2:0 sampling |
2668 | | if fi.frame_type.has_inter() && |
2669 | | fi.sequence.chroma_sampling != ChromaSampling::Cs420 && |
2670 | | bsize <= BlockSize::BLOCK_8X8 { |
2671 | | false |
2672 | | } else { |
2673 | | (bsize > fi.partition_range.min && is_square) || must_split |
2674 | | }; |
2675 | | |
2676 | | assert!(bsize >= BlockSize::BLOCK_8X8 || !can_split); |
2677 | | |
2678 | | let mut best_partition = PartitionType::PARTITION_INVALID; |
2679 | | |
2680 | | let cw_checkpoint = cw.checkpoint(&tile_bo, fi.sequence.chroma_sampling); |
2681 | | let w_pre_checkpoint = w_pre_cdef.checkpoint(); |
2682 | | let w_post_checkpoint = w_post_cdef.checkpoint(); |
2683 | | |
2684 | | // Code the whole block |
2685 | | if !must_split { |
2686 | | let cost = if bsize >= BlockSize::BLOCK_8X8 && is_square { |
2687 | | let w: &mut W = if cw.bc.cdef_coded { w_post_cdef } else { w_pre_cdef }; |
2688 | | let tell = w.tell_frac(); |
2689 | | cw.write_partition(w, tile_bo, PartitionType::PARTITION_NONE, bsize); |
2690 | | compute_rd_cost(fi, w.tell_frac() - tell, ScaledDistortion::zero()) |
2691 | | } else { |
2692 | | 0.0 |
2693 | | }; |
2694 | | |
2695 | | let mode_decision = |
2696 | | rdo_mode_decision(fi, ts, cw, bsize, tile_bo, inter_cfg); |
2697 | | |
2698 | | if !mode_decision.pred_mode_luma.is_intra() { |
2699 | | // Fill the saved motion structure |
2700 | | save_block_motion( |
2701 | | ts, |
2702 | | mode_decision.bsize, |
2703 | | mode_decision.bo, |
2704 | | mode_decision.ref_frames[0].to_index(), |
2705 | | mode_decision.mvs[0], |
2706 | | ); |
2707 | | } |
2708 | | |
2709 | | rd_cost = mode_decision.rd_cost + cost; |
2710 | | |
2711 | | best_partition = PartitionType::PARTITION_NONE; |
2712 | | best_rd = rd_cost; |
2713 | | rdo_output.part_modes.push(mode_decision.clone()); |
2714 | | |
2715 | | if !can_split { |
2716 | | encode_block_with_modes( |
2717 | | fi, |
2718 | | ts, |
2719 | | cw, |
2720 | | w_pre_cdef, |
2721 | | w_post_cdef, |
2722 | | bsize, |
2723 | | tile_bo, |
2724 | | &mode_decision, |
2725 | | rdo_type, |
2726 | | Some(enc_stats), |
2727 | | ); |
2728 | | } |
2729 | | } // if !must_split |
2730 | | |
2731 | | let mut early_exit = false; |
2732 | | |
2733 | | // Test all partition types other than PARTITION_NONE by comparing their RD costs |
2734 | | if can_split { |
2735 | | debug_assert!(is_square); |
2736 | | |
2737 | | let mut partition_types = ArrayVec::<PartitionType, 3>::new(); |
2738 | | if bsize |
2739 | | <= fi.config.speed_settings.partition.non_square_partition_max_threshold |
2740 | | || is_straddle_x |
2741 | | || is_straddle_y |
2742 | | { |
2743 | | if has_cols { |
2744 | | partition_types.push(PartitionType::PARTITION_HORZ); |
2745 | | } |
2746 | | if !(fi.sequence.chroma_sampling == ChromaSampling::Cs422) && has_rows { |
2747 | | partition_types.push(PartitionType::PARTITION_VERT); |
2748 | | } |
2749 | | } |
2750 | | partition_types.push(PartitionType::PARTITION_SPLIT); |
2751 | | |
2752 | | for partition in partition_types { |
2753 | | // (!has_rows || !has_cols) --> must_split |
2754 | | debug_assert!((has_rows && has_cols) || must_split); |
2755 | | // (!has_rows && has_cols) --> partition != PartitionType::PARTITION_VERT |
2756 | | debug_assert!( |
2757 | | has_rows || !has_cols || (partition != PartitionType::PARTITION_VERT) |
2758 | | ); |
2759 | | // (has_rows && !has_cols) --> partition != PartitionType::PARTITION_HORZ |
2760 | | debug_assert!( |
2761 | | !has_rows || has_cols || (partition != PartitionType::PARTITION_HORZ) |
2762 | | ); |
2763 | | // (!has_rows && !has_cols) --> partition == PartitionType::PARTITION_SPLIT |
2764 | | debug_assert!( |
2765 | | has_rows || has_cols || (partition == PartitionType::PARTITION_SPLIT) |
2766 | | ); |
2767 | | |
2768 | | cw.rollback(&cw_checkpoint); |
2769 | | w_pre_cdef.rollback(&w_pre_checkpoint); |
2770 | | w_post_cdef.rollback(&w_post_checkpoint); |
2771 | | |
2772 | | let subsize = bsize.subsize(partition).unwrap(); |
2773 | | let hbsw = subsize.width_mi(); // Half the block size width in blocks |
2774 | | let hbsh = subsize.height_mi(); // Half the block size height in blocks |
2775 | | let mut child_modes = ArrayVec::<PartitionParameters, 4>::new(); |
2776 | | rd_cost = 0.0; |
2777 | | |
2778 | | if bsize >= BlockSize::BLOCK_8X8 { |
2779 | | let w: &mut W = |
2780 | | if cw.bc.cdef_coded { w_post_cdef } else { w_pre_cdef }; |
2781 | | let tell = w.tell_frac(); |
2782 | | cw.write_partition(w, tile_bo, partition, bsize); |
2783 | | rd_cost = |
2784 | | compute_rd_cost(fi, w.tell_frac() - tell, ScaledDistortion::zero()); |
2785 | | } |
2786 | | |
2787 | | let four_partitions = [ |
2788 | | tile_bo, |
2789 | | TileBlockOffset(BlockOffset { x: tile_bo.0.x + hbsw, y: tile_bo.0.y }), |
2790 | | TileBlockOffset(BlockOffset { x: tile_bo.0.x, y: tile_bo.0.y + hbsh }), |
2791 | | TileBlockOffset(BlockOffset { |
2792 | | x: tile_bo.0.x + hbsw, |
2793 | | y: tile_bo.0.y + hbsh, |
2794 | | }), |
2795 | | ]; |
2796 | | let partitions = get_sub_partitions(&four_partitions, partition); |
2797 | | |
2798 | | early_exit = false; |
2799 | | // If either of horz or vert partition types is being tested, |
2800 | | // two partitioned rectangles, defined in 'partitions', of the current block |
2801 | | // is passed to encode_partition_bottomup() |
2802 | | for offset in partitions { |
2803 | | if offset.0.x >= ts.mi_width || offset.0.y >= ts.mi_height { |
2804 | | continue; |
2805 | | } |
2806 | | let child_rdo_output = encode_partition_bottomup( |
2807 | | fi, |
2808 | | ts, |
2809 | | cw, |
2810 | | w_pre_cdef, |
2811 | | w_post_cdef, |
2812 | | subsize, |
2813 | | offset, |
2814 | | best_rd, |
2815 | | inter_cfg, |
2816 | | enc_stats, |
2817 | | ); |
2818 | | let cost = child_rdo_output.rd_cost; |
2819 | | assert!(cost >= 0.0); |
2820 | | |
2821 | | if cost != std::f64::MAX { |
2822 | | rd_cost += cost; |
2823 | | if !must_split |
2824 | | && fi.enable_early_exit |
2825 | | && (rd_cost >= best_rd || rd_cost >= ref_rd_cost) |
2826 | | { |
2827 | | assert!(cost != std::f64::MAX); |
2828 | | early_exit = true; |
2829 | | break; |
2830 | | } else if partition != PartitionType::PARTITION_SPLIT { |
2831 | | child_modes.push(child_rdo_output.part_modes[0].clone()); |
2832 | | } |
2833 | | } |
2834 | | } |
2835 | | |
2836 | | if !early_exit && rd_cost < best_rd { |
2837 | | best_rd = rd_cost; |
2838 | | best_partition = partition; |
2839 | | if partition != PartitionType::PARTITION_SPLIT { |
2840 | | assert!(!child_modes.is_empty()); |
2841 | | rdo_output.part_modes = child_modes; |
2842 | | } |
2843 | | } |
2844 | | } |
2845 | | |
2846 | | debug_assert!( |
2847 | | early_exit || best_partition != PartitionType::PARTITION_INVALID |
2848 | | ); |
2849 | | |
2850 | | // If the best partition is not PARTITION_SPLIT, recode it |
2851 | | if best_partition != PartitionType::PARTITION_SPLIT { |
2852 | | assert!(!rdo_output.part_modes.is_empty()); |
2853 | | cw.rollback(&cw_checkpoint); |
2854 | | w_pre_cdef.rollback(&w_pre_checkpoint); |
2855 | | w_post_cdef.rollback(&w_post_checkpoint); |
2856 | | |
2857 | | assert!(best_partition != PartitionType::PARTITION_NONE || !must_split); |
2858 | | let subsize = bsize.subsize(best_partition).unwrap(); |
2859 | | |
2860 | | if bsize >= BlockSize::BLOCK_8X8 { |
2861 | | let w: &mut W = |
2862 | | if cw.bc.cdef_coded { w_post_cdef } else { w_pre_cdef }; |
2863 | | cw.write_partition(w, tile_bo, best_partition, bsize); |
2864 | | } |
2865 | | for mode in rdo_output.part_modes.clone() { |
2866 | | assert!(subsize == mode.bsize); |
2867 | | |
2868 | | if !mode.pred_mode_luma.is_intra() { |
2869 | | save_block_motion( |
2870 | | ts, |
2871 | | mode.bsize, |
2872 | | mode.bo, |
2873 | | mode.ref_frames[0].to_index(), |
2874 | | mode.mvs[0], |
2875 | | ); |
2876 | | } |
2877 | | |
2878 | | // FIXME: redundant block re-encode |
2879 | | encode_block_with_modes( |
2880 | | fi, |
2881 | | ts, |
2882 | | cw, |
2883 | | w_pre_cdef, |
2884 | | w_post_cdef, |
2885 | | mode.bsize, |
2886 | | mode.bo, |
2887 | | &mode, |
2888 | | rdo_type, |
2889 | | Some(enc_stats), |
2890 | | ); |
2891 | | } |
2892 | | } |
2893 | | } // if can_split { |
2894 | | |
2895 | | assert!(best_partition != PartitionType::PARTITION_INVALID); |
2896 | | |
2897 | | if is_square |
2898 | | && bsize >= BlockSize::BLOCK_8X8 |
2899 | | && (bsize == BlockSize::BLOCK_8X8 |
2900 | | || best_partition != PartitionType::PARTITION_SPLIT) |
2901 | | { |
2902 | | cw.bc.update_partition_context( |
2903 | | tile_bo, |
2904 | | bsize.subsize(best_partition).unwrap(), |
2905 | | bsize, |
2906 | | ); |
2907 | | } |
2908 | | |
2909 | | rdo_output.rd_cost = best_rd; |
2910 | | rdo_output.part_type = best_partition; |
2911 | | |
2912 | | if best_partition != PartitionType::PARTITION_NONE { |
2913 | | rdo_output.part_modes.clear(); |
2914 | | } |
2915 | | rdo_output |
2916 | | } |
2917 | | |
2918 | 0 | fn encode_partition_topdown<T: Pixel, W: Writer>( |
2919 | 0 | fi: &FrameInvariants<T>, ts: &mut TileStateMut<'_, T>, |
2920 | 0 | cw: &mut ContextWriter, w_pre_cdef: &mut W, w_post_cdef: &mut W, |
2921 | 0 | bsize: BlockSize, tile_bo: TileBlockOffset, |
2922 | 0 | block_output: &Option<PartitionGroupParameters>, inter_cfg: &InterConfig, |
2923 | 0 | enc_stats: &mut EncoderStats, |
2924 | 0 | ) { |
2925 | 0 | if tile_bo.0.x >= ts.mi_width || tile_bo.0.y >= ts.mi_height { |
2926 | 0 | return; |
2927 | 0 | } |
2928 | 0 | let is_square = bsize.is_sqr(); |
2929 | 0 | let rdo_type = RDOType::PixelDistRealRate; |
2930 | 0 | let hbs = bsize.width_mi() / 2; |
2931 | 0 | let has_cols = tile_bo.0.x + hbs < ts.mi_width; |
2932 | 0 | let has_rows = tile_bo.0.y + hbs < ts.mi_height; |
2933 | 0 |
|
2934 | 0 | // TODO: Update for 128x128 superblocks |
2935 | 0 | debug_assert!(fi.partition_range.max <= BlockSize::BLOCK_64X64); |
2936 | | |
2937 | 0 | let must_split = |
2938 | 0 | is_square && (bsize > fi.partition_range.max || !has_cols || !has_rows); |
2939 | | |
2940 | 0 | let can_split = // FIXME: sub-8x8 inter blocks not supported for non-4:2:0 sampling |
2941 | 0 | if fi.frame_type.has_inter() && |
2942 | 0 | fi.sequence.chroma_sampling != ChromaSampling::Cs420 && |
2943 | 0 | bsize <= BlockSize::BLOCK_8X8 { |
2944 | 0 | false |
2945 | | } else { |
2946 | 0 | (bsize > fi.partition_range.min && is_square) || must_split |
2947 | | }; |
2948 | | |
2949 | 0 | let mut rdo_output = |
2950 | 0 | block_output.clone().unwrap_or_else(|| PartitionGroupParameters { |
2951 | 0 | part_type: PartitionType::PARTITION_INVALID, |
2952 | 0 | rd_cost: std::f64::MAX, |
2953 | 0 | part_modes: ArrayVec::new(), |
2954 | 0 | }); Unexecuted instantiation: rav1e::encoder::encode_partition_topdown::<u16, rav1e::ec::WriterBase<rav1e::ec::WriterRecorder>>::{closure#0} Unexecuted instantiation: rav1e::encoder::encode_partition_topdown::<u8, rav1e::ec::WriterBase<rav1e::ec::WriterRecorder>>::{closure#0} |
2955 | | |
2956 | 0 | let partition = if must_split { |
2957 | 0 | PartitionType::PARTITION_SPLIT |
2958 | 0 | } else if can_split { |
2959 | 0 | debug_assert!(bsize.is_sqr()); |
2960 | | |
2961 | | // Blocks of sizes within the supported range are subjected to a partitioning decision |
2962 | 0 | rdo_output = rdo_partition_decision( |
2963 | 0 | fi, |
2964 | 0 | ts, |
2965 | 0 | cw, |
2966 | 0 | w_pre_cdef, |
2967 | 0 | w_post_cdef, |
2968 | 0 | bsize, |
2969 | 0 | tile_bo, |
2970 | 0 | &rdo_output, |
2971 | 0 | &[PartitionType::PARTITION_SPLIT, PartitionType::PARTITION_NONE], |
2972 | 0 | rdo_type, |
2973 | 0 | inter_cfg, |
2974 | 0 | ); |
2975 | 0 | rdo_output.part_type |
2976 | | } else { |
2977 | | // Blocks of sizes below the supported range are encoded directly |
2978 | 0 | PartitionType::PARTITION_NONE |
2979 | | }; |
2980 | | |
2981 | 0 | debug_assert!(partition != PartitionType::PARTITION_INVALID); |
2982 | | |
2983 | 0 | let subsize = bsize.subsize(partition).unwrap(); |
2984 | 0 |
|
2985 | 0 | if bsize >= BlockSize::BLOCK_8X8 && is_square { |
2986 | 0 | let w: &mut W = if cw.bc.cdef_coded { w_post_cdef } else { w_pre_cdef }; |
2987 | 0 | cw.write_partition(w, tile_bo, partition, bsize); |
2988 | 0 | } |
2989 | | |
2990 | 0 | match partition { |
2991 | | PartitionType::PARTITION_NONE => { |
2992 | | let rdo_decision; |
2993 | 0 | let part_decision = |
2994 | 0 | if let Some(part_mode) = rdo_output.part_modes.first() { |
2995 | | // The optimal prediction mode is known from a previous iteration |
2996 | 0 | part_mode |
2997 | | } else { |
2998 | | // Make a prediction mode decision for blocks encoded with no rdo_partition_decision call (e.g. edges) |
2999 | 0 | rdo_decision = |
3000 | 0 | rdo_mode_decision(fi, ts, cw, bsize, tile_bo, inter_cfg); |
3001 | 0 | &rdo_decision |
3002 | | }; |
3003 | | |
3004 | 0 | let mut mode_luma = part_decision.pred_mode_luma; |
3005 | 0 | let mut mode_chroma = part_decision.pred_mode_chroma; |
3006 | 0 |
|
3007 | 0 | let cfl = part_decision.pred_cfl_params; |
3008 | 0 | let skip = part_decision.skip; |
3009 | 0 | let ref_frames = part_decision.ref_frames; |
3010 | 0 | let mvs = part_decision.mvs; |
3011 | 0 | let mut cdef_coded = cw.bc.cdef_coded; |
3012 | 0 |
|
3013 | 0 | // Set correct segmentation ID before encoding and before |
3014 | 0 | // rdo_tx_size_type(). |
3015 | 0 | cw.bc.blocks.set_segmentation_idx(tile_bo, bsize, part_decision.sidx); |
3016 | 0 |
|
3017 | 0 | // NOTE: Cannot avoid calling rdo_tx_size_type() here again, |
3018 | 0 | // because, with top-down partition RDO, the neighboring contexts |
3019 | 0 | // of current partition can change, i.e. neighboring partitions can split down more. |
3020 | 0 | let (tx_size, tx_type) = rdo_tx_size_type( |
3021 | 0 | fi, ts, cw, bsize, tile_bo, mode_luma, ref_frames, mvs, skip, |
3022 | 0 | ); |
3023 | 0 |
|
3024 | 0 | let mut mv_stack = ArrayVec::<CandidateMV, 9>::new(); |
3025 | 0 | let is_compound = ref_frames[1] != NONE_FRAME; |
3026 | 0 | let mode_context = cw.find_mvrefs( |
3027 | 0 | tile_bo, |
3028 | 0 | ref_frames, |
3029 | 0 | &mut mv_stack, |
3030 | 0 | bsize, |
3031 | 0 | fi, |
3032 | 0 | is_compound, |
3033 | 0 | ); |
3034 | 0 |
|
3035 | 0 | // TODO: proper remap when is_compound is true |
3036 | 0 | if !mode_luma.is_intra() { |
3037 | 0 | if is_compound && mode_luma != PredictionMode::GLOBAL_GLOBALMV { |
3038 | 0 | let match0 = mv_stack[0].this_mv.row == mvs[0].row |
3039 | 0 | && mv_stack[0].this_mv.col == mvs[0].col; |
3040 | 0 | let match1 = mv_stack[0].comp_mv.row == mvs[1].row |
3041 | 0 | && mv_stack[0].comp_mv.col == mvs[1].col; |
3042 | | |
3043 | 0 | let match2 = mv_stack[1].this_mv.row == mvs[0].row |
3044 | 0 | && mv_stack[1].this_mv.col == mvs[0].col; |
3045 | 0 | let match3 = mv_stack[1].comp_mv.row == mvs[1].row |
3046 | 0 | && mv_stack[1].comp_mv.col == mvs[1].col; |
3047 | | |
3048 | 0 | let match4 = mv_stack.len() > 2 && mv_stack[2].this_mv == mvs[0]; |
3049 | 0 | let match5 = mv_stack.len() > 2 && mv_stack[2].comp_mv == mvs[1]; |
3050 | | |
3051 | 0 | let match6 = mv_stack.len() > 3 && mv_stack[3].this_mv == mvs[0]; |
3052 | 0 | let match7 = mv_stack.len() > 3 && mv_stack[3].comp_mv == mvs[1]; |
3053 | | |
3054 | 0 | mode_luma = if match0 && match1 { |
3055 | 0 | PredictionMode::NEAREST_NEARESTMV |
3056 | 0 | } else if match2 && match3 { |
3057 | 0 | PredictionMode::NEAR_NEAR0MV |
3058 | 0 | } else if match4 && match5 { |
3059 | 0 | PredictionMode::NEAR_NEAR1MV |
3060 | 0 | } else if match6 && match7 { |
3061 | 0 | PredictionMode::NEAR_NEAR2MV |
3062 | 0 | } else if match0 { |
3063 | 0 | PredictionMode::NEAREST_NEWMV |
3064 | 0 | } else if match1 { |
3065 | 0 | PredictionMode::NEW_NEARESTMV |
3066 | | } else { |
3067 | 0 | PredictionMode::NEW_NEWMV |
3068 | | }; |
3069 | | |
3070 | 0 | if mode_luma != PredictionMode::NEAREST_NEARESTMV |
3071 | 0 | && mvs[0].row == 0 |
3072 | 0 | && mvs[0].col == 0 |
3073 | 0 | && mvs[1].row == 0 |
3074 | 0 | && mvs[1].col == 0 |
3075 | 0 | { |
3076 | 0 | mode_luma = PredictionMode::GLOBAL_GLOBALMV; |
3077 | 0 | } |
3078 | 0 | mode_chroma = mode_luma; |
3079 | 0 | } else if !is_compound && mode_luma != PredictionMode::GLOBALMV { |
3080 | 0 | mode_luma = PredictionMode::NEWMV; |
3081 | 0 | for (c, m) in mv_stack.iter().take(4).zip( |
3082 | 0 | [ |
3083 | 0 | PredictionMode::NEARESTMV, |
3084 | 0 | PredictionMode::NEAR0MV, |
3085 | 0 | PredictionMode::NEAR1MV, |
3086 | 0 | PredictionMode::NEAR2MV, |
3087 | 0 | ] |
3088 | 0 | .iter(), |
3089 | 0 | ) { |
3090 | 0 | if c.this_mv.row == mvs[0].row && c.this_mv.col == mvs[0].col { |
3091 | 0 | mode_luma = *m; |
3092 | 0 | } |
3093 | | } |
3094 | 0 | if mode_luma == PredictionMode::NEWMV |
3095 | 0 | && mvs[0].row == 0 |
3096 | 0 | && mvs[0].col == 0 |
3097 | | { |
3098 | 0 | mode_luma = if mv_stack.is_empty() { |
3099 | 0 | PredictionMode::NEARESTMV |
3100 | 0 | } else if mv_stack.len() == 1 { |
3101 | 0 | PredictionMode::NEAR0MV |
3102 | | } else { |
3103 | 0 | PredictionMode::GLOBALMV |
3104 | | }; |
3105 | 0 | } |
3106 | 0 | mode_chroma = mode_luma; |
3107 | 0 | } |
3108 | | |
3109 | 0 | save_block_motion( |
3110 | 0 | ts, |
3111 | 0 | part_decision.bsize, |
3112 | 0 | part_decision.bo, |
3113 | 0 | part_decision.ref_frames[0].to_index(), |
3114 | 0 | part_decision.mvs[0], |
3115 | 0 | ); |
3116 | 0 | } |
3117 | | |
3118 | | // FIXME: every final block that has gone through the RDO decision process is encoded twice |
3119 | | cdef_coded = encode_block_pre_cdef( |
3120 | 0 | &fi.sequence, |
3121 | 0 | ts, |
3122 | 0 | cw, |
3123 | 0 | if cdef_coded { w_post_cdef } else { w_pre_cdef }, |
3124 | 0 | bsize, |
3125 | 0 | tile_bo, |
3126 | 0 | skip, |
3127 | 0 | ); |
3128 | 0 | encode_block_post_cdef( |
3129 | 0 | fi, |
3130 | 0 | ts, |
3131 | 0 | cw, |
3132 | 0 | if cdef_coded { w_post_cdef } else { w_pre_cdef }, |
3133 | 0 | mode_luma, |
3134 | 0 | mode_chroma, |
3135 | 0 | part_decision.angle_delta, |
3136 | 0 | ref_frames, |
3137 | 0 | mvs, |
3138 | 0 | bsize, |
3139 | 0 | tile_bo, |
3140 | 0 | skip, |
3141 | 0 | cfl, |
3142 | 0 | tx_size, |
3143 | 0 | tx_type, |
3144 | 0 | mode_context, |
3145 | 0 | &mv_stack, |
3146 | 0 | RDOType::PixelDistRealRate, |
3147 | 0 | true, |
3148 | 0 | Some(enc_stats), |
3149 | | ); |
3150 | | } |
3151 | | PARTITION_SPLIT | PARTITION_HORZ | PARTITION_VERT => { |
3152 | 0 | if !rdo_output.part_modes.is_empty() { |
3153 | 0 | debug_assert!(can_split && !must_split); |
3154 | | |
3155 | | // The optimal prediction modes for each split block is known from an rdo_partition_decision() call |
3156 | 0 | for mode in rdo_output.part_modes { |
3157 | 0 | // Each block is subjected to a new splitting decision |
3158 | 0 | encode_partition_topdown( |
3159 | 0 | fi, |
3160 | 0 | ts, |
3161 | 0 | cw, |
3162 | 0 | w_pre_cdef, |
3163 | 0 | w_post_cdef, |
3164 | 0 | subsize, |
3165 | 0 | mode.bo, |
3166 | 0 | &Some(PartitionGroupParameters { |
3167 | 0 | rd_cost: mode.rd_cost, |
3168 | 0 | part_type: PartitionType::PARTITION_NONE, |
3169 | 0 | part_modes: [mode][..].try_into().unwrap(), |
3170 | 0 | }), |
3171 | 0 | inter_cfg, |
3172 | 0 | enc_stats, |
3173 | 0 | ); |
3174 | 0 | } |
3175 | | } else { |
3176 | 0 | debug_assert!(must_split); |
3177 | 0 | let hbsw = subsize.width_mi(); // Half the block size width in blocks |
3178 | 0 | let hbsh = subsize.height_mi(); // Half the block size height in blocks |
3179 | 0 | let four_partitions = [ |
3180 | 0 | tile_bo, |
3181 | 0 | TileBlockOffset(BlockOffset { |
3182 | 0 | x: tile_bo.0.x + hbsw, |
3183 | 0 | y: tile_bo.0.y, |
3184 | 0 | }), |
3185 | 0 | TileBlockOffset(BlockOffset { |
3186 | 0 | x: tile_bo.0.x, |
3187 | 0 | y: tile_bo.0.y + hbsh, |
3188 | 0 | }), |
3189 | 0 | TileBlockOffset(BlockOffset { |
3190 | 0 | x: tile_bo.0.x + hbsw, |
3191 | 0 | y: tile_bo.0.y + hbsh, |
3192 | 0 | }), |
3193 | 0 | ]; |
3194 | 0 | let partitions = get_sub_partitions(&four_partitions, partition); |
3195 | 0 |
|
3196 | 0 | partitions.iter().for_each(|&offset| { |
3197 | 0 | encode_partition_topdown( |
3198 | 0 | fi, |
3199 | 0 | ts, |
3200 | 0 | cw, |
3201 | 0 | w_pre_cdef, |
3202 | 0 | w_post_cdef, |
3203 | 0 | subsize, |
3204 | 0 | offset, |
3205 | 0 | &None, |
3206 | 0 | inter_cfg, |
3207 | 0 | enc_stats, |
3208 | 0 | ); |
3209 | 0 | }); Unexecuted instantiation: rav1e::encoder::encode_partition_topdown::<u16, rav1e::ec::WriterBase<rav1e::ec::WriterRecorder>>::{closure#1} Unexecuted instantiation: rav1e::encoder::encode_partition_topdown::<u8, rav1e::ec::WriterBase<rav1e::ec::WriterRecorder>>::{closure#1} |
3210 | 0 | } |
3211 | | } |
3212 | 0 | _ => unreachable!(), |
3213 | | } |
3214 | | |
3215 | 0 | if is_square |
3216 | 0 | && bsize >= BlockSize::BLOCK_8X8 |
3217 | 0 | && (bsize == BlockSize::BLOCK_8X8 |
3218 | 0 | || partition != PartitionType::PARTITION_SPLIT) |
3219 | 0 | { |
3220 | 0 | cw.bc.update_partition_context(tile_bo, subsize, bsize); |
3221 | 0 | } |
3222 | 0 | } Unexecuted instantiation: rav1e::encoder::encode_partition_topdown::<u16, rav1e::ec::WriterBase<rav1e::ec::WriterRecorder>> Unexecuted instantiation: rav1e::encoder::encode_partition_topdown::<u8, rav1e::ec::WriterBase<rav1e::ec::WriterRecorder>> |
3223 | | |
3224 | 0 | fn get_initial_cdfcontext<T: Pixel>(fi: &FrameInvariants<T>) -> CDFContext { |
3225 | 0 | let cdf = if fi.primary_ref_frame == PRIMARY_REF_NONE { |
3226 | 0 | None |
3227 | | } else { |
3228 | 0 | let ref_frame_idx = fi.ref_frames[fi.primary_ref_frame as usize] as usize; |
3229 | 0 | let ref_frame = fi.rec_buffer.frames[ref_frame_idx].as_ref(); |
3230 | 0 | ref_frame.map(|rec| rec.cdfs) Unexecuted instantiation: rav1e::encoder::get_initial_cdfcontext::<u16>::{closure#0} Unexecuted instantiation: rav1e::encoder::get_initial_cdfcontext::<u8>::{closure#0} |
3231 | | }; |
3232 | | |
3233 | | // return the retrieved instance if any, a new one otherwise |
3234 | 0 | cdf.unwrap_or_else(|| CDFContext::new(fi.base_q_idx)) Unexecuted instantiation: rav1e::encoder::get_initial_cdfcontext::<u16>::{closure#1} Unexecuted instantiation: rav1e::encoder::get_initial_cdfcontext::<u8>::{closure#1} |
3235 | 0 | } Unexecuted instantiation: rav1e::encoder::get_initial_cdfcontext::<u16> Unexecuted instantiation: rav1e::encoder::get_initial_cdfcontext::<u8> |
3236 | | |
3237 | 0 | #[profiling::function] Unexecuted instantiation: rav1e::encoder::encode_tile_group::<u16> Unexecuted instantiation: rav1e::encoder::encode_tile_group::<u8> |
3238 | | fn encode_tile_group<T: Pixel>( |
3239 | | fi: &FrameInvariants<T>, fs: &mut FrameState<T>, inter_cfg: &InterConfig, |
3240 | | ) -> Vec<u8> { |
3241 | | let planes = |
3242 | | if fi.sequence.chroma_sampling == ChromaSampling::Cs400 { 1 } else { 3 }; |
3243 | | let mut blocks = FrameBlocks::new(fi.w_in_b, fi.h_in_b); |
3244 | | let ti = &fi.sequence.tiling; |
3245 | | |
3246 | | let initial_cdf = get_initial_cdfcontext(fi); |
3247 | | // dynamic allocation: once per frame |
3248 | | let mut cdfs = vec![initial_cdf; ti.tile_count()]; |
3249 | | |
3250 | | let (raw_tiles, stats): (Vec<_>, Vec<_>) = ti |
3251 | | .tile_iter_mut(fs, &mut blocks) |
3252 | | .zip(cdfs.iter_mut()) |
3253 | | .collect::<Vec<_>>() |
3254 | | .into_par_iter() |
3255 | 0 | .map(|(mut ctx, cdf)| { |
3256 | 0 | encode_tile(fi, &mut ctx.ts, cdf, &mut ctx.tb, inter_cfg) |
3257 | 0 | }) Unexecuted instantiation: rav1e::encoder::encode_tile_group::<u16>::{closure#0} Unexecuted instantiation: rav1e::encoder::encode_tile_group::<u8>::{closure#0} |
3258 | | .unzip(); |
3259 | | |
3260 | | for tile_stats in stats { |
3261 | | fs.enc_stats += &tile_stats; |
3262 | | } |
3263 | | |
3264 | | /* Frame deblocking operates over a single large tile wrapping the |
3265 | | * frame rather than the frame itself so that deblocking is |
3266 | | * available inside RDO when needed */ |
3267 | | /* TODO: Don't apply if lossless */ |
3268 | 0 | let levels = fs.apply_tile_state_mut(|ts| { |
3269 | 0 | let rec = &mut ts.rec; |
3270 | 0 | deblock_filter_optimize( |
3271 | 0 | fi, |
3272 | 0 | &rec.as_const(), |
3273 | 0 | &ts.input.as_tile(), |
3274 | 0 | &blocks.as_tile_blocks(), |
3275 | 0 | fi.width, |
3276 | 0 | fi.height, |
3277 | 0 | ) |
3278 | 0 | }); Unexecuted instantiation: rav1e::encoder::encode_tile_group::<u16>::{closure#1} Unexecuted instantiation: rav1e::encoder::encode_tile_group::<u8>::{closure#1} |
3279 | | fs.deblock.levels = levels; |
3280 | | |
3281 | | if fs.deblock.levels[0] != 0 || fs.deblock.levels[1] != 0 { |
3282 | 0 | fs.apply_tile_state_mut(|ts| { |
3283 | 0 | let rec = &mut ts.rec; |
3284 | 0 | deblock_filter_frame( |
3285 | 0 | ts.deblock, |
3286 | 0 | rec, |
3287 | 0 | &blocks.as_tile_blocks(), |
3288 | 0 | fi.width, |
3289 | 0 | fi.height, |
3290 | 0 | fi.sequence.bit_depth, |
3291 | 0 | planes, |
3292 | 0 | ); |
3293 | 0 | }); Unexecuted instantiation: rav1e::encoder::encode_tile_group::<u16>::{closure#2} Unexecuted instantiation: rav1e::encoder::encode_tile_group::<u8>::{closure#2} |
3294 | | } |
3295 | | |
3296 | | if fi.sequence.enable_restoration { |
3297 | | // Until the loop filters are better pipelined, we'll need to keep |
3298 | | // around a copy of both the deblocked and cdeffed frame. |
3299 | | let deblocked_frame = (*fs.rec).clone(); |
3300 | | |
3301 | | /* TODO: Don't apply if lossless */ |
3302 | | if fi.sequence.enable_cdef { |
3303 | 0 | fs.apply_tile_state_mut(|ts| { |
3304 | 0 | let rec = &mut ts.rec; |
3305 | 0 | cdef_filter_tile(fi, &deblocked_frame, &blocks.as_tile_blocks(), rec); |
3306 | 0 | }); Unexecuted instantiation: rav1e::encoder::encode_tile_group::<u16>::{closure#3} Unexecuted instantiation: rav1e::encoder::encode_tile_group::<u8>::{closure#3} |
3307 | | } |
3308 | | /* TODO: Don't apply if lossless */ |
3309 | | fs.restoration.lrf_filter_frame( |
3310 | | Arc::get_mut(&mut fs.rec).unwrap(), |
3311 | | &deblocked_frame, |
3312 | | fi, |
3313 | | ); |
3314 | | } else { |
3315 | | /* TODO: Don't apply if lossless */ |
3316 | | if fi.sequence.enable_cdef { |
3317 | | let deblocked_frame = (*fs.rec).clone(); |
3318 | 0 | fs.apply_tile_state_mut(|ts| { |
3319 | 0 | let rec = &mut ts.rec; |
3320 | 0 | cdef_filter_tile(fi, &deblocked_frame, &blocks.as_tile_blocks(), rec); |
3321 | 0 | }); Unexecuted instantiation: rav1e::encoder::encode_tile_group::<u16>::{closure#4} Unexecuted instantiation: rav1e::encoder::encode_tile_group::<u8>::{closure#4} |
3322 | | } |
3323 | | } |
3324 | | |
3325 | | let (idx_max, max_len) = raw_tiles |
3326 | | .iter() |
3327 | | .map(Vec::len) |
3328 | | .enumerate() |
3329 | 0 | .max_by_key(|&(_, len)| len) Unexecuted instantiation: rav1e::encoder::encode_tile_group::<u16>::{closure#5} Unexecuted instantiation: rav1e::encoder::encode_tile_group::<u8>::{closure#5} |
3330 | | .unwrap(); |
3331 | | |
3332 | | if !fi.disable_frame_end_update_cdf { |
3333 | | // use the biggest tile (in bytes) for CDF update |
3334 | | fs.context_update_tile_id = idx_max; |
3335 | | fs.cdfs = cdfs[idx_max]; |
3336 | | fs.cdfs.reset_counts(); |
3337 | | } |
3338 | | |
3339 | | let max_tile_size_bytes = ((ILog::ilog(max_len) + 7) / 8) as u32; |
3340 | | debug_assert!(max_tile_size_bytes > 0 && max_tile_size_bytes <= 4); |
3341 | | fs.max_tile_size_bytes = max_tile_size_bytes; |
3342 | | |
3343 | | build_raw_tile_group(ti, &raw_tiles, max_tile_size_bytes) |
3344 | | } |
3345 | | |
3346 | 0 | fn build_raw_tile_group( |
3347 | 0 | ti: &TilingInfo, raw_tiles: &[Vec<u8>], max_tile_size_bytes: u32, |
3348 | 0 | ) -> Vec<u8> { |
3349 | 0 | // <https://aomediacodec.github.io/av1-spec/#general-tile-group-obu-syntax> |
3350 | 0 | let mut raw = Vec::new(); |
3351 | 0 | let mut bw = BitWriter::endian(&mut raw, BigEndian); |
3352 | 0 | if ti.cols * ti.rows > 1 { |
3353 | 0 | // tile_start_and_end_present_flag |
3354 | 0 | bw.write_bit(false).unwrap(); |
3355 | 0 | } |
3356 | 0 | bw.byte_align().unwrap(); |
3357 | 0 | for (i, raw_tile) in raw_tiles.iter().enumerate() { |
3358 | 0 | let last = raw_tiles.len() - 1; |
3359 | 0 | if i != last { |
3360 | 0 | let tile_size_minus_1 = raw_tile.len() - 1; |
3361 | 0 | bw.write_le(max_tile_size_bytes, tile_size_minus_1 as u64).unwrap(); |
3362 | 0 | } |
3363 | 0 | bw.write_bytes(raw_tile).unwrap(); |
3364 | | } |
3365 | 0 | raw |
3366 | 0 | } |
3367 | | |
3368 | | pub struct SBSQueueEntry { |
3369 | | pub sbo: TileSuperBlockOffset, |
3370 | | pub lru_index: [i32; MAX_PLANES], |
3371 | | pub cdef_coded: bool, |
3372 | | pub w_pre_cdef: WriterBase<WriterRecorder>, |
3373 | | pub w_post_cdef: WriterBase<WriterRecorder>, |
3374 | | } |
3375 | | |
3376 | 0 | #[profiling::function] Unexecuted instantiation: rav1e::encoder::check_lf_queue::<u16> Unexecuted instantiation: rav1e::encoder::check_lf_queue::<u8> |
3377 | | fn check_lf_queue<T: Pixel>( |
3378 | | fi: &FrameInvariants<T>, ts: &mut TileStateMut<'_, T>, |
3379 | | cw: &mut ContextWriter, w: &mut WriterBase<WriterEncoder>, |
3380 | | sbs_q: &mut VecDeque<SBSQueueEntry>, last_lru_ready: &mut [i32; 3], |
3381 | | last_lru_rdoed: &mut [i32; 3], last_lru_coded: &mut [i32; 3], |
3382 | | deblock_p: bool, |
3383 | | ) { |
3384 | | let mut check_queue = true; |
3385 | | let planes = if fi.sequence.chroma_sampling == ChromaSampling::Cs400 { |
3386 | | 1 |
3387 | | } else { |
3388 | | MAX_PLANES |
3389 | | }; |
3390 | | |
3391 | | // Walk queue from the head, see if anything is ready for RDO and flush |
3392 | | while check_queue { |
3393 | | if let Some(qe) = sbs_q.front_mut() { |
3394 | | for pli in 0..planes { |
3395 | | if qe.lru_index[pli] > last_lru_ready[pli] { |
3396 | | check_queue = false; |
3397 | | break; |
3398 | | } |
3399 | | } |
3400 | | if check_queue { |
3401 | | // yes, this entry is ready |
3402 | | if qe.cdef_coded || fi.sequence.enable_restoration { |
3403 | | // only RDO once for a given LRU. |
3404 | | |
3405 | | // One quirk worth noting: LRUs in different planes |
3406 | | // may be different sizes; eg, one chroma LRU may |
3407 | | // cover four luma LRUs. However, we won't get here |
3408 | | // until all are ready for RDO because the smaller |
3409 | | // ones all fit inside the biggest, and the biggest |
3410 | | // doesn't trigger until everything is done. |
3411 | | |
3412 | | // RDO happens on all LRUs within the confines of the |
3413 | | // biggest, all together. If any of this SB's planes' |
3414 | | // LRUs are RDOed, in actuality they all are. |
3415 | | |
3416 | | // SBs tagged with a lru index of -1 are ignored in |
3417 | | // LRU coding/rdoing decisions (but still need to rdo |
3418 | | // for cdef). |
3419 | | let mut already_rdoed = false; |
3420 | | for pli in 0..planes { |
3421 | | if qe.lru_index[pli] != -1 |
3422 | | && qe.lru_index[pli] <= last_lru_rdoed[pli] |
3423 | | { |
3424 | | already_rdoed = true; |
3425 | | break; |
3426 | | } |
3427 | | } |
3428 | | if !already_rdoed { |
3429 | | rdo_loop_decision(qe.sbo, fi, ts, cw, w, deblock_p); |
3430 | | for pli in 0..planes { |
3431 | | if qe.lru_index[pli] != -1 |
3432 | | && last_lru_rdoed[pli] < qe.lru_index[pli] |
3433 | | { |
3434 | | last_lru_rdoed[pli] = qe.lru_index[pli]; |
3435 | | } |
3436 | | } |
3437 | | } |
3438 | | } |
3439 | | // write LRF information |
3440 | | if !fi.allow_intrabc && fi.sequence.enable_restoration { |
3441 | | // TODO: also disallow if lossless |
3442 | | for pli in 0..planes { |
3443 | | if qe.lru_index[pli] != -1 |
3444 | | && last_lru_coded[pli] < qe.lru_index[pli] |
3445 | | { |
3446 | | last_lru_coded[pli] = qe.lru_index[pli]; |
3447 | | cw.write_lrf(w, &mut ts.restoration, qe.sbo, pli); |
3448 | | } |
3449 | | } |
3450 | | } |
3451 | | // Now that loop restoration is coded, we can replay the initial block bits |
3452 | | qe.w_pre_cdef.replay(w); |
3453 | | // Now code CDEF into the middle of the block |
3454 | | if qe.cdef_coded { |
3455 | | let cdef_index = cw.bc.blocks.get_cdef(qe.sbo); |
3456 | | cw.write_cdef(w, cdef_index, fi.cdef_bits); |
3457 | | // Code queued symbols that come after the CDEF index |
3458 | | qe.w_post_cdef.replay(w); |
3459 | | } |
3460 | | sbs_q.pop_front(); |
3461 | | } |
3462 | | } else { |
3463 | | check_queue = false; |
3464 | | } |
3465 | | } |
3466 | | } |
3467 | | |
3468 | 0 | #[profiling::function] Unexecuted instantiation: rav1e::encoder::encode_tile::<u16> Unexecuted instantiation: rav1e::encoder::encode_tile::<u8> |
3469 | | fn encode_tile<'a, T: Pixel>( |
3470 | | fi: &FrameInvariants<T>, ts: &'a mut TileStateMut<'_, T>, |
3471 | | fc: &'a mut CDFContext, blocks: &'a mut TileBlocksMut<'a>, |
3472 | | inter_cfg: &InterConfig, |
3473 | | ) -> (Vec<u8>, EncoderStats) { |
3474 | | let mut enc_stats = EncoderStats::default(); |
3475 | | let mut w = WriterEncoder::new(); |
3476 | | let planes = |
3477 | | if fi.sequence.chroma_sampling == ChromaSampling::Cs400 { 1 } else { 3 }; |
3478 | | |
3479 | | let bc = BlockContext::new(blocks); |
3480 | | let mut cw = ContextWriter::new(fc, bc); |
3481 | | let mut sbs_q: VecDeque<SBSQueueEntry> = VecDeque::new(); |
3482 | | let mut last_lru_ready = [-1; 3]; |
3483 | | let mut last_lru_rdoed = [-1; 3]; |
3484 | | let mut last_lru_coded = [-1; 3]; |
3485 | | |
3486 | | // main loop |
3487 | | for sby in 0..ts.sb_height { |
3488 | | cw.bc.reset_left_contexts(planes); |
3489 | | |
3490 | | for sbx in 0..ts.sb_width { |
3491 | | cw.fc_log.clear(); |
3492 | | |
3493 | | let tile_sbo = TileSuperBlockOffset(SuperBlockOffset { x: sbx, y: sby }); |
3494 | | let mut sbs_qe = SBSQueueEntry { |
3495 | | sbo: tile_sbo, |
3496 | | lru_index: [-1; MAX_PLANES], |
3497 | | cdef_coded: false, |
3498 | | w_pre_cdef: WriterRecorder::new(), |
3499 | | w_post_cdef: WriterRecorder::new(), |
3500 | | }; |
3501 | | |
3502 | | let tile_bo = tile_sbo.block_offset(0, 0); |
3503 | | cw.bc.cdef_coded = false; |
3504 | | cw.bc.code_deltas = fi.delta_q_present; |
3505 | | |
3506 | | let is_straddle_sbx = |
3507 | | tile_bo.0.x + BlockSize::BLOCK_64X64.width_mi() > ts.mi_width; |
3508 | | let is_straddle_sby = |
3509 | | tile_bo.0.y + BlockSize::BLOCK_64X64.height_mi() > ts.mi_height; |
3510 | | |
3511 | | // Encode SuperBlock |
3512 | | if fi.config.speed_settings.partition.encode_bottomup |
3513 | | || is_straddle_sbx |
3514 | | || is_straddle_sby |
3515 | | { |
3516 | | encode_partition_bottomup( |
3517 | | fi, |
3518 | | ts, |
3519 | | &mut cw, |
3520 | | &mut sbs_qe.w_pre_cdef, |
3521 | | &mut sbs_qe.w_post_cdef, |
3522 | | BlockSize::BLOCK_64X64, |
3523 | | tile_bo, |
3524 | | std::f64::MAX, |
3525 | | inter_cfg, |
3526 | | &mut enc_stats, |
3527 | | ); |
3528 | | } else { |
3529 | | encode_partition_topdown( |
3530 | | fi, |
3531 | | ts, |
3532 | | &mut cw, |
3533 | | &mut sbs_qe.w_pre_cdef, |
3534 | | &mut sbs_qe.w_post_cdef, |
3535 | | BlockSize::BLOCK_64X64, |
3536 | | tile_bo, |
3537 | | &None, |
3538 | | inter_cfg, |
3539 | | &mut enc_stats, |
3540 | | ); |
3541 | | } |
3542 | | |
3543 | | { |
3544 | | let mut check_queue = false; |
3545 | | // queue our superblock for when the LRU is complete |
3546 | | sbs_qe.cdef_coded = cw.bc.cdef_coded; |
3547 | | for pli in 0..planes { |
3548 | | if let Some((lru_x, lru_y)) = |
3549 | | ts.restoration.planes[pli].restoration_unit_index(tile_sbo, false) |
3550 | | { |
3551 | | let lru_index = ts.restoration.planes[pli] |
3552 | | .restoration_unit_countable(lru_x, lru_y) |
3553 | | as i32; |
3554 | | sbs_qe.lru_index[pli] = lru_index; |
3555 | | if ts.restoration.planes[pli] |
3556 | | .restoration_unit_last_sb_for_rdo(fi, ts.sbo, tile_sbo) |
3557 | | { |
3558 | | last_lru_ready[pli] = lru_index; |
3559 | | check_queue = true; |
3560 | | } |
3561 | | } else { |
3562 | | // we're likely in an area stretched into a new tile |
3563 | | // tag this SB to be ignored in LRU decisions |
3564 | | sbs_qe.lru_index[pli] = -1; |
3565 | | check_queue = true; |
3566 | | } |
3567 | | } |
3568 | | sbs_q.push_back(sbs_qe); |
3569 | | |
3570 | | if check_queue && !fi.sequence.enable_delayed_loopfilter_rdo { |
3571 | | check_lf_queue( |
3572 | | fi, |
3573 | | ts, |
3574 | | &mut cw, |
3575 | | &mut w, |
3576 | | &mut sbs_q, |
3577 | | &mut last_lru_ready, |
3578 | | &mut last_lru_rdoed, |
3579 | | &mut last_lru_coded, |
3580 | | true, |
3581 | | ); |
3582 | | } |
3583 | | } |
3584 | | } |
3585 | | } |
3586 | | |
3587 | | if fi.sequence.enable_delayed_loopfilter_rdo { |
3588 | | // Solve deblocking for just this tile |
3589 | | /* TODO: Don't apply if lossless */ |
3590 | | let deblock_levels = deblock_filter_optimize( |
3591 | | fi, |
3592 | | &ts.rec.as_const(), |
3593 | | &ts.input_tile, |
3594 | | &cw.bc.blocks.as_const(), |
3595 | | fi.width, |
3596 | | fi.height, |
3597 | | ); |
3598 | | |
3599 | | if deblock_levels[0] != 0 || deblock_levels[1] != 0 { |
3600 | | // copy reconstruction to a temp frame to restore it later |
3601 | | let rec_copy = if planes == 3 { |
3602 | | vec![ |
3603 | | ts.rec.planes[0].scratch_copy(), |
3604 | | ts.rec.planes[1].scratch_copy(), |
3605 | | ts.rec.planes[2].scratch_copy(), |
3606 | | ] |
3607 | | } else { |
3608 | | vec![ts.rec.planes[0].scratch_copy()] |
3609 | | }; |
3610 | | |
3611 | | // copy ts.deblock because we need to set some of our own values here |
3612 | | let mut deblock_copy = *ts.deblock; |
3613 | | deblock_copy.levels = deblock_levels; |
3614 | | |
3615 | | // temporarily deblock the reference |
3616 | | deblock_filter_frame( |
3617 | | &deblock_copy, |
3618 | | &mut ts.rec, |
3619 | | &cw.bc.blocks.as_const(), |
3620 | | fi.width, |
3621 | | fi.height, |
3622 | | fi.sequence.bit_depth, |
3623 | | planes, |
3624 | | ); |
3625 | | |
3626 | | // rdo lf and write |
3627 | | check_lf_queue( |
3628 | | fi, |
3629 | | ts, |
3630 | | &mut cw, |
3631 | | &mut w, |
3632 | | &mut sbs_q, |
3633 | | &mut last_lru_ready, |
3634 | | &mut last_lru_rdoed, |
3635 | | &mut last_lru_coded, |
3636 | | false, |
3637 | | ); |
3638 | | |
3639 | | // copy original reference back in |
3640 | | for pli in 0..planes { |
3641 | | let dst = &mut ts.rec.planes[pli]; |
3642 | | let src = &rec_copy[pli]; |
3643 | | for (dst_row, src_row) in dst.rows_iter_mut().zip(src.rows_iter()) { |
3644 | | for (out, input) in dst_row.iter_mut().zip(src_row) { |
3645 | | *out = *input; |
3646 | | } |
3647 | | } |
3648 | | } |
3649 | | } else { |
3650 | | // rdo lf and write |
3651 | | check_lf_queue( |
3652 | | fi, |
3653 | | ts, |
3654 | | &mut cw, |
3655 | | &mut w, |
3656 | | &mut sbs_q, |
3657 | | &mut last_lru_ready, |
3658 | | &mut last_lru_rdoed, |
3659 | | &mut last_lru_coded, |
3660 | | false, |
3661 | | ); |
3662 | | } |
3663 | | } |
3664 | | |
3665 | | assert!( |
3666 | | sbs_q.is_empty(), |
3667 | | "Superblock queue not empty in tile at offset {}:{}", |
3668 | | ts.sbo.0.x, |
3669 | | ts.sbo.0.y |
3670 | | ); |
3671 | | (w.done(), enc_stats) |
3672 | | } |
3673 | | |
3674 | | #[allow(unused)] |
3675 | 0 | fn write_tile_group_header(tile_start_and_end_present_flag: bool) -> Vec<u8> { |
3676 | 0 | let mut buf = Vec::new(); |
3677 | 0 | { |
3678 | 0 | let mut bw = BitWriter::endian(&mut buf, BigEndian); |
3679 | 0 | bw.write_bit(tile_start_and_end_present_flag).unwrap(); |
3680 | 0 | bw.byte_align().unwrap(); |
3681 | 0 | } |
3682 | 0 | buf |
3683 | 0 | } |
3684 | | |
3685 | | /// Write a packet containing only the placeholder that tells the decoder |
3686 | | /// to present the already decoded frame present at `frame_to_show_map_idx` |
3687 | | /// |
3688 | | /// See `av1-spec` Section 6.8.2 and 7.18. |
3689 | | /// |
3690 | | /// # Panics |
3691 | | /// |
3692 | | /// - If the frame packets cannot be written |
3693 | 0 | #[profiling::function] Unexecuted instantiation: rav1e::encoder::encode_show_existing_frame::<u16> Unexecuted instantiation: rav1e::encoder::encode_show_existing_frame::<u8> |
3694 | | pub fn encode_show_existing_frame<T: Pixel>( |
3695 | | fi: &FrameInvariants<T>, fs: &mut FrameState<T>, inter_cfg: &InterConfig, |
3696 | | ) -> Vec<u8> { |
3697 | | debug_assert!(fi.is_show_existing_frame()); |
3698 | | let obu_extension = 0; |
3699 | | |
3700 | | let mut packet = Vec::new(); |
3701 | | |
3702 | | if fi.frame_type == FrameType::KEY { |
3703 | | write_key_frame_obus(&mut packet, fi, obu_extension).unwrap(); |
3704 | | } |
3705 | | |
3706 | | for t35 in fi.t35_metadata.iter() { |
3707 | | let mut t35_buf = Vec::new(); |
3708 | | let mut t35_bw = BitWriter::endian(&mut t35_buf, BigEndian); |
3709 | | t35_bw.write_t35_metadata_obu(t35).unwrap(); |
3710 | | packet.write_all(&t35_buf).unwrap(); |
3711 | | t35_buf.clear(); |
3712 | | } |
3713 | | |
3714 | | let mut buf1 = Vec::new(); |
3715 | | let mut buf2 = Vec::new(); |
3716 | | { |
3717 | | let mut bw2 = BitWriter::endian(&mut buf2, BigEndian); |
3718 | | bw2.write_frame_header_obu(fi, fs, inter_cfg).unwrap(); |
3719 | | } |
3720 | | |
3721 | | { |
3722 | | let mut bw1 = BitWriter::endian(&mut buf1, BigEndian); |
3723 | | bw1.write_obu_header(ObuType::OBU_FRAME_HEADER, obu_extension).unwrap(); |
3724 | | } |
3725 | | packet.write_all(&buf1).unwrap(); |
3726 | | buf1.clear(); |
3727 | | |
3728 | | { |
3729 | | let mut bw1 = BitWriter::endian(&mut buf1, BigEndian); |
3730 | | bw1.write_uleb128(buf2.len() as u64).unwrap(); |
3731 | | } |
3732 | | packet.write_all(&buf1).unwrap(); |
3733 | | buf1.clear(); |
3734 | | |
3735 | | packet.write_all(&buf2).unwrap(); |
3736 | | buf2.clear(); |
3737 | | |
3738 | | let map_idx = fi.frame_to_show_map_idx as usize; |
3739 | | if let Some(ref rec) = fi.rec_buffer.frames[map_idx] { |
3740 | | let fs_rec = Arc::get_mut(&mut fs.rec).unwrap(); |
3741 | | let planes = |
3742 | | if fi.sequence.chroma_sampling == ChromaSampling::Cs400 { 1 } else { 3 }; |
3743 | | for p in 0..planes { |
3744 | | fs_rec.planes[p].data.copy_from_slice(&rec.frame.planes[p].data); |
3745 | | } |
3746 | | } |
3747 | | packet |
3748 | | } |
3749 | | |
3750 | 0 | fn get_initial_segmentation<T: Pixel>( |
3751 | 0 | fi: &FrameInvariants<T>, |
3752 | 0 | ) -> SegmentationState { |
3753 | 0 | let segmentation = if fi.primary_ref_frame == PRIMARY_REF_NONE { |
3754 | 0 | None |
3755 | | } else { |
3756 | 0 | let ref_frame_idx = fi.ref_frames[fi.primary_ref_frame as usize] as usize; |
3757 | 0 | let ref_frame = fi.rec_buffer.frames[ref_frame_idx].as_ref(); |
3758 | 0 | ref_frame.map(|rec| rec.segmentation) Unexecuted instantiation: rav1e::encoder::get_initial_segmentation::<u16>::{closure#0} Unexecuted instantiation: rav1e::encoder::get_initial_segmentation::<u8>::{closure#0} |
3759 | | }; |
3760 | | |
3761 | | // return the retrieved instance if any, a new one otherwise |
3762 | 0 | segmentation.unwrap_or_default() |
3763 | 0 | } Unexecuted instantiation: rav1e::encoder::get_initial_segmentation::<u16> Unexecuted instantiation: rav1e::encoder::get_initial_segmentation::<u8> |
3764 | | |
3765 | | /// # Panics |
3766 | | /// |
3767 | | /// - If the frame packets cannot be written |
3768 | 0 | #[profiling::function] Unexecuted instantiation: rav1e::encoder::encode_frame::<u16> Unexecuted instantiation: rav1e::encoder::encode_frame::<u8> |
3769 | | pub fn encode_frame<T: Pixel>( |
3770 | | fi: &FrameInvariants<T>, fs: &mut FrameState<T>, inter_cfg: &InterConfig, |
3771 | | ) -> Vec<u8> { |
3772 | | debug_assert!(!fi.is_show_existing_frame()); |
3773 | | let obu_extension = 0; |
3774 | | |
3775 | | let mut packet = Vec::new(); |
3776 | | |
3777 | | if fi.enable_segmentation { |
3778 | | fs.segmentation = get_initial_segmentation(fi); |
3779 | | segmentation_optimize(fi, fs); |
3780 | | } |
3781 | | let tile_group = encode_tile_group(fi, fs, inter_cfg); |
3782 | | |
3783 | | if fi.frame_type == FrameType::KEY { |
3784 | | write_key_frame_obus(&mut packet, fi, obu_extension).unwrap(); |
3785 | | } |
3786 | | |
3787 | | for t35 in fi.t35_metadata.iter() { |
3788 | | let mut t35_buf = Vec::new(); |
3789 | | let mut t35_bw = BitWriter::endian(&mut t35_buf, BigEndian); |
3790 | | t35_bw.write_t35_metadata_obu(t35).unwrap(); |
3791 | | packet.write_all(&t35_buf).unwrap(); |
3792 | | t35_buf.clear(); |
3793 | | } |
3794 | | |
3795 | | let mut buf1 = Vec::new(); |
3796 | | let mut buf2 = Vec::new(); |
3797 | | { |
3798 | | let mut bw2 = BitWriter::endian(&mut buf2, BigEndian); |
3799 | | bw2.write_frame_header_obu(fi, fs, inter_cfg).unwrap(); |
3800 | | } |
3801 | | |
3802 | | { |
3803 | | let mut bw1 = BitWriter::endian(&mut buf1, BigEndian); |
3804 | | bw1.write_obu_header(ObuType::OBU_FRAME, obu_extension).unwrap(); |
3805 | | } |
3806 | | packet.write_all(&buf1).unwrap(); |
3807 | | buf1.clear(); |
3808 | | |
3809 | | { |
3810 | | let mut bw1 = BitWriter::endian(&mut buf1, BigEndian); |
3811 | | bw1.write_uleb128((buf2.len() + tile_group.len()) as u64).unwrap(); |
3812 | | } |
3813 | | packet.write_all(&buf1).unwrap(); |
3814 | | buf1.clear(); |
3815 | | |
3816 | | packet.write_all(&buf2).unwrap(); |
3817 | | buf2.clear(); |
3818 | | |
3819 | | packet.write_all(&tile_group).unwrap(); |
3820 | | packet |
3821 | | } |
3822 | | |
3823 | 0 | pub fn update_rec_buffer<T: Pixel>( |
3824 | 0 | output_frameno: u64, fi: &mut FrameInvariants<T>, fs: &FrameState<T>, |
3825 | 0 | ) { |
3826 | 0 | let rfs = Arc::new(ReferenceFrame { |
3827 | 0 | order_hint: fi.order_hint, |
3828 | 0 | width: fi.width as u32, |
3829 | 0 | height: fi.height as u32, |
3830 | 0 | render_width: fi.render_width, |
3831 | 0 | render_height: fi.render_height, |
3832 | 0 | frame: fs.rec.clone(), |
3833 | 0 | input_hres: fs.input_hres.clone(), |
3834 | 0 | input_qres: fs.input_qres.clone(), |
3835 | 0 | cdfs: fs.cdfs, |
3836 | 0 | frame_me_stats: fs.frame_me_stats.clone(), |
3837 | 0 | output_frameno, |
3838 | 0 | segmentation: fs.segmentation, |
3839 | 0 | }); |
3840 | 0 | for i in 0..REF_FRAMES { |
3841 | 0 | if (fi.refresh_frame_flags & (1 << i)) != 0 { |
3842 | 0 | fi.rec_buffer.frames[i] = Some(Arc::clone(&rfs)); |
3843 | 0 | fi.rec_buffer.deblock[i] = fs.deblock; |
3844 | 0 | } |
3845 | | } |
3846 | 0 | } Unexecuted instantiation: rav1e::encoder::update_rec_buffer::<u16> Unexecuted instantiation: rav1e::encoder::update_rec_buffer::<u8> |
3847 | | |
3848 | | #[cfg(test)] |
3849 | | mod test { |
3850 | | use super::*; |
3851 | | |
3852 | | #[test] |
3853 | | fn check_partition_types_order() { |
3854 | | assert_eq!( |
3855 | | RAV1E_PARTITION_TYPES[RAV1E_PARTITION_TYPES.len() - 1], |
3856 | | PartitionType::PARTITION_SPLIT |
3857 | | ); |
3858 | | } |
3859 | | } |