Merge "vp9 SVC: Fix the denoiser frame buffer management."
This commit is contained in:
@@ -190,11 +190,12 @@ static VP9_DENOISER_DECISION perform_motion_compensation(
|
||||
VP9_COMMON *const cm, VP9_DENOISER *denoiser, MACROBLOCK *mb, BLOCK_SIZE bs,
|
||||
int increase_denoising, int mi_row, int mi_col, PICK_MODE_CONTEXT *ctx,
|
||||
int motion_magnitude, int is_skin, int *zeromv_filter, int consec_zeromv,
|
||||
int num_spatial_layers, int width) {
|
||||
int num_spatial_layers, int width, int lst_fb_idx, int gld_fb_idx,
|
||||
int use_svc) {
|
||||
const int sse_diff = (ctx->newmv_sse == UINT_MAX)
|
||||
? 0
|
||||
: ((int)ctx->zeromv_sse - (int)ctx->newmv_sse);
|
||||
MV_REFERENCE_FRAME frame;
|
||||
int frame;
|
||||
MACROBLOCKD *filter_mbd = &mb->e_mbd;
|
||||
MODE_INFO *mi = filter_mbd->mi[0];
|
||||
MODE_INFO saved_mi;
|
||||
@@ -202,8 +203,10 @@ static VP9_DENOISER_DECISION perform_motion_compensation(
|
||||
struct buf_2d saved_dst[MAX_MB_PLANE];
|
||||
struct buf_2d saved_pre[MAX_MB_PLANE];
|
||||
RefBuffer *saved_block_refs[2];
|
||||
MV_REFERENCE_FRAME saved_frame;
|
||||
|
||||
frame = ctx->best_reference_frame;
|
||||
|
||||
saved_mi = *mi;
|
||||
|
||||
if (is_skin && (motion_magnitude > 0 || consec_zeromv < 4)) return COPY_BLOCK;
|
||||
@@ -246,6 +249,15 @@ static VP9_DENOISER_DECISION perform_motion_compensation(
|
||||
}
|
||||
}
|
||||
|
||||
saved_frame = frame;
|
||||
// When using SVC, we need to map REF_FRAME to the frame buffer index.
|
||||
if (use_svc) {
|
||||
if (frame == LAST_FRAME)
|
||||
frame = lst_fb_idx + 1;
|
||||
else if (frame == GOLDEN_FRAME)
|
||||
frame = gld_fb_idx + 1;
|
||||
}
|
||||
|
||||
if (ctx->newmv_sse > sse_thresh(bs, increase_denoising)) {
|
||||
// Restore everything to its original state
|
||||
*mi = saved_mi;
|
||||
@@ -292,7 +304,7 @@ static VP9_DENOISER_DECISION perform_motion_compensation(
|
||||
denoiser->mc_running_avg_y.uv_stride, mi_row, mi_col);
|
||||
filter_mbd->plane[2].dst.stride = denoiser->mc_running_avg_y.uv_stride;
|
||||
|
||||
set_ref_ptrs(cm, filter_mbd, frame, NONE);
|
||||
set_ref_ptrs(cm, filter_mbd, saved_frame, NONE);
|
||||
vp9_build_inter_predictors_sby(filter_mbd, mi_row, mi_col, bs);
|
||||
|
||||
// Restore everything to its original state
|
||||
@@ -370,7 +382,8 @@ void vp9_denoiser_denoise(VP9_COMP *cpi, MACROBLOCK *mb, int mi_row, int mi_col,
|
||||
decision = perform_motion_compensation(
|
||||
&cpi->common, denoiser, mb, bs, increase_denoising, mi_row, mi_col, ctx,
|
||||
motion_magnitude, is_skin, &zeromv_filter, consec_zeromv,
|
||||
cpi->svc.number_spatial_layers, cpi->Source->y_width);
|
||||
cpi->svc.number_spatial_layers, cpi->Source->y_width, cpi->lst_fb_idx,
|
||||
cpi->gld_fb_idx, cpi->use_svc);
|
||||
|
||||
if (decision == FILTER_BLOCK) {
|
||||
decision = vp9_denoiser_filter(src.buf, src.stride, mc_avg_start,
|
||||
@@ -417,23 +430,11 @@ static void swap_frame_buffer(YV12_BUFFER_CONFIG *const dest,
|
||||
src->y_buffer = tmp_buf;
|
||||
}
|
||||
|
||||
void vp9_denoise_init_svc(VP9_COMP *cpi) {
|
||||
// For fixed pattern SVC, on base temporal layer. Note we only denoise
|
||||
// higher spatial layer for SVC.
|
||||
if (cpi->svc.temporal_layering_mode != VP9E_TEMPORAL_LAYERING_MODE_BYPASS &&
|
||||
cpi->svc.spatial_layer_id == cpi->svc.number_spatial_layers - 1 &&
|
||||
cpi->svc.temporal_layer_id == 0) {
|
||||
VP9_DENOISER *denoiser = &cpi->denoiser;
|
||||
copy_frame(&denoiser->running_avg_y[LAST_FRAME],
|
||||
&denoiser->running_avg_y[GOLDEN_FRAME]);
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_denoiser_update_frame_info(
|
||||
VP9_DENOISER *denoiser, YV12_BUFFER_CONFIG src, FRAME_TYPE frame_type,
|
||||
int refresh_alt_ref_frame, int refresh_golden_frame, int refresh_last_frame,
|
||||
int resized, int svc_base_is_key, int svc_fixed_pattern,
|
||||
int temporal_layer_id) {
|
||||
int alt_fb_idx, int gld_fb_idx, int lst_fb_idx, int resized,
|
||||
int svc_base_is_key) {
|
||||
// Copy source into denoised reference buffers on KEY_FRAME or
|
||||
// if the just encoded frame was resized. For SVC, copy source if the base
|
||||
// spatial layer was key frame.
|
||||
@@ -441,48 +442,42 @@ void vp9_denoiser_update_frame_info(
|
||||
svc_base_is_key) {
|
||||
int i;
|
||||
// Start at 1 so as not to overwrite the INTRA_FRAME
|
||||
for (i = 1; i < denoiser->num_ref_frames; ++i)
|
||||
copy_frame(&denoiser->running_avg_y[i], &src);
|
||||
for (i = 1; i < denoiser->num_ref_frames; ++i) {
|
||||
if (denoiser->running_avg_y[i].buffer_alloc != NULL)
|
||||
copy_frame(&denoiser->running_avg_y[i], &src);
|
||||
}
|
||||
denoiser->reset = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// If more than one refresh occurs, must copy frame buffer.
|
||||
if (refresh_golden_frame + refresh_last_frame + refresh_alt_ref_frame > 1) {
|
||||
if (refresh_golden_frame) {
|
||||
copy_frame(&denoiser->running_avg_y[GOLDEN_FRAME],
|
||||
if ((refresh_alt_ref_frame + refresh_golden_frame + refresh_last_frame) > 1) {
|
||||
if (refresh_alt_ref_frame) {
|
||||
copy_frame(&denoiser->running_avg_y[alt_fb_idx + 1],
|
||||
&denoiser->running_avg_y[INTRA_FRAME]);
|
||||
}
|
||||
// For fixed pattern SVC: update denoised last_frame if alt_ref is
|
||||
// refreshed, only for non-zero temporal layer.
|
||||
if (refresh_last_frame ||
|
||||
(refresh_alt_ref_frame && svc_fixed_pattern && temporal_layer_id > 0)) {
|
||||
copy_frame(&denoiser->running_avg_y[LAST_FRAME],
|
||||
if (refresh_golden_frame) {
|
||||
copy_frame(&denoiser->running_avg_y[gld_fb_idx + 1],
|
||||
&denoiser->running_avg_y[INTRA_FRAME]);
|
||||
}
|
||||
if (refresh_last_frame) {
|
||||
copy_frame(&denoiser->running_avg_y[lst_fb_idx + 1],
|
||||
&denoiser->running_avg_y[INTRA_FRAME]);
|
||||
}
|
||||
} else {
|
||||
if (refresh_alt_ref_frame) {
|
||||
swap_frame_buffer(&denoiser->running_avg_y[alt_fb_idx + 1],
|
||||
&denoiser->running_avg_y[INTRA_FRAME]);
|
||||
}
|
||||
if (refresh_golden_frame) {
|
||||
swap_frame_buffer(&denoiser->running_avg_y[GOLDEN_FRAME],
|
||||
swap_frame_buffer(&denoiser->running_avg_y[gld_fb_idx + 1],
|
||||
&denoiser->running_avg_y[INTRA_FRAME]);
|
||||
}
|
||||
// For fixed pattern SVC: update denoised last_frame if alt_ref is
|
||||
// refreshed, only for non-zero temporal layer.
|
||||
if (refresh_last_frame ||
|
||||
(refresh_alt_ref_frame && svc_fixed_pattern && temporal_layer_id > 0)) {
|
||||
swap_frame_buffer(&denoiser->running_avg_y[LAST_FRAME],
|
||||
if (refresh_last_frame) {
|
||||
swap_frame_buffer(&denoiser->running_avg_y[lst_fb_idx + 1],
|
||||
&denoiser->running_avg_y[INTRA_FRAME]);
|
||||
}
|
||||
}
|
||||
// For fixed pattern SVC we need to keep track of denoised last_frame for base
|
||||
// temporal layer (since alt_ref refresh may update denoised last_frame on
|
||||
// the upper/middle temporal layers).We do this by copying the current
|
||||
// denoised last into the denoised golden_frame, for temporal_layer_id = 0.
|
||||
// For the fixed pattern SVC golden is always spatial reference and is never
|
||||
// used for denoising, so we can use it to keep track of denoised last_frame.
|
||||
if (svc_fixed_pattern && temporal_layer_id == 0) {
|
||||
copy_frame(&denoiser->running_avg_y[GOLDEN_FRAME],
|
||||
&denoiser->running_avg_y[LAST_FRAME]);
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_denoiser_reset_frame_stats(PICK_MODE_CONTEXT *ctx) {
|
||||
@@ -509,21 +504,62 @@ void vp9_denoiser_update_frame_stats(MODE_INFO *mi, unsigned int sse,
|
||||
}
|
||||
}
|
||||
|
||||
static int vp9_denoiser_realloc_svc_helper(VP9_COMMON *cm,
|
||||
VP9_DENOISER *denoiser, int fb_idx) {
|
||||
int fail = 0;
|
||||
if (denoiser->running_avg_y[fb_idx].buffer_alloc == NULL) {
|
||||
fail =
|
||||
vpx_alloc_frame_buffer(&denoiser->running_avg_y[fb_idx], cm->width,
|
||||
cm->height, cm->subsampling_x, cm->subsampling_y,
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
cm->use_highbitdepth,
|
||||
#endif
|
||||
VP9_ENC_BORDER_IN_PIXELS, 0);
|
||||
if (fail) {
|
||||
vp9_denoiser_free(denoiser);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vp9_denoiser_realloc_svc(VP9_COMMON *cm, VP9_DENOISER *denoiser,
|
||||
int refresh_alt, int refresh_gld, int refresh_lst,
|
||||
int alt_fb_idx, int gld_fb_idx, int lst_fb_idx) {
|
||||
int fail = 0;
|
||||
if (refresh_alt) {
|
||||
// Increase the frame buffer index by 1 to map it to the buffer index in the
|
||||
// denoiser.
|
||||
fail = vp9_denoiser_realloc_svc_helper(cm, denoiser, alt_fb_idx + 1);
|
||||
if (fail) return 1;
|
||||
}
|
||||
if (refresh_gld) {
|
||||
fail = vp9_denoiser_realloc_svc_helper(cm, denoiser, gld_fb_idx + 1);
|
||||
if (fail) return 1;
|
||||
}
|
||||
if (refresh_lst) {
|
||||
fail = vp9_denoiser_realloc_svc_helper(cm, denoiser, lst_fb_idx + 1);
|
||||
if (fail) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vp9_denoiser_alloc(VP9_COMMON *cm, int use_svc, VP9_DENOISER *denoiser,
|
||||
int width, int height, int ssx, int ssy,
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
int use_highbitdepth,
|
||||
#endif
|
||||
int border) {
|
||||
int i, fail;
|
||||
int i, fail, init_num_ref_frames;
|
||||
const int legacy_byte_alignment = 0;
|
||||
assert(denoiser != NULL);
|
||||
|
||||
denoiser->num_ref_frames = use_svc ? MAX_REF_FRAMES : NONSVC_REF_FRAMES;
|
||||
denoiser->num_ref_frames = use_svc ? SVC_REF_FRAMES : NONSVC_REF_FRAMES;
|
||||
init_num_ref_frames = use_svc ? MAX_REF_FRAMES : NONSVC_REF_FRAMES;
|
||||
CHECK_MEM_ERROR(
|
||||
cm, denoiser->running_avg_y,
|
||||
vpx_calloc(denoiser->num_ref_frames, sizeof(denoiser->running_avg_y[0])));
|
||||
for (i = 0; i < denoiser->num_ref_frames; ++i) {
|
||||
for (i = 0; i < init_num_ref_frames; ++i) {
|
||||
fail = vpx_alloc_frame_buffer(&denoiser->running_avg_y[i], width, height,
|
||||
ssx, ssy,
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
@@ -594,7 +630,8 @@ void vp9_denoiser_set_noise_level(VP9_DENOISER *denoiser, int noise_level) {
|
||||
denoiser->prev_denoising_level = denoiser->denoising_level;
|
||||
}
|
||||
|
||||
// Scale/increase the partition threshold for denoiser speed-up.
|
||||
// Scale/increase the partition threshold
|
||||
// for denoiser speed-up.
|
||||
int64_t vp9_scale_part_thresh(int64_t threshold, VP9_DENOISER_LEVEL noise_level,
|
||||
int content_state, int temporal_layer_id) {
|
||||
if ((content_state == kLowSadLowSumdiff) ||
|
||||
@@ -609,7 +646,8 @@ int64_t vp9_scale_part_thresh(int64_t threshold, VP9_DENOISER_LEVEL noise_level,
|
||||
}
|
||||
}
|
||||
|
||||
// Scale/increase the ac skip threshold for denoiser speed-up.
|
||||
// Scale/increase the ac skip threshold for
|
||||
// denoiser speed-up.
|
||||
int64_t vp9_scale_acskip_thresh(int64_t threshold,
|
||||
VP9_DENOISER_LEVEL noise_level, int abs_sumdiff,
|
||||
int temporal_layer_id) {
|
||||
|
||||
@@ -25,6 +25,10 @@ extern "C" {
|
||||
// need to allocate for it, and hence we need MAX_REF_FRAME - 1
|
||||
#define NONSVC_REF_FRAMES MAX_REF_FRAMES - 1
|
||||
|
||||
// Number of frame buffers when SVC is used. [0] for current denoised buffer and
|
||||
// [1..8] for REF_FRAMES
|
||||
#define SVC_REF_FRAMES 9
|
||||
|
||||
typedef enum vp9_denoiser_decision {
|
||||
COPY_BLOCK,
|
||||
FILTER_BLOCK,
|
||||
@@ -63,13 +67,11 @@ typedef struct {
|
||||
|
||||
struct VP9_COMP;
|
||||
|
||||
void vp9_denoise_init_svc(struct VP9_COMP *cpi);
|
||||
|
||||
void vp9_denoiser_update_frame_info(
|
||||
VP9_DENOISER *denoiser, YV12_BUFFER_CONFIG src, FRAME_TYPE frame_type,
|
||||
int refresh_alt_ref_frame, int refresh_golden_frame, int refresh_last_frame,
|
||||
int resized, int svc_base_is_key, int svc_fixed_pattern,
|
||||
int temporal_layer_id);
|
||||
int alt_fb_idx, int gld_fb_idx, int lst_fb_idx, int resized,
|
||||
int svc_base_is_key);
|
||||
|
||||
void vp9_denoiser_denoise(struct VP9_COMP *cpi, MACROBLOCK *mb, int mi_row,
|
||||
int mi_col, BLOCK_SIZE bs, PICK_MODE_CONTEXT *ctx,
|
||||
@@ -81,6 +83,10 @@ void vp9_denoiser_update_frame_stats(MODE_INFO *mi, unsigned int sse,
|
||||
PREDICTION_MODE mode,
|
||||
PICK_MODE_CONTEXT *ctx);
|
||||
|
||||
int vp9_denoiser_realloc_svc(VP9_COMMON *cm, VP9_DENOISER *denoiser,
|
||||
int refresh_alt, int refresh_gld, int refresh_lst,
|
||||
int alt_fb_idx, int gld_fb_idx, int lst_fb_idx);
|
||||
|
||||
int vp9_denoiser_alloc(VP9_COMMON *cm, int use_svc, VP9_DENOISER *denoiser,
|
||||
int width, int height, int ssx, int ssy,
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
|
||||
@@ -2833,21 +2833,29 @@ void vp9_update_reference_frames(VP9_COMP *cpi) {
|
||||
if (cpi->oxcf.noise_sensitivity > 0 && denoise_svc(cpi) &&
|
||||
cpi->denoiser.denoising_level > kDenLowLow) {
|
||||
int svc_base_is_key = 0;
|
||||
int svc_fixed_pattern = 0;
|
||||
if (cpi->use_svc) {
|
||||
int realloc_fail = 0;
|
||||
int layer = LAYER_IDS_TO_IDX(cpi->svc.spatial_layer_id,
|
||||
cpi->svc.temporal_layer_id,
|
||||
cpi->svc.number_temporal_layers);
|
||||
LAYER_CONTEXT *lc = &cpi->svc.layer_context[layer];
|
||||
svc_base_is_key = lc->is_key_frame;
|
||||
svc_fixed_pattern = (cpi->svc.temporal_layering_mode !=
|
||||
VP9E_TEMPORAL_LAYERING_MODE_BYPASS);
|
||||
|
||||
// Check if we need to allocate extra buffers in the denoiser for
|
||||
// refreshed frames.
|
||||
realloc_fail = vp9_denoiser_realloc_svc(
|
||||
cm, &cpi->denoiser, cpi->refresh_alt_ref_frame,
|
||||
cpi->refresh_golden_frame, cpi->refresh_last_frame, cpi->alt_fb_idx,
|
||||
cpi->gld_fb_idx, cpi->lst_fb_idx);
|
||||
if (realloc_fail)
|
||||
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
|
||||
"Failed to re-allocate denoiser for SVC");
|
||||
}
|
||||
vp9_denoiser_update_frame_info(
|
||||
&cpi->denoiser, *cpi->Source, cpi->common.frame_type,
|
||||
cpi->refresh_alt_ref_frame, cpi->refresh_golden_frame,
|
||||
cpi->refresh_last_frame, cpi->resize_pending, svc_base_is_key,
|
||||
svc_fixed_pattern, cpi->svc.temporal_layer_id);
|
||||
cpi->refresh_last_frame, cpi->alt_fb_idx, cpi->gld_fb_idx,
|
||||
cpi->lst_fb_idx, cpi->resize_pending, svc_base_is_key);
|
||||
}
|
||||
#endif
|
||||
if (is_one_pass_cbr_svc(cpi)) {
|
||||
@@ -3481,12 +3489,6 @@ static void encode_without_recode_loop(VP9_COMP *cpi, size_t *size,
|
||||
|
||||
vp9_update_noise_estimate(cpi);
|
||||
|
||||
#if CONFIG_VP9_TEMPORAL_DENOISING
|
||||
if (cpi->oxcf.noise_sensitivity > 0 && cpi->use_svc &&
|
||||
cpi->denoiser.denoising_level > kDenLowLow)
|
||||
vp9_denoise_init_svc(cpi);
|
||||
#endif
|
||||
|
||||
// Scene detection is always used for VBR mode or screen-content case.
|
||||
// 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).
|
||||
|
||||
Reference in New Issue
Block a user