vp9: force refresh of long term ref when denoiser reset.

This will allocate extra frame buffer if long term temporal reference is
used and denoiser is enabled on non-key frame.

Add test.

Change-Id: I0e8d1fdb9a2d697a8eed7fe6206bcb362e69f1c8
This commit is contained in:
Jerome Jiang
2018-11-29 15:53:41 -08:00
parent 932f8fa04d
commit 28345f9730
10 changed files with 210 additions and 13 deletions

View File

@@ -61,6 +61,8 @@ class DatarateOnePassCbrSvc : public ::svc_test::OnePassCbrSvc {
force_intra_only_frame_ = 0;
superframe_has_intra_only_ = 0;
use_post_encode_drop_ = 0;
denoiser_off_on_ = false;
denoiser_enable_layers_ = false;
}
virtual void BeginPassHook(unsigned int /*pass*/) {}
@@ -181,6 +183,46 @@ class DatarateOnePassCbrSvc : public ::svc_test::OnePassCbrSvc {
}
}
if (denoiser_off_on_) {
encoder->Control(VP9E_SET_AQ_MODE, 3);
// Set inter_layer_pred to INTER_LAYER_PRED_OFF_NONKEY (K-SVC).
encoder->Control(VP9E_SET_SVC_INTER_LAYER_PRED, 2);
if (!denoiser_enable_layers_) {
if (video->frame() == 0)
encoder->Control(VP9E_SET_NOISE_SENSITIVITY, 0);
else if (video->frame() == 100)
encoder->Control(VP9E_SET_NOISE_SENSITIVITY, 1);
} else {
// Cumulative bitrates for top spatial layers, for
// 3 temporal layers.
if (video->frame() == 0) {
encoder->Control(VP9E_SET_NOISE_SENSITIVITY, 0);
// Change layer bitrates to set top spatial layer to 0.
// This is for 3 spatial 3 temporal layers.
// This will trigger skip encoding/dropping of top spatial layer.
cfg_.rc_target_bitrate -= cfg_.layer_target_bitrate[8];
for (int i = 0; i < 3; i++)
bitrate_sl3_[i] = cfg_.layer_target_bitrate[i + 6];
cfg_.layer_target_bitrate[6] = 0;
cfg_.layer_target_bitrate[7] = 0;
cfg_.layer_target_bitrate[8] = 0;
encoder->Config(&cfg_);
} else if (video->frame() == 100) {
// Change layer bitrates to non-zero on top spatial layer.
// This will trigger skip encoding of top spatial layer
// on key frame (period = 100).
for (int i = 0; i < 3; i++)
cfg_.layer_target_bitrate[i + 6] = bitrate_sl3_[i];
cfg_.rc_target_bitrate += cfg_.layer_target_bitrate[8];
encoder->Config(&cfg_);
} else if (video->frame() == 120) {
// Enable denoiser and top spatial layer after key frame (period is
// 100).
encoder->Control(VP9E_SET_NOISE_SENSITIVITY, 1);
}
}
}
if (update_pattern_ && video->frame() >= 100) {
vpx_svc_layer_id_t layer_id;
if (video->frame() == 100) {
@@ -488,6 +530,11 @@ class DatarateOnePassCbrSvc : public ::svc_test::OnePassCbrSvc {
int force_intra_only_frame_;
int superframe_has_intra_only_;
int use_post_encode_drop_;
int bitrate_sl3_[3];
// Denoiser switched on the fly.
bool denoiser_off_on_;
// Top layer enabled on the fly.
bool denoiser_enable_layers_;
};
// Params: speed setting.
@@ -644,6 +691,112 @@ TEST_P(DatarateOnePassCbrSvcSingleBR, OnePassCbrSvc3SL2TLDynamicPatternChange) {
#endif
}
// Check basic rate targeting for 1 pass CBR SVC with 3 spatial and 3 temporal
// layers, for inter_layer_pred=OffKey (K-SVC) and on the fly switching
// of denoiser from off to on (on at frame = 100). Key frame period is set to
// 1000 so denoise is enabled on non-key.
TEST_P(DatarateOnePassCbrSvcSingleBR,
OnePassCbrSvc3SL3TL_DenoiserOffOnFixedLayers) {
cfg_.rc_buf_initial_sz = 500;
cfg_.rc_buf_optimal_sz = 500;
cfg_.rc_buf_sz = 1000;
cfg_.rc_min_quantizer = 0;
cfg_.rc_max_quantizer = 63;
cfg_.rc_end_usage = VPX_CBR;
cfg_.g_lag_in_frames = 0;
cfg_.ss_number_layers = 3;
cfg_.ts_number_layers = 3;
cfg_.ts_rate_decimator[0] = 4;
cfg_.ts_rate_decimator[1] = 2;
cfg_.ts_rate_decimator[2] = 1;
cfg_.temporal_layering_mode = 3;
cfg_.g_error_resilient = 1;
cfg_.g_threads = 1;
svc_params_.scaling_factor_num[0] = 72;
svc_params_.scaling_factor_den[0] = 288;
svc_params_.scaling_factor_num[1] = 144;
svc_params_.scaling_factor_den[1] = 288;
svc_params_.scaling_factor_num[2] = 288;
svc_params_.scaling_factor_den[2] = 288;
cfg_.rc_dropframe_thresh = 30;
cfg_.kf_max_dist = 1000;
number_spatial_layers_ = cfg_.ss_number_layers;
number_temporal_layers_ = cfg_.ts_number_layers;
::libvpx_test::I420VideoSource video("desktop_office1.1280_720-020.yuv", 1280,
720, 30, 1, 0, 300);
top_sl_width_ = 1280;
top_sl_height_ = 720;
cfg_.rc_target_bitrate = 1000;
ResetModel();
denoiser_off_on_ = true;
denoiser_enable_layers_ = false;
AssignLayerBitrates();
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
// Don't check rate targeting on two top spatial layer since they will be
// skipped for part of the sequence.
CheckLayerRateTargeting(number_spatial_layers_ - 2, number_temporal_layers_,
0.78, 1.15);
#if CONFIG_VP9_DECODER
// The non-reference frames are expected to be mismatched frames as the
// encoder will avoid loopfilter on these frames.
EXPECT_EQ(num_nonref_frames_, GetMismatchFrames());
#endif
}
// Check basic rate targeting for 1 pass CBR SVC with 3 spatial and 3 temporal
// layers, for inter_layer_pred=OffKey (K-SVC) and on the fly switching
// of denoiser from off to on, for dynamic layers. Start at 2 spatial layers
// and enable 3rd spatial layer at frame = 100. Use periodic key frame with
// period 100 so enabling of spatial layer occurs at key frame. Enable denoiser
// at frame > 100, after the key frame sync.
TEST_P(DatarateOnePassCbrSvcSingleBR,
OnePassCbrSvc3SL3TL_DenoiserOffOnEnableLayers) {
cfg_.rc_buf_initial_sz = 500;
cfg_.rc_buf_optimal_sz = 500;
cfg_.rc_buf_sz = 1000;
cfg_.rc_min_quantizer = 0;
cfg_.rc_max_quantizer = 63;
cfg_.rc_end_usage = VPX_CBR;
cfg_.g_lag_in_frames = 0;
cfg_.ss_number_layers = 3;
cfg_.ts_number_layers = 3;
cfg_.ts_rate_decimator[0] = 4;
cfg_.ts_rate_decimator[1] = 2;
cfg_.ts_rate_decimator[2] = 1;
cfg_.temporal_layering_mode = 3;
cfg_.g_error_resilient = 1;
cfg_.g_threads = 1;
svc_params_.scaling_factor_num[0] = 72;
svc_params_.scaling_factor_den[0] = 288;
svc_params_.scaling_factor_num[1] = 144;
svc_params_.scaling_factor_den[1] = 288;
svc_params_.scaling_factor_num[2] = 288;
svc_params_.scaling_factor_den[2] = 288;
cfg_.rc_dropframe_thresh = 0;
cfg_.kf_max_dist = 100;
number_spatial_layers_ = cfg_.ss_number_layers;
number_temporal_layers_ = cfg_.ts_number_layers;
::libvpx_test::I420VideoSource video("desktop_office1.1280_720-020.yuv", 1280,
720, 30, 1, 0, 300);
top_sl_width_ = 1280;
top_sl_height_ = 720;
cfg_.rc_target_bitrate = 1000;
ResetModel();
denoiser_off_on_ = true;
denoiser_enable_layers_ = true;
AssignLayerBitrates();
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
// Don't check rate targeting on two top spatial layer since they will be
// skipped for part of the sequence.
CheckLayerRateTargeting(number_spatial_layers_ - 2, number_temporal_layers_,
0.78, 1.15);
#if CONFIG_VP9_DECODER
// The non-reference frames are expected to be mismatched frames as the
// encoder will avoid loopfilter on these frames.
EXPECT_EQ(num_nonref_frames_, GetMismatchFrames());
#endif
}
// Check basic rate targeting for 1 pass CBR SVC with 3 spatial layers and on
// the fly switching to 1 and then 2 and back to 3 spatial layers. This switch
// is done by setting spatial layer bitrates to 0, and then back to non-zero,

View File

@@ -3,6 +3,7 @@ LIBVPX_TEST_SRCS-yes += test-data.mk
# Encoder test source
LIBVPX_TEST_DATA-$(CONFIG_ENCODERS) += hantro_collage_w352h288.yuv
LIBVPX_TEST_DATA-$(CONFIG_ENCODERS) += hantro_odd.yuv
LIBVPX_TEST_DATA-$(CONFIG_ENCODERS) += desktop_office1.1280_720-020.yuv
LIBVPX_TEST_DATA-$(CONFIG_ENCODERS) += park_joy_90p_10_420.y4m
LIBVPX_TEST_DATA-$(CONFIG_ENCODERS) += park_joy_90p_10_422.y4m

View File

@@ -863,3 +863,4 @@ f1026c03efd5da21b381c8eb21f0d64e6d7e4ba3 *invalid-crbug-1558.ivf
eb198c25f861c3fe2cbd310de11eb96843019345 *invalid-crbug-1558.ivf.res
c62b005a9fd32c36a1b3f67de6840330f9915e34 *invalid-crbug-1562.ivf
f0cd8389948ad16085714d96567612136f6a46c5 *invalid-crbug-1562.ivf.res
bac455906360b45338a16dd626ac5f19bc36a307 *desktop_office1.1280_720-020.yuv

View File

@@ -692,6 +692,7 @@ int vp9_denoiser_alloc(VP9_COMMON *cm, struct SVC *svc, VP9_DENOISER *denoiser,
denoiser->denoising_level = kDenLow;
denoiser->prev_denoising_level = kDenLow;
denoiser->reset = 0;
denoiser->current_denoiser_frame = 0;
return 0;
}
@@ -716,13 +717,29 @@ void vp9_denoiser_free(VP9_DENOISER *denoiser) {
vpx_free_frame_buffer(&denoiser->last_source);
}
void vp9_denoiser_set_noise_level(VP9_DENOISER *denoiser, int noise_level) {
static void force_refresh_longterm_ref(VP9_COMP *const cpi) {
SVC *const svc = &cpi->svc;
// If long term reference is used, force refresh of that slot, so
// denoiser buffer for long term reference stays in sync.
if (svc->use_gf_temporal_ref_current_layer) {
int index = svc->spatial_layer_id;
if (svc->number_spatial_layers == 3) index = svc->spatial_layer_id - 1;
assert(index >= 0);
cpi->alt_fb_idx = svc->buffer_gf_temporal_ref[index].idx;
cpi->refresh_alt_ref_frame = 1;
}
}
void vp9_denoiser_set_noise_level(VP9_COMP *const cpi, int noise_level) {
VP9_DENOISER *const denoiser = &cpi->denoiser;
denoiser->denoising_level = noise_level;
if (denoiser->denoising_level > kDenLowLow &&
denoiser->prev_denoising_level == kDenLowLow)
denoiser->prev_denoising_level == kDenLowLow) {
denoiser->reset = 1;
else
force_refresh_longterm_ref(cpi);
} else {
denoiser->reset = 0;
}
denoiser->prev_denoising_level = denoiser->denoising_level;
}
@@ -754,14 +771,24 @@ int64_t vp9_scale_acskip_thresh(int64_t threshold,
return threshold;
}
void vp9_denoiser_reset_on_first_frame(VP9_COMP *const cpi) {
if (vp9_denoise_svc_non_key(cpi) &&
cpi->denoiser.current_denoiser_frame == 0) {
cpi->denoiser.reset = 1;
force_refresh_longterm_ref(cpi);
}
}
void vp9_denoiser_update_ref_frame(VP9_COMP *const cpi) {
VP9_COMMON *const cm = &cpi->common;
SVC *const svc = &cpi->svc;
if (cpi->oxcf.noise_sensitivity > 0 && denoise_svc(cpi) &&
cpi->denoiser.denoising_level > kDenLowLow) {
int svc_refresh_denoiser_buffers = 0;
int denoise_svc_second_layer = 0;
FRAME_TYPE frame_type = cm->intra_only ? KEY_FRAME : cm->frame_type;
cpi->denoiser.current_denoiser_frame++;
if (cpi->use_svc) {
const int svc_buf_shift =
svc->number_spatial_layers - svc->spatial_layer_id == 2

View File

@@ -50,6 +50,7 @@ typedef struct vp9_denoiser {
int reset;
int num_ref_frames;
int num_layers;
unsigned int current_denoiser_frame;
VP9_DENOISER_LEVEL denoising_level;
VP9_DENOISER_LEVEL prev_denoising_level;
} VP9_DENOISER;
@@ -111,7 +112,9 @@ static INLINE int total_adj_strong_thresh(BLOCK_SIZE bs,
void vp9_denoiser_free(VP9_DENOISER *denoiser);
void vp9_denoiser_set_noise_level(VP9_DENOISER *denoiser, int noise_level);
void vp9_denoiser_set_noise_level(struct VP9_COMP *const cpi, int noise_level);
void vp9_denoiser_reset_on_first_frame(struct VP9_COMP *const cpi);
int64_t vp9_scale_part_thresh(int64_t threshold, VP9_DENOISER_LEVEL noise_level,
int content_state, int temporal_layer_id);

View File

@@ -3815,6 +3815,10 @@ static int encode_without_recode_loop(VP9_COMP *cpi, size_t *size,
cm->mi_rows * cm->mi_cols * sizeof(*cpi->consec_zero_mv));
}
#if CONFIG_VP9_TEMPORAL_DENOISING
if (cpi->oxcf.noise_sensitivity > 0 && cpi->use_svc)
vp9_denoiser_reset_on_first_frame(cpi);
#endif
vp9_update_noise_estimate(cpi);
// Scene detection is always used for VBR mode or screen-content case.

View File

@@ -159,7 +159,7 @@ void vp9_update_noise_estimate(VP9_COMP *const cpi) {
#if CONFIG_VP9_TEMPORAL_DENOISING
if (cpi->oxcf.noise_sensitivity > 0 && noise_est_svc(cpi) &&
cpi->svc.current_superframe > 1) {
vp9_denoiser_set_noise_level(&cpi->denoiser, ne->level);
vp9_denoiser_set_noise_level(cpi, ne->level);
copy_frame(&cpi->denoiser.last_source, cpi->Source);
}
#endif
@@ -269,7 +269,7 @@ void vp9_update_noise_estimate(VP9_COMP *const cpi) {
ne->level = vp9_noise_estimate_extract_level(ne);
#if CONFIG_VP9_TEMPORAL_DENOISING
if (cpi->oxcf.noise_sensitivity > 0 && noise_est_svc(cpi))
vp9_denoiser_set_noise_level(&cpi->denoiser, ne->level);
vp9_denoiser_set_noise_level(cpi, ne->level);
#endif
}
}

View File

@@ -1815,13 +1815,7 @@ void vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x, TileDataEnc *tile_data,
#if CONFIG_VP9_TEMPORAL_DENOISING
if (cpi->oxcf.noise_sensitivity > 0) {
if (cpi->use_svc) {
int layer =
LAYER_IDS_TO_IDX(svc->spatial_layer_id, svc->temporal_layer_id,
svc->number_temporal_layers);
LAYER_CONTEXT *lc = &svc->layer_context[layer];
denoise_svc_pickmode = denoise_svc(cpi) && !lc->is_key_frame;
}
if (cpi->use_svc) denoise_svc_pickmode = vp9_denoise_svc_non_key(cpi);
if (cpi->denoiser.denoising_level > kDenLowLow && denoise_svc_pickmode)
vp9_denoiser_reset_frame_stats(ctx);
}

View File

@@ -1106,6 +1106,16 @@ void vp9_svc_assert_constraints_pattern(VP9_COMP *const cpi) {
}
}
#if CONFIG_VP9_TEMPORAL_DENOISING
int vp9_denoise_svc_non_key(VP9_COMP *const cpi) {
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];
return denoise_svc(cpi) && !lc->is_key_frame;
}
#endif
void vp9_svc_check_spatial_layer_sync(VP9_COMP *const cpi) {
SVC *const svc = &cpi->svc;
// Only for superframes whose base is not key, as those are

View File

@@ -235,6 +235,10 @@ struct lookahead_entry *vp9_svc_lookahead_pop(struct VP9_COMP *const cpi,
// Start a frame and initialize svc parameters
int vp9_svc_start_frame(struct VP9_COMP *const cpi);
#if CONFIG_VP9_TEMPORAL_DENOISING
int vp9_denoise_svc_non_key(struct VP9_COMP *const cpi);
#endif
void vp9_copy_flags_ref_update_idx(struct VP9_COMP *const cpi);
int vp9_one_pass_cbr_svc_start_layer(struct VP9_COMP *const cpi);