Rework codec to improve performance for Shorts videos
BUG=b/435747631
STATS_CHANGED
Change-Id: I774b30ef4281f0c1db85ee21a06eb96e61aaf0cd
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index 8256e39..4dc4258 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -3981,6 +3981,7 @@
section->frame_avg_wavelet_energy -= frame->frame_avg_wavelet_energy;
section->coded_error -= frame->coded_error;
section->sr_coded_error -= frame->sr_coded_error;
+ section->lt_coded_error -= frame->lt_coded_error;
section->pcnt_inter -= frame->pcnt_inter;
section->pcnt_motion -= frame->pcnt_motion;
section->pcnt_second_ref -= frame->pcnt_second_ref;
diff --git a/av1/encoder/firstpass.c b/av1/encoder/firstpass.c
index 552c342..a49db4a 100644
--- a/av1/encoder/firstpass.c
+++ b/av1/encoder/firstpass.c
@@ -97,6 +97,7 @@
section->log_intra_error = 0.0;
section->log_coded_error = 0.0;
section->sr_coded_error = 0.0;
+ section->lt_coded_error = 0.0;
section->pcnt_inter = 0.0;
section->pcnt_motion = 0.0;
section->pcnt_second_ref = 0.0;
@@ -129,6 +130,7 @@
section->frame_avg_wavelet_energy += frame->frame_avg_wavelet_energy;
section->coded_error += frame->coded_error;
section->sr_coded_error += frame->sr_coded_error;
+ section->lt_coded_error += frame->lt_coded_error;
section->pcnt_inter += frame->pcnt_inter;
section->pcnt_motion += frame->pcnt_motion;
section->pcnt_second_ref += frame->pcnt_second_ref;
@@ -702,7 +704,8 @@
// this_inter_error
static int firstpass_inter_prediction(
AV1_COMP *cpi, ThreadData *td, const YV12_BUFFER_CONFIG *const last_frame,
- const YV12_BUFFER_CONFIG *const golden_frame, const int unit_row,
+ const YV12_BUFFER_CONFIG *const golden_frame,
+ const YV12_BUFFER_CONFIG *const last2_frame, const int unit_row,
const int unit_col, const int recon_yoffset, const int recon_uvoffset,
const int src_yoffset, const BLOCK_SIZE fp_block_size,
const int this_intra_error, const int raw_motion_err_counts,
@@ -770,6 +773,19 @@
}
}
+ int last2_motion_error = motion_error;
+ if ((current_frame->frame_number > 2) && last2_frame != NULL) {
+ FULLPEL_MV tmp_mv = kZeroFullMv;
+ // Assume 0,0 motion with no mv overhead.
+ av1_setup_pre_planes(xd, 0, last2_frame, 0, 0, NULL, 1);
+ xd->plane[0].pre[0].buf += recon_yoffset;
+ last2_motion_error =
+ get_prediction_error_bitdepth(is_high_bitdepth, bitdepth, bsize,
+ &x->plane[0].src, &xd->plane[0].pre[0]);
+ first_pass_motion_search(cpi, x, &kZeroMv, &tmp_mv, &last2_motion_error);
+ stats->lt_coded_error += AOMMIN(last2_motion_error, this_intra_error);
+ }
+
// Motion search in 2nd reference frame.
int gf_motion_error = motion_error;
if ((current_frame->frame_number > 1) && golden_frame != NULL) {
@@ -859,6 +875,7 @@
double f_h) {
fps->coded_error /= num_mbs_16x16;
fps->sr_coded_error /= num_mbs_16x16;
+ fps->lt_coded_error /= num_mbs_16x16;
fps->intra_error /= num_mbs_16x16;
fps->frame_avg_wavelet_energy /= num_mbs_16x16;
fps->log_coded_error = log1p(fps->coded_error);
@@ -914,6 +931,7 @@
fps.frame = frame_number;
fps.coded_error = (double)(stats->coded_error >> 8) + min_err;
fps.sr_coded_error = (double)(stats->sr_coded_error >> 8) + min_err;
+ fps.lt_coded_error = (double)(stats->lt_coded_error >> 8) + min_err;
fps.intra_error = (double)(stats->intra_error >> 8) + min_err;
fps.frame_avg_wavelet_energy = (double)stats->frame_avg_wavelet_energy;
fps.count = 1.0;
@@ -1033,6 +1051,7 @@
stats.new_mv_count += mb_stat.new_mv_count;
stats.second_ref_count += mb_stat.second_ref_count;
stats.sr_coded_error += mb_stat.sr_coded_error;
+ stats.lt_coded_error += mb_stat.lt_coded_error;
stats.sum_in_vectors += mb_stat.sum_in_vectors;
stats.sum_mvc += mb_stat.sum_mvc;
stats.sum_mvc_abs += mb_stat.sum_mvc_abs;
@@ -1150,6 +1169,10 @@
if (!golden_frame) {
golden_frame = get_ref_frame_yv12_buf(cm, GOLDEN_FRAME);
}
+ const YV12_BUFFER_CONFIG *last2_frame =
+ av1_get_scaled_ref_frame(cpi, LAST2_FRAME);
+ if (!last2_frame) last2_frame = get_ref_frame_yv12_buf(cm, LAST2_FRAME);
+
YV12_BUFFER_CONFIG *const this_frame = &cm->cur_frame->buf;
PICK_MODE_CONTEXT *ctx = td->firstpass_ctx;
@@ -1223,10 +1246,10 @@
if (!frame_is_intra_only(cm)) {
const int this_inter_error = firstpass_inter_prediction(
- cpi, td, last_frame, golden_frame, unit_row, unit_col, recon_yoffset,
- recon_uvoffset, src_yoffset, fp_block_size, this_intra_error,
- raw_motion_err_counts, raw_motion_err_list, best_ref_mv, &best_ref_mv,
- &last_mv, mb_stats);
+ cpi, td, last_frame, golden_frame, last2_frame, unit_row, unit_col,
+ recon_yoffset, recon_uvoffset, src_yoffset, fp_block_size,
+ this_intra_error, raw_motion_err_counts, raw_motion_err_list,
+ best_ref_mv, &best_ref_mv, &last_mv, mb_stats);
if (unit_col_in_tile == 0) {
*first_top_mv = last_mv;
}
@@ -1235,6 +1258,7 @@
} else {
mb_stats->sr_coded_error += this_intra_error;
mb_stats->coded_error += this_intra_error;
+ mb_stats->lt_coded_error += this_intra_error;
}
// Adjust to the next column of MBs.
@@ -1289,7 +1313,8 @@
const int qindex = find_fp_qindex(seq_params->bit_depth);
const int ref_frame_flags_backup = cpi->ref_frame_flags;
cpi->ref_frame_flags = av1_ref_frame_flag_list[LAST_FRAME] |
- av1_ref_frame_flag_list[GOLDEN_FRAME];
+ av1_ref_frame_flag_list[GOLDEN_FRAME] |
+ av1_ref_frame_flag_list[LAST2_FRAME];
// Detect if the key frame is screen content type.
if (frame_is_intra_only(cm)) {
@@ -1343,6 +1368,8 @@
const YV12_BUFFER_CONFIG *last_frame = NULL;
const YV12_BUFFER_CONFIG *golden_frame = NULL;
+ const YV12_BUFFER_CONFIG *last2_frame = NULL;
+
if (!frame_is_intra_only(cm)) {
av1_scale_references(cpi, EIGHTTAP_REGULAR, 0, 0);
last_frame = av1_is_scaled(get_ref_scale_factors_const(cm, LAST_FRAME))
@@ -1351,6 +1378,9 @@
golden_frame = av1_is_scaled(get_ref_scale_factors_const(cm, GOLDEN_FRAME))
? av1_get_scaled_ref_frame(cpi, GOLDEN_FRAME)
: get_ref_frame_yv12_buf(cm, GOLDEN_FRAME);
+ last2_frame = av1_is_scaled(get_ref_scale_factors_const(cm, LAST2_FRAME))
+ ? av1_get_scaled_ref_frame(cpi, LAST2_FRAME)
+ : get_ref_frame_yv12_buf(cm, LAST2_FRAME);
}
YV12_BUFFER_CONFIG *const this_frame = &cm->cur_frame->buf;
@@ -1440,6 +1470,12 @@
current_frame->frame_number, ts_duration,
fp_block_size);
+ if (this_frame_stats->pcnt_inter < 0.2 && last2_frame != NULL) {
+ assign_frame_buffer_p(
+ &cm->ref_frame_map[get_ref_frame_map_idx(cm, LAST2_FRAME)],
+ cm->ref_frame_map[get_ref_frame_map_idx(cm, GOLDEN_FRAME)]);
+ }
+
// Copy the previous Last Frame back into gf buffer if the prediction is good
// enough... but also don't allow it to lag too far.
if ((twopass->sr_update_lag > 3) ||
@@ -1472,6 +1508,13 @@
cm->ref_frame_map[get_ref_frame_map_idx(cm, LAST_FRAME)]);
}
+ if (current_frame->frame_number == 0 &&
+ get_ref_frame_map_idx(cm, LAST2_FRAME) != INVALID_IDX) {
+ assign_frame_buffer_p(
+ &cm->ref_frame_map[get_ref_frame_map_idx(cm, LAST2_FRAME)],
+ cm->ref_frame_map[get_ref_frame_map_idx(cm, LAST_FRAME)]);
+ }
+
print_reconstruction_frame(last_frame, current_frame->frame_number,
/*do_print=*/0);
diff --git a/av1/encoder/firstpass.h b/av1/encoder/firstpass.h
index a1b7e7d..d4b6ef1 100644
--- a/av1/encoder/firstpass.h
+++ b/av1/encoder/firstpass.h
@@ -69,6 +69,10 @@
*/
double sr_coded_error;
/*!
+ * Best of intra pred error and inter pred error using long term frame as ref.
+ */
+ double lt_coded_error;
+ /*!
* Percentage of blocks with inter pred error < intra pred error.
*/
double pcnt_inter;
@@ -482,6 +486,9 @@
int64_t coded_error;
// Best of intra pred error and inter pred error using golden frame as ref.
int64_t sr_coded_error;
+ // Best of coded error using long term reference.
+ int64_t lt_coded_error;
+
// Count of motion vector.
int mv_count;
// Count of blocks that pick inter prediction (inter pred error is smaller
diff --git a/av1/encoder/pass2_strategy.c b/av1/encoder/pass2_strategy.c
index a109109..a1d6640 100644
--- a/av1/encoder/pass2_strategy.c
+++ b/av1/encoder/pass2_strategy.c
@@ -2985,6 +2985,7 @@
: cpi->common.mi_params.MBs;
const int future_stats_count =
av1_firstpass_info_future_count(firstpass_info, 0);
+
while (frames_to_key < future_stats_count &&
frames_to_key < num_frames_to_detect_scenecut) {
// Provided that we are not at the end of the file...
@@ -2999,7 +3000,19 @@
oxcf->rc_cfg.mode, cpi->ppi->p_rc.enable_scenecut_detection,
num_mbs);
if (scenecut_detected) {
- break;
+ int test_next_gop = 0;
+
+ for (int idx = 0; idx < 32; ++idx) {
+ const FIRSTPASS_STATS *next_stats =
+ av1_firstpass_info_peek(firstpass_info, frames_to_key + idx);
+
+ if (next_stats == NULL) continue;
+
+ if (next_stats->lt_coded_error * 2.5 < next_stats->coded_error)
+ test_next_gop = 1;
+ }
+
+ if (!test_next_gop) break;
}
}