Commit a1d24bae45 for aom
commit a1d24bae455a25fc30a3a738a5347711af49a9c3
Author: Marco Paniconi <marpan@google.com>
Date: Fri Dec 19 08:56:45 2025 -0800
Source content analysis for one_pass_rt_lag encoding
For the one_pass realtime with lookahead encoding mode:
add source analysis processing of frames in lookahead buffer,
for adjusting the gop parameters. Usage of this feature
will be in subsequent CL.
Also fix speed feature setting for source_sad usage.
Change-Id: I5d20b35848cf60d86e65364fc50a269029889b6f
diff --git a/av1/encoder/pass2_strategy.c b/av1/encoder/pass2_strategy.c
index b0d6db4715..202ebaeead 100644
--- a/av1/encoder/pass2_strategy.c
+++ b/av1/encoder/pass2_strategy.c
@@ -3808,6 +3808,31 @@ static void get_one_pass_rt_lag_params(AV1_COMP *cpi, unsigned int frame_flags,
: MAX_GF_LENGTH_LAP;
// Limit the max gop length for the last gop in 1 pass setting.
max_gop_length = AOMMIN(max_gop_length, rc->frames_to_key);
+ // Go through source frames in lookahead buffer and compute source metrics:
+ // scene change, frame average source sad, etc.
+ for (int i = 1; i < max_gop_length; i++) {
+ EncodeFrameInput frame_input;
+ memset(&frame_input, 0, sizeof(frame_input));
+ struct lookahead_entry *e =
+ av1_lookahead_peek(cpi->ppi->lookahead, i, cpi->compressor_stage);
+ struct lookahead_entry *e_prev =
+ av1_lookahead_peek(cpi->ppi->lookahead, i - 1, cpi->compressor_stage);
+ if (e != NULL && e_prev != NULL) {
+ frame_input.source = &e->img;
+ frame_input.last_source = &e_prev->img;
+ rc->high_source_sad_lag[i] = -1;
+ rc->frame_source_sad_lag[i] = 0;
+ rc->avg_source_sad = 0;
+ av1_rc_scene_detection_onepass_rt(cpi, &frame_input);
+ rc->high_source_sad_lag[i] = rc->high_source_sad;
+ rc->frame_source_sad_lag[i] = rc->frame_source_sad;
+ // Use rc->high_source_sad_lag[i] and frame_source_sad_lag[i] to
+ // adjust/adapt the gop parameters. Reset the parameters for the
+ // encoding.
+ rc->high_source_sad = 0;
+ rc->frame_source_sad = UINT64_MAX;
+ }
+ }
calculate_gf_length(cpi, max_gop_length, MAX_NUM_GF_INTERVALS);
define_gf_group(cpi, frame_params, 0);
rc->frames_till_gf_update_due = p_rc->baseline_gf_interval;
diff --git a/av1/encoder/ratectrl.c b/av1/encoder/ratectrl.c
index 99d25049d4..8e09f0f043 100644
--- a/av1/encoder/ratectrl.c
+++ b/av1/encoder/ratectrl.c
@@ -3159,21 +3159,8 @@ static unsigned int estimate_scroll_motion(
return best_sad;
}
-/*!\brief Check for scene detection, for 1 pass real-time mode.
- *
- * Compute average source sad (temporal sad: between current source and
- * previous source) over a subset of superblocks. Use this is detect big changes
- * in content and set the \c cpi->rc.high_source_sad flag.
- *
- * \ingroup rate_control
- * \param[in] cpi Top level encoder structure
- * \param[in] frame_input Current and last input source frames
- *
- * \remark Nothing is returned. Instead the flag \c cpi->rc.high_source_sad
- * is set if scene change is detected, and \c cpi->rc.avg_source_sad is updated.
- */
-static void rc_scene_detection_onepass_rt(AV1_COMP *cpi,
- const EncodeFrameInput *frame_input) {
+void av1_rc_scene_detection_onepass_rt(AV1_COMP *cpi,
+ const EncodeFrameInput *frame_input) {
AV1_COMMON *const cm = &cpi->common;
RATE_CONTROL *const rc = &cpi->rc;
YV12_BUFFER_CONFIG const *const unscaled_src = frame_input->source;
@@ -3265,7 +3252,7 @@ static void rc_scene_detection_onepass_rt(AV1_COMP *cpi,
rc->prev_frame_is_dropped || cpi->svc.number_temporal_layers > 1;
// Store blkwise SAD for later use. Disable for spatial layers for now.
if (width == cm->render_width && height == cm->render_height &&
- cpi->svc.number_spatial_layers == 1) {
+ cpi->svc.number_spatial_layers == 1 && !is_one_pass_rt_lag_params(cpi)) {
if (cpi->src_sad_blk_64x64 == NULL) {
CHECK_MEM_ERROR(cm, cpi->src_sad_blk_64x64,
(uint64_t *)aom_calloc(sb_cols * sb_rows,
@@ -3354,7 +3341,7 @@ static void rc_scene_detection_onepass_rt(AV1_COMP *cpi,
const uint64_t thresh_high_motion = scale * 64 * 64;
if (cpi->svc.temporal_layer_id == 0 && rc->drop_count_consec < 3) {
cpi->rc.high_motion_content_screen_rtc = 0;
- if (cpi->oxcf.speed >= 11 &&
+ if (cpi->oxcf.speed >= 11 && !is_one_pass_rt_lag_params(cpi) &&
cpi->oxcf.tune_cfg.content == AOM_CONTENT_SCREEN &&
rc->num_col_blscroll_last_tl0 < 5 &&
rc->num_row_blscroll_last_tl0 < 5 &&
@@ -3833,7 +3820,7 @@ void av1_get_one_pass_rt_params(AV1_COMP *cpi, FRAME_TYPE *const frame_type,
svc->spatial_layer_id == 0) {
if (rc->prev_coded_width == cm->width &&
rc->prev_coded_height == cm->height) {
- rc_scene_detection_onepass_rt(cpi, frame_input);
+ av1_rc_scene_detection_onepass_rt(cpi, frame_input);
} else {
aom_free(cpi->src_sad_blk_64x64);
cpi->src_sad_blk_64x64 = NULL;
diff --git a/av1/encoder/ratectrl.h b/av1/encoder/ratectrl.h
index cd376bacf9..4d6ef52bea 100644
--- a/av1/encoder/ratectrl.h
+++ b/av1/encoder/ratectrl.h
@@ -190,10 +190,20 @@ typedef struct {
int sframe_due;
int high_source_sad;
+ /*!
+ * The high_source_sad flag, which indicates scene change, for each frame [i]
+ * in the lookahead buffer, used for the encoding mode: is_one_pass_rt_lag.
+ */
+ int high_source_sad_lag[MAX_GF_INTERVAL];
int high_motion_content_screen_rtc;
uint64_t avg_source_sad;
uint64_t prev_avg_source_sad;
uint64_t frame_source_sad;
+ /*!
+ * The frame source sad for each frame [i] in the lookahead buffer,
+ * used for the encoding mode: is_one_pass_rt_lag.
+ */
+ uint64_t frame_source_sad_lag[MAX_GF_INTERVAL];
unsigned int last_frame_low_source_sad;
uint64_t frame_spatial_variance;
int static_since_last_scene_change;
@@ -831,6 +841,22 @@ int av1_encodedframe_overshoot_cbr(struct AV1_COMP *cpi, int *q);
*/
int av1_postencode_drop_cbr(struct AV1_COMP *cpi, size_t *size);
+/*!\brief Check for scene detection, for 1 pass real-time mode.
+ *
+ * Compute average source sad (temporal sad: between current source and
+ * previous source) over a subset of superblocks. Use this is detect big changes
+ * in content and set the \c cpi->rc.high_source_sad flag.
+ *
+ * \ingroup rate_control
+ * \param[in] cpi Top level encoder structure
+ * \param[in] frame_input Current and last input source frames
+ *
+ * \remark Nothing is returned. Instead the flag \c cpi->rc.high_source_sad
+ * is set if scene change is detected, and \c cpi->rc.avg_source_sad is updated.
+ */
+void av1_rc_scene_detection_onepass_rt(
+ struct AV1_COMP *cpi, const struct EncodeFrameInput *frame_input);
+
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/av1/encoder/speed_features.c b/av1/encoder/speed_features.c
index 3d9833a647..bd35d8b5ae 100644
--- a/av1/encoder/speed_features.c
+++ b/av1/encoder/speed_features.c
@@ -1839,6 +1839,11 @@ static void set_rt_speed_feature_framesize_dependent(const AV1_COMP *const cpi,
sf->rt_sf.set_zeromv_skip_based_on_source_sad = 0;
if (is_one_pass_rt_lag_params(cpi)) {
+ const RefreshFrameInfo *const refresh_frame = &cpi->refresh_frame;
+ if (refresh_frame->alt_ref_frame) {
+ sf->rt_sf.source_metrics_sb_nonrd = 0;
+ sf->rt_sf.var_part_based_on_qidx = 0;
+ }
sf->rt_sf.use_nonrd_altref_frame = 1;
// For non-zero lag: disable the 3 speed features below for now,
// until further testing.