ref: 3e09814a027cba6c2824ca98859da8c9ab947acc
parent: bc7c99e7eca8d30d005e7d5db8b0aada2459fb15
author: Marco Paniconi <marpan@google.com>
date: Wed Jul 11 15:38:44 EDT 2018
vp9: Force hybrid_intra on scene change For real-time screen content mode: when scene/slide change is detected and re-encode is decided, force hybrid_intra mode search if slide change is big and alot of Intra modes were used. hybrid_intra mode will use rd-based intra mode search for small blocks. Overall better PSNR on clip with slide changes, with similar encoded frame size. Encode time lightly higher on average with this change. Change-Id: I503835253b777b9f98d74e75a52a8000b76c310c
--- a/vp9/encoder/vp9_encodeframe.c
+++ b/vp9/encoder/vp9_encodeframe.c
@@ -4340,6 +4340,18 @@
}
}
+static void hybrid_search_scene_change(VP9_COMP *cpi, MACROBLOCK *const x,
+ RD_COST *rd_cost, BLOCK_SIZE bsize,
+ PICK_MODE_CONTEXT *ctx,
+ TileDataEnc *tile_data, int mi_row,
+ int mi_col) {
+ if (!cpi->sf.nonrd_keyframe && bsize <= BLOCK_8X8) {
+ vp9_rd_pick_intra_mode_sb(cpi, x, rd_cost, bsize, ctx, INT64_MAX);
+ } else {
+ vp9_pick_inter_mode(cpi, x, tile_data, mi_row, mi_col, rd_cost, bsize, ctx);
+ }
+}
+
static void nonrd_pick_sb_modes(VP9_COMP *cpi, TileDataEnc *tile_data,
MACROBLOCK *const x, int mi_row, int mi_col,
RD_COST *rd_cost, BLOCK_SIZE bsize,
@@ -4377,10 +4389,16 @@
mi_col);
else if (segfeature_active(&cm->seg, mi->segment_id, SEG_LVL_SKIP))
set_mode_info_seg_skip(x, cm->tx_mode, rd_cost, bsize);
- else if (bsize >= BLOCK_8X8)
- vp9_pick_inter_mode(cpi, x, tile_data, mi_row, mi_col, rd_cost, bsize, ctx);
- else
+ else if (bsize >= BLOCK_8X8) {
+ if (cpi->rc.hybrid_intra_scene_change)
+ hybrid_search_scene_change(cpi, x, rd_cost, bsize, ctx, tile_data, mi_row,
+ mi_col);
+ else
+ vp9_pick_inter_mode(cpi, x, tile_data, mi_row, mi_col, rd_cost, bsize,
+ ctx);
+ } else {
vp9_pick_inter_mode_sub8x8(cpi, x, mi_row, mi_col, rd_cost, bsize, ctx);
+ }
duplicate_mode_info_in_sb(cm, xd, mi_row, mi_col, bsize);
--- a/vp9/encoder/vp9_encoder.c
+++ b/vp9/encoder/vp9_encoder.c
@@ -3983,6 +3983,7 @@
// For other cases (e.g., CBR mode) use it for 5 <= speed < 8 for now
// (need to check encoding time cost for doing this for speed 8).
cpi->rc.high_source_sad = 0;
+ cpi->rc.hybrid_intra_scene_change = 0;
if (cm->show_frame && cpi->oxcf.mode == REALTIME &&
(cpi->oxcf.rc_mode == VPX_VBR ||
cpi->oxcf.content == VP9E_CONTENT_SCREEN ||
--- a/vp9/encoder/vp9_ratectrl.c
+++ b/vp9/encoder/vp9_ratectrl.c
@@ -363,6 +363,7 @@
rc->high_source_sad = 0;
rc->reset_high_source_sad = 0;
rc->high_source_sad_lagindex = -1;
+ rc->hybrid_intra_scene_change = 0;
rc->alt_ref_gf_group = 0;
rc->last_frame_is_src_altref = 0;
rc->fac_active_worst_inter = 150;
@@ -2807,6 +2808,26 @@
int enumerator;
// Force a re-encode, and for now use max-QP.
*q = cpi->rc.worst_quality;
+ // If the frame_size is much larger than the threshold (big content change)
+ // and the encoded frame used alot of Intra modes, then force hybrid_intra
+ // encoding for the re-encode on this scene change. hybrid_intra will
+ // use rd-based intra mode selection for small blocks.
+ if (frame_size > (thresh_rate << 1) && cpi->svc.spatial_layer_id == 0) {
+ MODE_INFO **mi = cm->mi_grid_visible;
+ int sum_intra_usage = 0;
+ int mi_row, mi_col;
+ int tot = 0;
+ for (mi_row = 0; mi_row < cm->mi_rows; mi_row++) {
+ for (mi_col = 0; mi_col < cm->mi_cols; mi_col++) {
+ if (mi[0]->ref_frame[0] == INTRA_FRAME) sum_intra_usage++;
+ tot++;
+ mi++;
+ }
+ mi += 8;
+ }
+ sum_intra_usage = 100 * sum_intra_usage / (cm->mi_rows * cm->mi_cols);
+ if (sum_intra_usage > 60) cpi->rc.hybrid_intra_scene_change = 1;
+ }
// Adjust avg_frame_qindex, buffer_level, and rate correction factors, as
// these parameters will affect QP selection for subsequent frames. If they
// have settled down to a very different (low QP) state, then not adjusting
--- a/vp9/encoder/vp9_ratectrl.h
+++ b/vp9/encoder/vp9_ratectrl.h
@@ -181,6 +181,7 @@
int last_frame_is_src_altref;
int high_source_sad;
int count_last_scene_change;
+ int hybrid_intra_scene_change;
int avg_frame_low_motion;
int af_ratio_onepass_vbr;
int force_qpmin;