ref: b121a3e7b8be493c1fa91a740300e1880339fb93
parent: 52e7f4153bbd06ec4fd0942c554544c7ede5911e
author: Marco <[email protected]>
date: Mon Dec 21 05:35:05 EST 2015
aq-mode=3: Don't reset segment if block is determined to be skin. For coding block sizes <=16X16, if the block is determined to be skin, then always allow for that block to be candidate for refresh. So if that block happens to be on the boost segment(s), segment won't get reset to 0 and delta-q will be applied. PSNR/SSIM metrics neutral (little/no change) on RTC clips. Speed increase small/negligible (< 1%). Some visual improvement on faces in a few RTC clips. Change-Id: I6bf0fce6f39d820b491ce05d7c017ad168fce7d6
--- a/vp9/encoder/vp9_aq_cyclicrefresh.c
+++ b/vp9/encoder/vp9_aq_cyclicrefresh.c
@@ -191,7 +191,8 @@
BLOCK_SIZE bsize,
int64_t rate,
int64_t dist,
- int skip) {
+ int skip,
+ struct macroblock_plane *const p) {
const VP9_COMMON *const cm = &cpi->common;
CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
const int bw = num_8x8_blocks_wide_lookup[bsize];
@@ -199,11 +200,32 @@
const int xmis = VPXMIN(cm->mi_cols - mi_col, bw);
const int ymis = VPXMIN(cm->mi_rows - mi_row, bh);
const int block_index = mi_row * cm->mi_cols + mi_col;
- const int refresh_this_block = candidate_refresh_aq(cr, mbmi, rate, dist,
- bsize);
+ int refresh_this_block = candidate_refresh_aq(cr, mbmi, rate, dist, bsize);
// Default is to not update the refresh map.
int new_map_value = cr->map[block_index];
int x = 0; int y = 0;
+
+ int is_skin = 0;
+ if (refresh_this_block == 0 &&
+ bsize <= BLOCK_16X16 &&
+ cpi->oxcf.content != VP9E_CONTENT_SCREEN) {
+ // Take center pixel in block to determine is_skin.
+ const int y_width_shift = (4 << b_width_log2_lookup[bsize]) >> 1;
+ const int y_height_shift = (4 << b_height_log2_lookup[bsize]) >> 1;
+ const int uv_width_shift = y_width_shift >> 1;
+ const int uv_height_shift = y_height_shift >> 1;
+ const int stride = p[0].src.stride;
+ const int strideuv = p[1].src.stride;
+ const uint8_t ysource =
+ p[0].src.buf[y_height_shift * stride + y_width_shift];
+ const uint8_t usource =
+ p[1].src.buf[uv_height_shift * strideuv + uv_width_shift];
+ const uint8_t vsource =
+ p[2].src.buf[uv_height_shift * strideuv + uv_width_shift];
+ is_skin = vp9_skin_pixel(ysource, usource, vsource);
+ if (is_skin)
+ refresh_this_block = 1;
+ }
// If this block is labeled for refresh, check if we should reset the
// segment_id.
--- a/vp9/encoder/vp9_aq_cyclicrefresh.h
+++ b/vp9/encoder/vp9_aq_cyclicrefresh.h
@@ -14,6 +14,8 @@
#include "vpx/vpx_integer.h"
#include "vp9/common/vp9_blockd.h"
+#include "vp9/encoder/vp9_block.h"
+#include "vp9/encoder/vp9_skin_detection.h"
#ifdef __cplusplus
extern "C" {
@@ -93,7 +95,8 @@
void vp9_cyclic_refresh_update_segment(struct VP9_COMP *const cpi,
MB_MODE_INFO *const mbmi,
int mi_row, int mi_col, BLOCK_SIZE bsize,
- int64_t rate, int64_t dist, int skip);
+ int64_t rate, int64_t dist, int skip,
+ struct macroblock_plane *const p);
void vp9_cyclic_refresh_update_sb_postencode(struct VP9_COMP *const cpi,
const MB_MODE_INFO *const mbmi,
--- a/vp9/encoder/vp9_encodeframe.c
+++ b/vp9/encoder/vp9_encodeframe.c
@@ -1045,7 +1045,7 @@
if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ) {
vp9_cyclic_refresh_update_segment(cpi, &xd->mi[0]->mbmi, mi_row,
mi_col, bsize, ctx->rate, ctx->dist,
- x->skip);
+ x->skip, p);
}
}
@@ -1705,6 +1705,7 @@
MACROBLOCKD *const xd = &x->e_mbd;
MODE_INFO *const mi = xd->mi[0];
MB_MODE_INFO *const mbmi = &xd->mi[0]->mbmi;
+ struct macroblock_plane *const p = x->plane;
const struct segmentation *const seg = &cm->seg;
const int bw = num_8x8_blocks_wide_lookup[mi->mbmi.sb_type];
const int bh = num_8x8_blocks_high_lookup[mi->mbmi.sb_type];
@@ -1725,7 +1726,7 @@
} else {
// Setting segmentation map for cyclic_refresh.
vp9_cyclic_refresh_update_segment(cpi, mbmi, mi_row, mi_col, bsize,
- ctx->rate, ctx->dist, x->skip);
+ ctx->rate, ctx->dist, x->skip, p);
}
vp9_init_plane_quantizers(cpi, x);
}