ref: f27276f44fa3a66c07a2a92a381f31aaf8371add
parent: 8a152a55f79062a9cba249919f1689ddbabbee22
parent: 1d5ca84df600ab610d14c0356b038ad4c395a6fd
author: Jerome Jiang <jianj@google.com>
date: Tue Dec 20 16:46:43 EST 2016
Merge "vp9: Add feature to copy partition from the last frame."
--- a/vp9/encoder/vp9_encodeframe.c
+++ b/vp9/encoder/vp9_encodeframe.c
@@ -526,6 +526,7 @@
: 1000;
cpi->vbp_bsize_min = BLOCK_16X16;
}
+ cpi->vbp_threshold_copy = cpi->vbp_thresholds[0] << 16;
cpi->vbp_threshold_minmax = 15 + (q >> 3);
}
}
@@ -766,6 +767,93 @@
}
}
+static void copy_prev_partition(VP9_COMP *cpi, BLOCK_SIZE bsize, int mi_row,
+ int mi_col) {
+ VP9_COMMON *const cm = &cpi->common;
+ BLOCK_SIZE *prev_part = cpi->prev_partition;
+ int start_pos = mi_row * cm->mi_stride + mi_col;
+
+ const int bsl = b_width_log2_lookup[bsize];
+ const int bs = (1 << bsl) / 4;
+ BLOCK_SIZE subsize;
+ PARTITION_TYPE partition;
+ MODE_INFO *mi = NULL;
+
+ if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols) return;
+
+ partition = partition_lookup[bsl][prev_part[start_pos]];
+ subsize = get_subsize(bsize, partition);
+ mi = cm->mi_grid_visible[mi_row * cm->mi_stride + mi_col];
+
+ if (subsize < BLOCK_8X8) {
+ mi->sb_type = bsize;
+ } else {
+ switch (partition) {
+ case PARTITION_NONE: mi->sb_type = bsize; break;
+ case PARTITION_HORZ:
+ mi->sb_type = subsize;
+ if (mi_row + bs < cm->mi_rows)
+ cm->mi_grid_visible[(mi_row + bs) * cm->mi_stride + mi_col]->sb_type =
+ subsize;
+ break;
+ case PARTITION_VERT:
+ mi->sb_type = subsize;
+ if (mi_col + bs < cm->mi_cols)
+ cm->mi_grid_visible[mi_row * cm->mi_stride + mi_col + bs]->sb_type =
+ subsize;
+ break;
+ case PARTITION_SPLIT:
+ copy_prev_partition(cpi, subsize, mi_row, mi_col);
+ copy_prev_partition(cpi, subsize, mi_row + bs, mi_col);
+ copy_prev_partition(cpi, subsize, mi_row, mi_col + bs);
+ copy_prev_partition(cpi, subsize, mi_row + bs, mi_col + bs);
+ break;
+ default: assert(0);
+ }
+ }
+}
+
+static void update_prev_partition(VP9_COMP *cpi, BLOCK_SIZE bsize, int mi_row,
+ int mi_col) {
+ VP9_COMMON *const cm = &cpi->common;
+ BLOCK_SIZE *prev_part = cpi->prev_partition;
+ int start_pos = mi_row * cm->mi_stride + mi_col;
+ const int bsl = b_width_log2_lookup[bsize];
+ const int bs = (1 << bsl) / 4;
+ BLOCK_SIZE subsize;
+ PARTITION_TYPE partition;
+ const MODE_INFO *mi = NULL;
+
+ if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols) return;
+
+ mi = cm->mi_grid_visible[start_pos];
+ partition = partition_lookup[bsl][mi->sb_type];
+ subsize = get_subsize(bsize, partition);
+ if (subsize < BLOCK_8X8) {
+ prev_part[start_pos] = bsize;
+ } else {
+ switch (partition) {
+ case PARTITION_NONE: prev_part[start_pos] = bsize; break;
+ case PARTITION_HORZ:
+ prev_part[start_pos] = subsize;
+ if (mi_row + bs < cm->mi_rows)
+ prev_part[start_pos + bs * cm->mi_stride] = subsize;
+ break;
+ case PARTITION_VERT:
+ prev_part[start_pos] = subsize;
+ if (mi_col + bs < cm->mi_cols) prev_part[start_pos + bs] = subsize;
+ break;
+ case PARTITION_SPLIT:
+ update_prev_partition(cpi, subsize, mi_row, mi_col);
+ update_prev_partition(cpi, subsize, mi_row + bs, mi_col);
+ update_prev_partition(cpi, subsize, mi_row, mi_col + bs);
+ update_prev_partition(cpi, subsize, mi_row + bs, mi_col + bs);
+ break;
+ default: assert(0);
+ }
+ }
+}
+
static void chroma_check(VP9_COMP *cpi, MACROBLOCK *x, int bsize,
unsigned int y_sad, int is_key_frame) {
int i;
@@ -828,6 +916,7 @@
const int low_res = (cm->width <= 352 && cm->height <= 288);
int variance4x4downsample[16];
int segment_id;
+ int offset = cm->mi_stride * mi_row + mi_col;
set_offsets(cpi, tile, x, mi_row, mi_col, BLOCK_64X64);
segment_id = xd->mi[0]->segment_id;
@@ -861,7 +950,7 @@
YV12_BUFFER_CONFIG *yv12 = get_ref_frame_buffer(cpi, LAST_FRAME);
const YV12_BUFFER_CONFIG *yv12_g = NULL;
- unsigned int y_sad_g, y_sad_thr;
+ unsigned int y_sad_g, y_sad_thr, y_sad_last;
bsize = BLOCK_32X32 + (mi_col + 4 < cm->mi_cols) * 2 +
(mi_row + 4 < cm->mi_rows);
@@ -901,6 +990,7 @@
mi->interp_filter = BILINEAR;
y_sad = vp9_int_pro_motion_estimation(cpi, x, bsize, mi_row, mi_col);
+ y_sad_last = y_sad;
// Pick ref frame for partitioning, bias last frame when y_sad_g and y_sad
// are close if short_circuit_low_temp_var is on.
y_sad_thr = cpi->sf.short_circuit_low_temp_var ? (y_sad * 7) >> 3 : y_sad;
@@ -941,6 +1031,20 @@
return 0;
}
}
+
+ // If the y_sad is small enough, copy the partition of the superblock in the
+ // last frame to current frame only if the last frame is not a keyframe.
+ // TODO(jianj) : tune the threshold.
+ if (cpi->sf.copy_partition_flag && cpi->rc.frames_since_key > 1 &&
+ segment_id == CR_SEGMENT_ID_BASE &&
+ cpi->prev_segment_id[offset] == CR_SEGMENT_ID_BASE &&
+ y_sad_last < cpi->vbp_threshold_copy) {
+ if (cpi->prev_partition != NULL) {
+ copy_prev_partition(cpi, BLOCK_64X64, mi_row, mi_col);
+ chroma_check(cpi, x, bsize, y_sad, is_key_frame);
+ return 0;
+ }
+ }
} else {
d = VP9_VAR_OFFS;
dp = 0;
@@ -1133,6 +1237,11 @@
}
}
}
+ }
+
+ if (cm->frame_type != KEY_FRAME && cpi->sf.copy_partition_flag) {
+ update_prev_partition(cpi, BLOCK_64X64, mi_row, mi_col);
+ cpi->prev_segment_id[offset] = segment_id;
}
if (cpi->sf.short_circuit_low_temp_var) {
--- a/vp9/encoder/vp9_encoder.c
+++ b/vp9/encoder/vp9_encoder.c
@@ -439,6 +439,12 @@
cpi->nmvsadcosts_hp[0] = NULL;
cpi->nmvsadcosts_hp[1] = NULL;
+ vpx_free(cpi->prev_partition);
+ cpi->prev_partition = NULL;
+
+ vpx_free(cpi->prev_segment_id);
+ cpi->prev_segment_id = NULL;
+
vp9_cyclic_refresh_free(cpi->cyclic_refresh);
cpi->cyclic_refresh = NULL;
--- a/vp9/encoder/vp9_encoder.h
+++ b/vp9/encoder/vp9_encoder.h
@@ -594,6 +594,8 @@
int64_t vbp_thresholds[4];
int64_t vbp_threshold_minmax;
int64_t vbp_threshold_sad;
+ // Threshold used for partition copy
+ int64_t vbp_threshold_copy;
BLOCK_SIZE vbp_bsize_min;
// Multi-threading
@@ -605,6 +607,10 @@
int keep_level_stats;
Vp9LevelInfo level_info;
+
+ // Previous Partition Info
+ BLOCK_SIZE *prev_partition;
+ int8_t *prev_segment_id;
} VP9_COMP;
void vp9_initialize_enc(void);
--- a/vp9/encoder/vp9_speed_features.c
+++ b/vp9/encoder/vp9_speed_features.c
@@ -311,6 +311,7 @@
sf->allow_exhaustive_searches = 0;
sf->exhaustive_searches_thresh = INT_MAX;
sf->allow_acl = 0;
+ sf->copy_partition_flag = 0;
if (speed >= 1) {
sf->allow_txfm_domain_distortion = 1;
@@ -496,6 +497,18 @@
if (speed >= 8) {
sf->adaptive_rd_thresh = 4;
+ // Disabled for now until the threshold is tuned.
+ sf->copy_partition_flag = 0;
+ if (sf->copy_partition_flag) {
+ if (cpi->prev_partition == NULL) {
+ cpi->prev_partition = (BLOCK_SIZE *)vpx_calloc(
+ cm->mi_stride * cm->mi_rows, sizeof(BLOCK_SIZE));
+ }
+ if (cpi->prev_segment_id == NULL) {
+ cpi->prev_segment_id =
+ (int8_t *)vpx_calloc(cm->mi_stride * cm->mi_rows, sizeof(int8_t));
+ }
+ }
sf->mv.subpel_force_stop = (content == VP9E_CONTENT_SCREEN) ? 3 : 2;
if (content == VP9E_CONTENT_SCREEN) sf->lpf_pick = LPF_PICK_MINIMAL_LPF;
// Only keep INTRA_DC mode for speed 8.
--- a/vp9/encoder/vp9_speed_features.h
+++ b/vp9/encoder/vp9_speed_features.h
@@ -474,6 +474,9 @@
// Bias to use base mv and skip 1/4 subpel search when use base mv in
// enhancement layer.
int base_mv_aggressive;
+
+ // Global flag to enable partition copy from the previous frame.
+ int copy_partition_flag;
} SPEED_FEATURES;
struct VP9_COMP;