From c760c33b993c26376631474a54f2f04a58aaf8a2 Mon Sep 17 00:00:00 2001 From: Marco Date: Mon, 7 Dec 2015 12:23:56 -0800 Subject: [PATCH 1/7] SVC 1 pass mode: Constrain inter mode search within superframe. Keep track of frame indexes for the references, and constrain inter mode search for reference with same temporal alignment. Improves speed by about ~15%, no noticeable loss in compression performance. Change-Id: I5c407a8acca921234060c4fcef4afd7d734201c8 --- vp9/encoder/vp9_encoder.c | 16 ++++++++++++++++ vp9/encoder/vp9_pickmode.c | 20 +++++++++++++++++++- vp9/encoder/vp9_svc_layercontext.c | 9 ++++++++- vp9/encoder/vp9_svc_layercontext.h | 3 +++ 4 files changed, 46 insertions(+), 2 deletions(-) diff --git a/vp9/encoder/vp9_encoder.c b/vp9/encoder/vp9_encoder.c index 72fa82835..9c4351897 100644 --- a/vp9/encoder/vp9_encoder.c +++ b/vp9/encoder/vp9_encoder.c @@ -2793,6 +2793,22 @@ void vp9_update_reference_frames(VP9_COMP *cpi) { cpi->resize_pending); } #endif + if (is_one_pass_cbr_svc(cpi)) { + // Keep track of frame index for each reference frame. + SVC *const svc = &cpi->svc; + if (cm->frame_type == KEY_FRAME) { + svc->ref_frame_index[cpi->lst_fb_idx] = svc->current_superframe; + svc->ref_frame_index[cpi->gld_fb_idx] = svc->current_superframe; + svc->ref_frame_index[cpi->alt_fb_idx] = svc->current_superframe; + } else { + if (cpi->refresh_last_frame) + svc->ref_frame_index[cpi->lst_fb_idx] = svc->current_superframe; + if (cpi->refresh_golden_frame) + svc->ref_frame_index[cpi->gld_fb_idx] = svc->current_superframe; + if (cpi->refresh_alt_ref_frame) + svc->ref_frame_index[cpi->alt_fb_idx] = svc->current_superframe; + } + } } static void loopfilter_frame(VP9_COMP *cpi, VP9_COMMON *cm) { diff --git a/vp9/encoder/vp9_pickmode.c b/vp9/encoder/vp9_pickmode.c index 90650dbe8..9b69ede2b 100644 --- a/vp9/encoder/vp9_pickmode.c +++ b/vp9/encoder/vp9_pickmode.c @@ -1094,6 +1094,7 @@ void vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bsize, PICK_MODE_CONTEXT *ctx) { VP9_COMMON *const cm = &cpi->common; SPEED_FEATURES *const sf = &cpi->sf; + const SVC *const svc = &cpi->svc; TileInfo *const tile_info = &tile_data->tile_info; MACROBLOCKD *const xd = &x->e_mbd; MB_MODE_INFO *const mbmi = &xd->mi[0]->mbmi; @@ -1143,6 +1144,7 @@ void vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x, int best_pred_sad = INT_MAX; int best_early_term = 0; int ref_frame_cost[MAX_REF_FRAMES]; + int svc_force_zero_mode[3] = {0}; #if CONFIG_VP9_TEMPORAL_DENOISING int64_t zero_last_cost_orig = INT64_MAX; #endif @@ -1196,6 +1198,17 @@ void vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x, } else { usable_ref_frame = GOLDEN_FRAME; } + + // If the reference is temporally aligned with current superframe + // (e.g., spatial reference within superframe), constrain the inter mode: + // for now only test zero motion. + if (cpi->use_svc && svc ->force_zero_mode_spatial_ref) { + if (svc->ref_frame_index[cpi->lst_fb_idx] == svc->current_superframe) + svc_force_zero_mode[LAST_FRAME - 1] = 1; + if (svc->ref_frame_index[cpi->gld_fb_idx] == svc->current_superframe) + svc_force_zero_mode[GOLDEN_FRAME - 1] = 1; + } + for (ref_frame = LAST_FRAME; ref_frame <= usable_ref_frame; ++ref_frame) { const YV12_BUFFER_CONFIG *yv12 = get_ref_frame_buffer(cpi, ref_frame); @@ -1248,8 +1261,13 @@ void vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x, continue; ref_frame = ref_mode_set[idx].ref_frame; - if (cpi->use_svc) + if (cpi->use_svc) { ref_frame = ref_mode_set_svc[idx].ref_frame; + if (svc_force_zero_mode[ref_frame - 1] && + frame_mv[this_mode][ref_frame].as_int != 0) + continue; + } + if (!(cpi->ref_frame_flags & flag_list[ref_frame])) continue; if (const_motion[ref_frame] && this_mode == NEARMV) diff --git a/vp9/encoder/vp9_svc_layercontext.c b/vp9/encoder/vp9_svc_layercontext.c index b0617c1ca..a4e7eb19e 100644 --- a/vp9/encoder/vp9_svc_layercontext.c +++ b/vp9/encoder/vp9_svc_layercontext.c @@ -25,13 +25,17 @@ void vp9_init_layer_context(VP9_COMP *const cpi) { const VP9EncoderConfig *const oxcf = &cpi->oxcf; int mi_rows = cpi->common.mi_rows; int mi_cols = cpi->common.mi_cols; - int sl, tl; + int sl, tl, i; int alt_ref_idx = svc->number_spatial_layers; svc->spatial_layer_id = 0; svc->temporal_layer_id = 0; svc->first_spatial_layer_to_encode = 0; svc->rc_drop_superframe = 0; + svc->force_zero_mode_spatial_ref = 0; + svc->current_superframe = 0; + for (i = 0; i < REF_FRAMES; ++i) + svc->ref_frame_index[i] = -1; if (cpi->oxcf.error_resilient_mode == 0 && cpi->oxcf.pass == 2) { if (vpx_realloc_frame_buffer(&cpi->svc.empty_frame.img, @@ -353,6 +357,8 @@ void vp9_inc_frame_in_layer(VP9_COMP *const cpi) { cpi->svc.number_temporal_layers]; ++lc->current_video_frame_in_layer; ++lc->frames_from_key_frame; + if (cpi->svc.spatial_layer_id == cpi->svc.number_spatial_layers - 1) + ++cpi->svc.current_superframe; } int vp9_is_upper_layer_key_frame(const VP9_COMP *const cpi) { @@ -542,6 +548,7 @@ static void set_flags_and_fb_idx_for_temporal_mode_noLayering( int vp9_one_pass_cbr_svc_start_layer(VP9_COMP *const cpi) { int width = 0, height = 0; LAYER_CONTEXT *lc = NULL; + cpi->svc.force_zero_mode_spatial_ref = 1; if (cpi->svc.temporal_layering_mode == VP9E_TEMPORAL_LAYERING_MODE_0212) { set_flags_and_fb_idx_for_temporal_mode3(cpi); diff --git a/vp9/encoder/vp9_svc_layercontext.h b/vp9/encoder/vp9_svc_layercontext.h index 5dbf9b418..1f446d743 100644 --- a/vp9/encoder/vp9_svc_layercontext.h +++ b/vp9/encoder/vp9_svc_layercontext.h @@ -83,6 +83,9 @@ typedef struct { int ext_lst_fb_idx[VPX_MAX_LAYERS]; int ext_gld_fb_idx[VPX_MAX_LAYERS]; int ext_alt_fb_idx[VPX_MAX_LAYERS]; + int ref_frame_index[REF_FRAMES]; + int force_zero_mode_spatial_ref; + int current_superframe; } SVC; struct VP9_COMP; From c7101830a6f1e58c5e441eb29cecbefdb6c5632a Mon Sep 17 00:00:00 2001 From: Yaowu Xu Date: Mon, 14 Dec 2015 18:49:59 -0800 Subject: [PATCH 2/7] Fix a enc/dec mismatch under CONFIG_MISC_FIXES The culprit is on the decode side xd->lossless[i] setup was in wrong location where segment features are not yet decoded. Also on the encoder side, transform mode was not set consistently between when tx_mode is selected and how tx_mode is enforced in tx size selection. Change-Id: I4c4c32188fda7530cadab9b46d4201f33f7ceca3 --- vp10/decoder/decodeframe.c | 35 ++++++++++++++++++----------------- vp10/encoder/bitstream.c | 23 ++++++++++++----------- vp10/encoder/rdopt.c | 2 +- 3 files changed, 31 insertions(+), 29 deletions(-) diff --git a/vp10/decoder/decodeframe.c b/vp10/decoder/decodeframe.c index 70d012b27..31b9c7e49 100644 --- a/vp10/decoder/decodeframe.c +++ b/vp10/decoder/decodeframe.c @@ -1143,24 +1143,13 @@ static INLINE int read_delta_q(struct vpx_read_bit_buffer *rb) { vpx_rb_read_inv_signed_literal(rb, CONFIG_MISC_FIXES ? 6 : 4) : 0; } -static void setup_quantization(VP10_COMMON *const cm, MACROBLOCKD *const xd, +static void setup_quantization(VP10_COMMON *const cm, struct vpx_read_bit_buffer *rb) { - int i; - cm->base_qindex = vpx_rb_read_literal(rb, QINDEX_BITS); cm->y_dc_delta_q = read_delta_q(rb); cm->uv_dc_delta_q = read_delta_q(rb); cm->uv_ac_delta_q = read_delta_q(rb); cm->dequant_bit_depth = cm->bit_depth; - for (i = 0; i < MAX_SEGMENTS; ++i) { - const int qindex = CONFIG_MISC_FIXES && cm->seg.enabled ? - vp10_get_qindex(&cm->seg, i, cm->base_qindex) : - cm->base_qindex; - xd->lossless[i] = qindex == 0 && - cm->y_dc_delta_q == 0 && - cm->uv_dc_delta_q == 0 && - cm->uv_ac_delta_q == 0; - } #if CONFIG_VP9_HIGHBITDEPTH xd->bd = (int)cm->bit_depth; @@ -1874,9 +1863,7 @@ static void read_bitdepth_colorspace_sampling( static size_t read_uncompressed_header(VP10Decoder *pbi, struct vpx_read_bit_buffer *rb) { VP10_COMMON *const cm = &pbi->common; -#if CONFIG_MISC_FIXES MACROBLOCKD *const xd = &pbi->mb; -#endif BufferPool *const pool = cm->buffer_pool; RefCntBuffer *const frame_bufs = pool->frame_bufs; int i, mask, ref_index = 0; @@ -2104,12 +2091,26 @@ static size_t read_uncompressed_header(VP10Decoder *pbi, vp10_setup_past_independence(cm); setup_loopfilter(&cm->lf, rb); - setup_quantization(cm, &pbi->mb, rb); + setup_quantization(cm, rb); setup_segmentation(cm, rb); + + { + int i; + for (i = 0; i < MAX_SEGMENTS; ++i) { + const int qindex = CONFIG_MISC_FIXES && cm->seg.enabled ? + vp10_get_qindex(&cm->seg, i, cm->base_qindex) : + cm->base_qindex; + xd->lossless[i] = qindex == 0 && + cm->y_dc_delta_q == 0 && + cm->uv_dc_delta_q == 0 && + cm->uv_ac_delta_q == 0; + } + } + setup_segmentation_dequant(cm); #if CONFIG_MISC_FIXES - cm->tx_mode = (!cm->seg.enabled && xd->lossless[0]) ? ONLY_4X4 - : read_tx_mode(rb); + cm->tx_mode = (xd->lossless[0]) ? ONLY_4X4 + : read_tx_mode(rb); cm->reference_mode = read_frame_reference_mode(cm, rb); #endif diff --git a/vp10/encoder/bitstream.c b/vp10/encoder/bitstream.c index 5f6d9d342..361ac9962 100644 --- a/vp10/encoder/bitstream.c +++ b/vp10/encoder/bitstream.c @@ -897,18 +897,17 @@ static void write_txfm_mode(TX_MODE mode, struct vpx_write_bit_buffer *wb) { if (mode != TX_MODE_SELECT) vpx_wb_write_literal(wb, mode, 2); } +#else +static void write_txfm_mode(TX_MODE mode, struct vpx_writer *wb) { + vpx_write_literal(wb, VPXMIN(mode, ALLOW_32X32), 2); + if (mode >= ALLOW_32X32) + vpx_write_bit(wb, mode == TX_MODE_SELECT); +} #endif + static void update_txfm_probs(VP10_COMMON *cm, vpx_writer *w, FRAME_COUNTS *counts) { -#if !CONFIG_MISC_FIXES - // Mode - vpx_write_literal(w, VPXMIN(cm->tx_mode, ALLOW_32X32), 2); - if (cm->tx_mode >= ALLOW_32X32) - vpx_write_bit(w, cm->tx_mode == TX_MODE_SELECT); - - // Probabilities -#endif if (cm->tx_mode == TX_MODE_SELECT) { int i, j; @@ -1261,7 +1260,7 @@ static void write_uncompressed_header(VP10_COMP *cpi, encode_quantization(cm, wb); encode_segmentation(cm, xd, wb); #if CONFIG_MISC_FIXES - if (!cm->seg.enabled && xd->lossless[0]) + if (xd->lossless[0]) cm->tx_mode = TX_4X4; else write_txfm_mode(cm->tx_mode, wb); @@ -1291,10 +1290,12 @@ static size_t write_compressed_header(VP10_COMP *cpi, uint8_t *data) { vpx_start_encode(&header_bc, data); #if !CONFIG_MISC_FIXES - if (cpi->td.mb.e_mbd.lossless[0]) + if (cpi->td.mb.e_mbd.lossless[0]) { cm->tx_mode = TX_4X4; - else + } else { + write_txfm_mode(cm->tx_mode, &header_bc); update_txfm_probs(cm, &header_bc, counts); + } #else update_txfm_probs(cm, &header_bc, counts); #endif diff --git a/vp10/encoder/rdopt.c b/vp10/encoder/rdopt.c index 974700e19..a9ed27d15 100644 --- a/vp10/encoder/rdopt.c +++ b/vp10/encoder/rdopt.c @@ -725,7 +725,7 @@ static void super_block_yrd(VP10_COMP *cpi, MACROBLOCK *x, int *rate, assert(bs == xd->mi[0]->mbmi.sb_type); - if (CONFIG_MISC_FIXES && xd->lossless[xd->mi[0]->mbmi.segment_id]) { + if (CONFIG_MISC_FIXES && xd->lossless[0]) { choose_smallest_tx_size(cpi, x, rate, distortion, skip, ret_sse, ref_best_rd, bs); } else if (cpi->sf.tx_size_search_method == USE_LARGESTALL || From cea5e1c1e362ea37612346ed1585ae28089c1f45 Mon Sep 17 00:00:00 2001 From: paulwilkins Date: Tue, 15 Dec 2015 10:27:51 +0000 Subject: [PATCH 3/7] 1 pass VBR mode bug fix. The one pass VBR mode selects a Q range based on a moving average of recent Q values. This calculation should have been excluding arf overlay frames as these are usually coded at the highest allowed value. Their inclusion skews the average and can cause it to drift upwards even when the clip as a whole is undershooting. As such it can undermine correct adaptation of the allowed Q range especially for easy content. Change-Id: I7d10fe4227262376aa2dc2a7aec0f1fd82bf11f9 --- vp9/encoder/vp9_ratectrl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vp9/encoder/vp9_ratectrl.c b/vp9/encoder/vp9_ratectrl.c index 8ab51cd20..22b0f8c1b 100644 --- a/vp9/encoder/vp9_ratectrl.c +++ b/vp9/encoder/vp9_ratectrl.c @@ -1313,9 +1313,9 @@ void vp9_rc_postencode_update(VP9_COMP *cpi, uint64_t bytes_used) { } } } else { - if (rc->is_src_frame_alt_ref || - !(cpi->refresh_golden_frame || cpi->refresh_alt_ref_frame) || - (cpi->use_svc && oxcf->rc_mode == VPX_CBR)) { + if ((cpi->use_svc && oxcf->rc_mode == VPX_CBR) || + (!rc->is_src_frame_alt_ref && + !(cpi->refresh_golden_frame || cpi->refresh_alt_ref_frame))) { rc->last_q[INTER_FRAME] = qindex; rc->avg_frame_qindex[INTER_FRAME] = ROUND_POWER_OF_TWO(3 * rc->avg_frame_qindex[INTER_FRAME] + qindex, 2); From fc50d95b2e576ca7a5420a749d93a5755d479ce0 Mon Sep 17 00:00:00 2001 From: paulwilkins Date: Mon, 14 Dec 2015 12:34:25 +0000 Subject: [PATCH 4/7] Fixed interval, fixed Q 1 pass test patch. For testing implemented a fixed pattern and delta, 1 pass, fixed Q, low delay mode. This has not in any way been tuned or optimized. Change-Id: Idf5ee179b277fa15d07a97f14f2ce5bbaae80a04 --- vp9/encoder/vp9_encoder.c | 6 ++- vp9/encoder/vp9_ratectrl.c | 84 ++++++++++++++++++++++++-------------- vp9/encoder/vp9_ratectrl.h | 1 + 3 files changed, 60 insertions(+), 31 deletions(-) diff --git a/vp9/encoder/vp9_encoder.c b/vp9/encoder/vp9_encoder.c index 72fa82835..bca85a805 100644 --- a/vp9/encoder/vp9_encoder.c +++ b/vp9/encoder/vp9_encoder.c @@ -1478,7 +1478,11 @@ void vp9_change_config(struct VP9_COMP *cpi, const VP9EncoderConfig *oxcf) { cpi->td.mb.e_mbd.bd = (int)cm->bit_depth; #endif // CONFIG_VP9_HIGHBITDEPTH - rc->baseline_gf_interval = (MIN_GF_INTERVAL + MAX_GF_INTERVAL) / 2; + if ((oxcf->pass == 0) && (oxcf->rc_mode == VPX_Q)) { + rc->baseline_gf_interval = FIXED_GF_INTERVAL; + } else { + rc->baseline_gf_interval = (MIN_GF_INTERVAL + MAX_GF_INTERVAL) / 2; + } cpi->refresh_golden_frame = 0; cpi->refresh_last_frame = 1; diff --git a/vp9/encoder/vp9_ratectrl.c b/vp9/encoder/vp9_ratectrl.c index 22b0f8c1b..2579c6005 100644 --- a/vp9/encoder/vp9_ratectrl.c +++ b/vp9/encoder/vp9_ratectrl.c @@ -833,10 +833,16 @@ static int rc_pick_q_and_bounds_one_pass_vbr(const VP9_COMP *cpi, ASSIGN_MINQ_TABLE(cm->bit_depth, inter_minq); if (frame_is_intra_only(cm)) { - // Handle the special case for key frames forced when we have reached - // the maximum key frame interval. Here force the Q to a range - // based on the ambient Q to reduce the risk of popping. - if (rc->this_key_frame_forced) { + if (oxcf->rc_mode == VPX_Q) { + int qindex = cq_level; + double q = vp9_convert_qindex_to_q(qindex, cm->bit_depth); + int delta_qindex = vp9_compute_qdelta(rc, q, q * 0.25, + cm->bit_depth); + active_best_quality = VPXMAX(qindex + delta_qindex, rc->best_quality); + } else if (rc->this_key_frame_forced) { + // Handle the special case for key frames forced when we have reached + // the maximum key frame interval. Here force the Q to a range + // based on the ambient Q to reduce the risk of popping. int qindex = rc->last_boosted_qindex; double last_boosted_q = vp9_convert_qindex_to_q(qindex, cm->bit_depth); int delta_qindex = vp9_compute_qdelta(rc, last_boosted_q, @@ -886,17 +892,28 @@ static int rc_pick_q_and_bounds_one_pass_vbr(const VP9_COMP *cpi, active_best_quality = active_best_quality * 15 / 16; } else if (oxcf->rc_mode == VPX_Q) { - if (!cpi->refresh_alt_ref_frame) { - active_best_quality = cq_level; - } else { - active_best_quality = get_gf_active_quality(rc, q, cm->bit_depth); - } + int qindex = cq_level; + double q = vp9_convert_qindex_to_q(qindex, cm->bit_depth); + int delta_qindex; + if (cpi->refresh_alt_ref_frame) + delta_qindex = vp9_compute_qdelta(rc, q, q * 0.40, cm->bit_depth); + else + delta_qindex = vp9_compute_qdelta(rc, q, q * 0.50, cm->bit_depth); + active_best_quality = VPXMAX(qindex + delta_qindex, rc->best_quality); } else { active_best_quality = get_gf_active_quality(rc, q, cm->bit_depth); } } else { if (oxcf->rc_mode == VPX_Q) { - active_best_quality = cq_level; + int qindex = cq_level; + double q = vp9_convert_qindex_to_q(qindex, cm->bit_depth); + double delta_rate[FIXED_GF_INTERVAL] = + {0.50, 1.0, 0.85, 1.0, 0.70, 1.0, 0.85, 1.0}; + int delta_qindex = + vp9_compute_qdelta(rc, q, + q * delta_rate[cm->current_video_frame % + FIXED_GF_INTERVAL], cm->bit_depth); + active_best_quality = VPXMAX(qindex + delta_qindex, rc->best_quality); } else { // Use the lower of active_worst_quality and recent/average Q. if (cm->current_video_frame > 1) @@ -1722,29 +1739,36 @@ void vp9_rc_set_gf_interval_range(const VP9_COMP *const cpi, RATE_CONTROL *const rc) { const VP9EncoderConfig *const oxcf = &cpi->oxcf; - // Set Maximum gf/arf interval - rc->max_gf_interval = oxcf->max_gf_interval; - rc->min_gf_interval = oxcf->min_gf_interval; - if (rc->min_gf_interval == 0) - rc->min_gf_interval = vp9_rc_get_default_min_gf_interval( - oxcf->width, oxcf->height, cpi->framerate); - if (rc->max_gf_interval == 0) - rc->max_gf_interval = vp9_rc_get_default_max_gf_interval( - cpi->framerate, rc->min_gf_interval); + // Special case code for 1 pass fixed Q mode tests + if ((oxcf->pass == 0) && (oxcf->rc_mode == VPX_Q)) { + rc->max_gf_interval = FIXED_GF_INTERVAL; + rc->min_gf_interval = FIXED_GF_INTERVAL; + rc->static_scene_max_gf_interval = FIXED_GF_INTERVAL; + } else { + // Set Maximum gf/arf interval + rc->max_gf_interval = oxcf->max_gf_interval; + rc->min_gf_interval = oxcf->min_gf_interval; + if (rc->min_gf_interval == 0) + rc->min_gf_interval = vp9_rc_get_default_min_gf_interval( + oxcf->width, oxcf->height, cpi->framerate); + if (rc->max_gf_interval == 0) + rc->max_gf_interval = vp9_rc_get_default_max_gf_interval( + cpi->framerate, rc->min_gf_interval); - // Extended interval for genuinely static scenes - rc->static_scene_max_gf_interval = MAX_LAG_BUFFERS * 2; + // Extended interval for genuinely static scenes + rc->static_scene_max_gf_interval = MAX_LAG_BUFFERS * 2; - if (is_altref_enabled(cpi)) { - if (rc->static_scene_max_gf_interval > oxcf->lag_in_frames - 1) - rc->static_scene_max_gf_interval = oxcf->lag_in_frames - 1; + if (is_altref_enabled(cpi)) { + if (rc->static_scene_max_gf_interval > oxcf->lag_in_frames - 1) + rc->static_scene_max_gf_interval = oxcf->lag_in_frames - 1; + } + + if (rc->max_gf_interval > rc->static_scene_max_gf_interval) + rc->max_gf_interval = rc->static_scene_max_gf_interval; + + // Clamp min to max + rc->min_gf_interval = VPXMIN(rc->min_gf_interval, rc->max_gf_interval); } - - if (rc->max_gf_interval > rc->static_scene_max_gf_interval) - rc->max_gf_interval = rc->static_scene_max_gf_interval; - - // Clamp min to max - rc->min_gf_interval = VPXMIN(rc->min_gf_interval, rc->max_gf_interval); } void vp9_rc_update_framerate(VP9_COMP *cpi) { diff --git a/vp9/encoder/vp9_ratectrl.h b/vp9/encoder/vp9_ratectrl.h index 136fd3e78..3df909cb1 100644 --- a/vp9/encoder/vp9_ratectrl.h +++ b/vp9/encoder/vp9_ratectrl.h @@ -26,6 +26,7 @@ extern "C" { #define MIN_GF_INTERVAL 4 #define MAX_GF_INTERVAL 16 +#define FIXED_GF_INTERVAL 8 // Used in some testing modes only #define ONEHALFONLY_RESIZE 0 typedef enum { From 9ce611a764ec41d8580aad8fad49d8266e009b31 Mon Sep 17 00:00:00 2001 From: paulwilkins Date: Tue, 15 Dec 2015 14:53:44 +0000 Subject: [PATCH 5/7] 1 pass VBR mode bug fix. (copied from VP9) The one pass VBR mode selects a Q range based on a moving average of recent Q values. This calculation should have been excluding arf overlay frames as these are usually coded at the highest allowed value. Their inclusion skews the average and can cause it to drift upwards even when the clip as a whole is undershooting. As such it can undermine correct adaptation of the allowed Q range especially for easy content. Change-Id: I9e12da84e12917e836b6e53ca4dfe4f150b9efb1 --- vp10/encoder/ratectrl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vp10/encoder/ratectrl.c b/vp10/encoder/ratectrl.c index 3ff24768d..64244166c 100644 --- a/vp10/encoder/ratectrl.c +++ b/vp10/encoder/ratectrl.c @@ -1254,7 +1254,7 @@ void vp10_rc_postencode_update(VP10_COMP *cpi, uint64_t bytes_used) { rc->avg_frame_qindex[KEY_FRAME] = ROUND_POWER_OF_TWO(3 * rc->avg_frame_qindex[KEY_FRAME] + qindex, 2); } else { - if (rc->is_src_frame_alt_ref || + if (!rc->is_src_frame_alt_ref && !(cpi->refresh_golden_frame || cpi->refresh_alt_ref_frame)) { rc->last_q[INTER_FRAME] = qindex; rc->avg_frame_qindex[INTER_FRAME] = From 99309004bf349f4d66beb2a90e934fb25855b1e9 Mon Sep 17 00:00:00 2001 From: paulwilkins Date: Tue, 15 Dec 2015 15:23:47 +0000 Subject: [PATCH 6/7] Fixed interval, fixed Q 1 pass test patch. For testing implemented a fixed pattern and delta, 1 pass, fixed Q, low delay mode. This has not in any way been tuned or optimized. Change-Id: Icf9b57c3bb16cc5c0726d5229009212af36eb6d9 --- vp10/encoder/encoder.c | 6 ++- vp10/encoder/ratectrl.c | 90 +++++++++++++++++++++++++---------------- vp10/encoder/ratectrl.h | 1 + 3 files changed, 61 insertions(+), 36 deletions(-) diff --git a/vp10/encoder/encoder.c b/vp10/encoder/encoder.c index 6bba84845..175c6d855 100644 --- a/vp10/encoder/encoder.c +++ b/vp10/encoder/encoder.c @@ -1422,7 +1422,11 @@ void vp10_change_config(struct VP10_COMP *cpi, const VP10EncoderConfig *oxcf) { cpi->td.mb.e_mbd.bd = (int)cm->bit_depth; #endif // CONFIG_VP9_HIGHBITDEPTH - rc->baseline_gf_interval = (MIN_GF_INTERVAL + MAX_GF_INTERVAL) / 2; + if ((oxcf->pass == 0) && (oxcf->rc_mode == VPX_Q)) { + rc->baseline_gf_interval = FIXED_GF_INTERVAL; + } else { + rc->baseline_gf_interval = (MIN_GF_INTERVAL + MAX_GF_INTERVAL) / 2; + } cpi->refresh_golden_frame = 0; cpi->refresh_last_frame = 1; diff --git a/vp10/encoder/ratectrl.c b/vp10/encoder/ratectrl.c index 64244166c..606877594 100644 --- a/vp10/encoder/ratectrl.c +++ b/vp10/encoder/ratectrl.c @@ -794,16 +794,18 @@ static int rc_pick_q_and_bounds_one_pass_vbr(const VP10_COMP *cpi, ASSIGN_MINQ_TABLE(cm->bit_depth, inter_minq); if (frame_is_intra_only(cm)) { - - // Handle the special case for key frames forced when we have reached - // the maximum key frame interval. Here force the Q to a range - // based on the ambient Q to reduce the risk of popping. - if (rc->this_key_frame_forced) { + if (oxcf->rc_mode == VPX_Q) { + int qindex = cq_level; + double q = vp10_convert_qindex_to_q(qindex, cm->bit_depth); + int delta_qindex = vp10_compute_qdelta(rc, q, q * 0.25, + cm->bit_depth); + active_best_quality = VPXMAX(qindex + delta_qindex, rc->best_quality); + } else if (rc->this_key_frame_forced) { int qindex = rc->last_boosted_qindex; double last_boosted_q = vp10_convert_qindex_to_q(qindex, cm->bit_depth); int delta_qindex = vp10_compute_qdelta(rc, last_boosted_q, - last_boosted_q * 0.75, - cm->bit_depth); + last_boosted_q * 0.75, + cm->bit_depth); active_best_quality = VPXMAX(qindex + delta_qindex, rc->best_quality); } else { // not first frame of one pass and kf_boost is set @@ -823,8 +825,8 @@ static int rc_pick_q_and_bounds_one_pass_vbr(const VP10_COMP *cpi, // on active_best_quality. q_val = vp10_convert_qindex_to_q(active_best_quality, cm->bit_depth); active_best_quality += vp10_compute_qdelta(rc, q_val, - q_val * q_adj_factor, - cm->bit_depth); + q_val * q_adj_factor, + cm->bit_depth); } } else if (!rc->is_src_frame_alt_ref && (cpi->refresh_golden_frame || cpi->refresh_alt_ref_frame)) { @@ -848,17 +850,28 @@ static int rc_pick_q_and_bounds_one_pass_vbr(const VP10_COMP *cpi, active_best_quality = active_best_quality * 15 / 16; } else if (oxcf->rc_mode == VPX_Q) { - if (!cpi->refresh_alt_ref_frame) { - active_best_quality = cq_level; - } else { - active_best_quality = get_gf_active_quality(rc, q, cm->bit_depth); - } + int qindex = cq_level; + double q = vp10_convert_qindex_to_q(qindex, cm->bit_depth); + int delta_qindex; + if (cpi->refresh_alt_ref_frame) + delta_qindex = vp10_compute_qdelta(rc, q, q * 0.40, cm->bit_depth); + else + delta_qindex = vp10_compute_qdelta(rc, q, q * 0.50, cm->bit_depth); + active_best_quality = VPXMAX(qindex + delta_qindex, rc->best_quality); } else { active_best_quality = get_gf_active_quality(rc, q, cm->bit_depth); } } else { if (oxcf->rc_mode == VPX_Q) { - active_best_quality = cq_level; + int qindex = cq_level; + double q = vp10_convert_qindex_to_q(qindex, cm->bit_depth); + double delta_rate[FIXED_GF_INTERVAL] = + {0.50, 1.0, 0.85, 1.0, 0.70, 1.0, 0.85, 1.0}; + int delta_qindex = + vp10_compute_qdelta(rc, q, + q * delta_rate[cm->current_video_frame % + FIXED_GF_INTERVAL], cm->bit_depth); + active_best_quality = VPXMAX(qindex + delta_qindex, rc->best_quality); } else { // Use the lower of active_worst_quality and recent/average Q. if (cm->current_video_frame > 1) @@ -1562,29 +1575,36 @@ void vp10_rc_set_gf_interval_range(const VP10_COMP *const cpi, RATE_CONTROL *const rc) { const VP10EncoderConfig *const oxcf = &cpi->oxcf; - // Set Maximum gf/arf interval - rc->max_gf_interval = oxcf->max_gf_interval; - rc->min_gf_interval = oxcf->min_gf_interval; - if (rc->min_gf_interval == 0) - rc->min_gf_interval = vp10_rc_get_default_min_gf_interval( - oxcf->width, oxcf->height, cpi->framerate); - if (rc->max_gf_interval == 0) - rc->max_gf_interval = vp10_rc_get_default_max_gf_interval( - cpi->framerate, rc->min_gf_interval); + // Special case code for 1 pass fixed Q mode tests + if ((oxcf->pass == 0) && (oxcf->rc_mode == VPX_Q)) { + rc->max_gf_interval = FIXED_GF_INTERVAL; + rc->min_gf_interval = FIXED_GF_INTERVAL; + rc->static_scene_max_gf_interval = FIXED_GF_INTERVAL; + } else { + // Set Maximum gf/arf interval + rc->max_gf_interval = oxcf->max_gf_interval; + rc->min_gf_interval = oxcf->min_gf_interval; + if (rc->min_gf_interval == 0) + rc->min_gf_interval = vp10_rc_get_default_min_gf_interval( + oxcf->width, oxcf->height, cpi->framerate); + if (rc->max_gf_interval == 0) + rc->max_gf_interval = vp10_rc_get_default_max_gf_interval( + cpi->framerate, rc->min_gf_interval); - // Extended interval for genuinely static scenes - rc->static_scene_max_gf_interval = MAX_LAG_BUFFERS * 2; + // Extended interval for genuinely static scenes + rc->static_scene_max_gf_interval = MAX_LAG_BUFFERS * 2; - if (is_altref_enabled(cpi)) { - if (rc->static_scene_max_gf_interval > oxcf->lag_in_frames - 1) - rc->static_scene_max_gf_interval = oxcf->lag_in_frames - 1; + if (is_altref_enabled(cpi)) { + if (rc->static_scene_max_gf_interval > oxcf->lag_in_frames - 1) + rc->static_scene_max_gf_interval = oxcf->lag_in_frames - 1; + } + + if (rc->max_gf_interval > rc->static_scene_max_gf_interval) + rc->max_gf_interval = rc->static_scene_max_gf_interval; + + // Clamp min to max + rc->min_gf_interval = VPXMIN(rc->min_gf_interval, rc->max_gf_interval); } - - if (rc->max_gf_interval > rc->static_scene_max_gf_interval) - rc->max_gf_interval = rc->static_scene_max_gf_interval; - - // Clamp min to max - rc->min_gf_interval = VPXMIN(rc->min_gf_interval, rc->max_gf_interval); } void vp10_rc_update_framerate(VP10_COMP *cpi) { diff --git a/vp10/encoder/ratectrl.h b/vp10/encoder/ratectrl.h index 8008c1610..0b9fd456d 100644 --- a/vp10/encoder/ratectrl.h +++ b/vp10/encoder/ratectrl.h @@ -26,6 +26,7 @@ extern "C" { #define MIN_GF_INTERVAL 4 #define MAX_GF_INTERVAL 16 +#define FIXED_GF_INTERVAL 8 // Used in some testing modes only typedef enum { INTER_NORMAL = 0, From f3e7539c6786eb97014f623d8b4ee967b5bdac1c Mon Sep 17 00:00:00 2001 From: Marco Paniconi Date: Tue, 15 Dec 2015 16:44:40 +0000 Subject: [PATCH 7/7] Revert "Add "unknown" status for noise estimation." This reverts commit e15fedb9258251bbb07def57e49e2bd1e0c4c538. Change-Id: Ibf2bce008c727a9754f88814b7630095fa7b8253 --- vp9/encoder/vp9_encodeframe.c | 2 +- vp9/encoder/vp9_noise_estimate.c | 4 ++-- vp9/encoder/vp9_noise_estimate.h | 1 - 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/vp9/encoder/vp9_encodeframe.c b/vp9/encoder/vp9_encodeframe.c index 89f2bd9b8..1606b16a2 100644 --- a/vp9/encoder/vp9_encodeframe.c +++ b/vp9/encoder/vp9_encodeframe.c @@ -496,7 +496,7 @@ static void set_vbp_thresholds(VP9_COMP *cpi, int64_t thresholds[], int q) { threshold_base = 3 * threshold_base; else if (noise_level == kMedium) threshold_base = threshold_base << 1; - else if (noise_level == kLowLow) + else if (noise_level < kLow) threshold_base = (7 * threshold_base) >> 3; } if (cm->width <= 352 && cm->height <= 288) { diff --git a/vp9/encoder/vp9_noise_estimate.c b/vp9/encoder/vp9_noise_estimate.c index 6e717e53c..4befbb066 100644 --- a/vp9/encoder/vp9_noise_estimate.c +++ b/vp9/encoder/vp9_noise_estimate.c @@ -25,7 +25,7 @@ void vp9_noise_estimate_init(NOISE_ESTIMATE *const ne, int width, int height) { ne->enabled = 0; - ne->level = kUnknown; + ne->level = kLowLow; ne->value = 0; ne->count = 0; ne->thresh = 90; @@ -83,7 +83,7 @@ static void copy_frame(YV12_BUFFER_CONFIG * const dest, } NOISE_LEVEL vp9_noise_estimate_extract_level(NOISE_ESTIMATE *const ne) { - int noise_level = kUnknown; + int noise_level = kLowLow; if (ne->value > (ne->thresh << 1)) { noise_level = kHigh; } else { diff --git a/vp9/encoder/vp9_noise_estimate.h b/vp9/encoder/vp9_noise_estimate.h index 266326286..826d125b5 100644 --- a/vp9/encoder/vp9_noise_estimate.h +++ b/vp9/encoder/vp9_noise_estimate.h @@ -24,7 +24,6 @@ extern "C" { #endif typedef enum noise_level { - kUnknown, kLowLow, kLow, kMedium,