vp9 non-rd mode: Modification for detected skin areas.

If a superblock contains alot of "skin" then force split
of 64x64 partition, and make some adjustments in mode selection.

This helps to reduce artifacts on moving face/skin areas at low bitrates.

Little/no change in metrics: avgPSNR/SSIM down by ~0.12%.
Small encoding time increase < 1%.

Change-Id: Ic57f52148c3716f391419fab0530d916e4c1d186
This commit is contained in:
Marco 2016-01-22 11:45:31 -08:00
parent cdb141dd94
commit b39a599cef
3 changed files with 54 additions and 6 deletions

View File

@ -137,6 +137,8 @@ struct macroblock {
// the visual quality at the boundary of moving color objects.
uint8_t color_sensitivity[2];
uint8_t sb_is_skin;
void (*fwd_txm4x4)(const int16_t *input, tran_low_t *output, int stride);
void (*itxm_add)(const tran_low_t *input, uint8_t *dest, int stride, int eob);
#if CONFIG_VP9_HIGHBITDEPTH

View File

@ -714,6 +714,10 @@ static int choose_partitioning(VP9_COMP *cpi,
s = x->plane[0].src.buf;
sp = x->plane[0].src.stride;
// Index for force_split: 0 for 64x64, 1-4 for 32x32 blocks,
// 5-20 for the 16x16 blocks.
force_split[0] = 0;
if (!is_key_frame) {
// In the case of spatial/temporal scalable coding, the assumption here is
// that the temporal reference frame will always be of type LAST_FRAME.
@ -768,6 +772,47 @@ static int choose_partitioning(VP9_COMP *cpi,
vp9_build_inter_predictors_sb(xd, mi_row, mi_col, BLOCK_64X64);
// Check if most of the superblock is skin content, and if so, force split
// to 32x32. Avoid checking superblocks on/near boundary for high resoln
// Note superblock may still pick 64X64 if y_sad is very small
// (i.e., y_sad < cpi->vbp_threshold_sad) below. For now leave this as is.
x->sb_is_skin = 0;
if (cpi->oxcf.content != VP9E_CONTENT_SCREEN && (low_res || (mi_col >= 8 &&
mi_col + 8 < cm->mi_cols && mi_row >= 8 && mi_row + 8 < cm->mi_rows))) {
int num_16x16_skin = 0;
int num_16x16_nonskin = 0;
uint8_t *ysignal = x->plane[0].src.buf;
uint8_t *usignal = x->plane[1].src.buf;
uint8_t *vsignal = x->plane[2].src.buf;
int spuv = x->plane[1].src.stride;
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
int is_skin = vp9_compute_skin_block(ysignal,
usignal,
vsignal,
sp,
spuv,
BLOCK_16X16);
num_16x16_skin += is_skin;
num_16x16_nonskin += (1 - is_skin);
if (num_16x16_nonskin > 3) {
// Exit loop if at least 4 of the 16x16 blocks are not skin.
i = 4;
j = 4;
}
ysignal += 16;
usignal += 8;
vsignal += 8;
}
ysignal += (sp << 4) - 64;
usignal += (spuv << 3) - 32;
vsignal += (spuv << 3) - 32;
}
if (num_16x16_skin > 12) {
x->sb_is_skin = 1;
force_split[0] = 1;
}
}
for (i = 1; i <= 2; ++i) {
struct macroblock_plane *p = &x->plane[i];
struct macroblockd_plane *pd = &xd->plane[i];
@ -779,7 +824,9 @@ static int choose_partitioning(VP9_COMP *cpi,
uv_sad = cpi->fn_ptr[bs].sdf(p->src.buf, p->src.stride,
pd->dst.buf, pd->dst.stride);
x->color_sensitivity[i - 1] = uv_sad > (y_sad >> 2);
// TODO(marpan): Investigate if we should lower this threshold if
// superblock is detected as skin.
x->color_sensitivity[i - 1] = uv_sad > (y_sad >> 2);
}
d = xd->plane[0].dst.buf;
@ -818,9 +865,6 @@ static int choose_partitioning(VP9_COMP *cpi,
#endif // CONFIG_VP9_HIGHBITDEPTH
}
// Index for force_split: 0 for 64x64, 1-4 for 32x32 blocks,
// 5-20 for the 16x16 blocks.
force_split[0] = 0;
// Fill in the entire tree of 8x8 (or 4x4 under some conditions) variances
// for splits.
for (i = 0; i < 4; i++) {
@ -3629,6 +3673,7 @@ static void encode_nonrd_sb_row(VP9_COMP *cpi,
vp9_rd_cost_init(&dummy_rdc);
x->color_sensitivity[0] = 0;
x->color_sensitivity[1] = 0;
x->sb_is_skin = 0;
if (seg->enabled) {
const uint8_t *const map = seg->update_map ? cpi->segmentation_map

View File

@ -812,7 +812,7 @@ static void encode_breakout_test(VP9_COMP *cpi, MACROBLOCK *x,
mi->mv[0].as_mv.col > 64 ||
mi->mv[0].as_mv.col < -64)
motion_low = 0;
if (x->encode_breakout > 0 && motion_low == 1) {
if (x->encode_breakout > 0 && motion_low == 1 && !x->sb_is_skin) {
// Set a maximum for threshold to avoid big PSNR loss in low bit rate
// case. Use extreme low threshold for static frames to limit
// skipping.
@ -1585,7 +1585,8 @@ void vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x,
this_rdc.rdcost = RDCOST(x->rdmult, x->rddiv, this_rdc.rate, this_rdc.dist);
if (cpi->oxcf.speed >= 5 &&
cpi->oxcf.content != VP9E_CONTENT_SCREEN) {
cpi->oxcf.content != VP9E_CONTENT_SCREEN &&
!x->sb_is_skin) {
// Bias against non-zero (above some threshold) motion for large blocks.
// This is temporary fix to avoid selection of large mv for big blocks.
if (frame_mv[this_mode][ref_frame].as_mv.row > 64 ||