Commit d50b000ac8 for aom
commit d50b000ac8e16c7bdb2dd5ea2ea98dd2f63c3907
Author: Bohan Li <bohanli@google.com>
Date: Thu May 28 13:14:07 2026 -0700
Store tpl recon of last ARF
- Store the tpl recon of last ARF. Used for ext rc to find propagation to prev arf.
- Fix src buffer condition of last ARF. It should use gf_group->display_idx consistently.
- In tpl process, if a frame wants to refer to previous GOP's ref frames, they can only use the previous ARF frame.
Primarily intended for ext RC. Shows slight gains for libaom RC in q mode speed 2.
See results at: http://shortn/_y5vuPIozhv
STATS_CHANGED
Change-Id: Ic06670f5a4df217f84596c597f3811c44ef9c5a6
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index 07ef75b615..878075f820 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -1761,6 +1761,7 @@ void av1_remove_primary_compressor(AV1_PRIMARY *ppi) {
aom_free(tpl_data->tpl_stats_pool[frame]);
aom_free_frame_buffer(&tpl_data->tpl_rec_pool[frame]);
aom_free_frame_buffer(&tpl_data->prev_gop_arf_src);
+ aom_free_frame_buffer(&tpl_data->prev_gop_arf_tpl_recon);
tpl_data->prev_gop_arf_disp_order = -1;
tpl_data->tpl_stats_pool[frame] = NULL;
}
@@ -4573,16 +4574,18 @@ int av1_encode(AV1_COMP *const cpi, uint8_t *const dest, size_t dest_size,
cpi->ppi->gf_group.layer_depth[cpi->gf_frame_index],
current_frame->display_order_hint, cpi->ppi->gf_group.max_layer_depth);
+#if !CONFIG_REALTIME_ONLY
const GF_GROUP *gf_group = &cpi->ppi->gf_group;
// Check if this is the last frame in the gop. If so, make a copy of the
// source for TPL.
if (cpi->oxcf.algo_cfg.enable_tpl_model &&
+ av1_tpl_stats_ready(&cpi->ppi->tpl_data, cpi->gf_frame_index) &&
gf_group->update_type[cpi->gf_frame_index] != OVERLAY_UPDATE &&
gf_group->update_type[cpi->gf_frame_index] != INTNL_OVERLAY_UPDATE) {
int is_last = 1;
for (int i = 0; i < gf_group->size; ++i) {
if (gf_group->display_idx[i] >
- (int64_t)current_frame->display_order_hint) {
+ gf_group->display_idx[cpi->gf_frame_index]) {
is_last = 0;
break;
}
@@ -4590,6 +4593,7 @@ int av1_encode(AV1_COMP *const cpi, uint8_t *const dest, size_t dest_size,
if (is_last) {
cpi->ppi->tpl_data.prev_gop_arf_disp_order = -1;
const AV1EncoderConfig *const oxcf = &cpi->oxcf;
+ int available = 1;
int ret = aom_realloc_frame_buffer(
&cpi->ppi->tpl_data.prev_gop_arf_src, oxcf->frm_dim_cfg.width,
oxcf->frm_dim_cfg.height, cm->seq_params->subsampling_x,
@@ -4600,19 +4604,53 @@ int av1_encode(AV1_COMP *const cpi, uint8_t *const dest, size_t dest_size,
aom_internal_error(cm->error, AOM_CODEC_MEM_ERROR,
"Failed to allocate tpl prev_gop_arf_src buf.");
- // Currently it is not supported if source/refernece is resized.
+ // Currently it is not supported if source/reference is resized.
if (cpi->source->y_width == cpi->ppi->tpl_data.prev_gop_arf_src.y_width &&
cpi->source->y_height ==
cpi->ppi->tpl_data.prev_gop_arf_src.y_height) {
// Copy the content from source to this buffer for next gop.
aom_yv12_copy_frame(cpi->source, &cpi->ppi->tpl_data.prev_gop_arf_src,
av1_num_planes(cm));
+ } else {
+ available = 0;
+ }
+ ret = aom_realloc_frame_buffer(
+ &cpi->ppi->tpl_data.prev_gop_arf_tpl_recon, oxcf->frm_dim_cfg.width,
+ oxcf->frm_dim_cfg.height, cm->seq_params->subsampling_x,
+ cm->seq_params->subsampling_y, cm->seq_params->use_highbitdepth,
+ cpi->oxcf.border_in_pixels, cm->features.byte_alignment, NULL, NULL,
+ NULL, cpi->alloc_pyramid, 0);
+ if (ret)
+ aom_internal_error(
+ cm->error, AOM_CODEC_MEM_ERROR,
+ "Failed to allocate tpl prev_gop_arf_tpl_recon buf.");
+
+ YV12_BUFFER_CONFIG *prev_gop_arf_tpl_recon_buf =
+ cpi->ppi->tpl_data.tpl_frame
+ ? cpi->ppi->tpl_data.tpl_frame[cpi->gf_frame_index].rec_picture
+ : NULL;
+
+ // Currently it is not supported if source/reference is resized.
+ if (prev_gop_arf_tpl_recon_buf &&
+ prev_gop_arf_tpl_recon_buf->y_width ==
+ cpi->ppi->tpl_data.prev_gop_arf_tpl_recon.y_width &&
+ prev_gop_arf_tpl_recon_buf->y_height ==
+ cpi->ppi->tpl_data.prev_gop_arf_tpl_recon.y_height) {
+ // Copy the content from source to this buffer for next gop.
+ aom_yv12_copy_frame(prev_gop_arf_tpl_recon_buf,
+ &cpi->ppi->tpl_data.prev_gop_arf_tpl_recon, 1);
+ } else {
+ available = 0;
+ }
+
+ if (available) {
cpi->ppi->tpl_data.prev_gop_arf_disp_order =
current_frame->display_order_hint;
}
}
}
+#endif
if (is_stat_generation_stage(cpi)) {
#if !CONFIG_REALTIME_ONLY
diff --git a/av1/encoder/tpl_model.c b/av1/encoder/tpl_model.c
index 7f3bc97d7b..c1691f9151 100644
--- a/av1/encoder/tpl_model.c
+++ b/av1/encoder/tpl_model.c
@@ -851,7 +851,11 @@ static inline void mode_estimation(AV1_COMP *cpi, TplTxfmStats *tpl_txfm_stats,
// Store inter cost for each ref frame. This is used to prune inter modes.
tpl_stats->pred_error[rf_idx] = AOMMAX(1, inter_cost);
- if (inter_cost < best_inter_cost) {
+ // If we have saved the previous arf frame. Only allow using it as reference
+ // for previous gop.
+ if (inter_cost < best_inter_cost &&
+ (tpl_data->prev_gop_arf_disp_order < 0 ||
+ tpl_data->src_ref_frame[rf_idx] != tpl_data->ref_frame[rf_idx])) {
best_rf_idx = rf_idx;
best_inter_cost = inter_cost;
@@ -981,7 +985,13 @@ static inline void mode_estimation(AV1_COMP *cpi, TplTxfmStats *tpl_txfm_stats,
inter_cost =
tpl_get_satd_cost(bd_info, src_diff, bw, src_mb_buffer, src_stride,
predictor, bw, coeff, bw, bh, tx_size);
- if (inter_cost < best_inter_cost) {
+
+ // If we have saved the previous arf frame. Only allow using it as reference
+ // for previous gop.
+ if (inter_cost < best_inter_cost &&
+ (tpl_data->prev_gop_arf_disp_order < 0 ||
+ (tpl_data->src_ref_frame[rf_idx0] != tpl_data->ref_frame[rf_idx0] &&
+ tpl_data->src_ref_frame[rf_idx1] != tpl_data->ref_frame[rf_idx1]))) {
best_cmp_rf_idx = cmp_rf_idx;
best_inter_cost = inter_cost;
best_mv[0] = tmp_mv[0];
@@ -1648,15 +1658,23 @@ static inline int init_gop_frames_for_tpl(
tpl_data->tpl_frame[-i - 1].rec_picture = NULL;
tpl_data->tpl_frame[-i - 1].frame_display_index = 0;
} else {
+ int has_prev_arf = 0;
if (cm->ref_frame_map[i]->display_order_hint ==
tpl_data->prev_gop_arf_disp_order) {
tpl_data->tpl_frame[-i - 1].gf_picture = &tpl_data->prev_gop_arf_src;
+ tpl_data->tpl_frame[-i - 1].rec_picture =
+ &tpl_data->prev_gop_arf_tpl_recon;
+ has_prev_arf = 1;
} else {
tpl_data->tpl_frame[-i - 1].gf_picture = &cm->ref_frame_map[i]->buf;
+ tpl_data->tpl_frame[-i - 1].rec_picture = &cm->ref_frame_map[i]->buf;
}
- tpl_data->tpl_frame[-i - 1].rec_picture = &cm->ref_frame_map[i]->buf;
tpl_data->tpl_frame[-i - 1].frame_display_index =
cm->ref_frame_map[i]->display_order_hint;
+
+ if (!has_prev_arf) {
+ tpl_data->prev_gop_arf_disp_order = -1;
+ }
}
ref_picture_map[i] = -i - 1;
diff --git a/av1/encoder/tpl_model.h b/av1/encoder/tpl_model.h
index a69bf46271..34bcfc67c7 100644
--- a/av1/encoder/tpl_model.h
+++ b/av1/encoder/tpl_model.h
@@ -243,6 +243,11 @@ typedef struct TplParams {
*/
YV12_BUFFER_CONFIG prev_gop_arf_src;
+ /*!
+ * The buffer for the past gop's last frame's tpl recon.
+ */
+ YV12_BUFFER_CONFIG prev_gop_arf_tpl_recon;
+
/*!
* Display order of the past gop's last frame.
*/