Merge "In frame Q adjustment experiment."
This commit is contained in:
commit
cc1e05ca5f
@ -67,6 +67,7 @@ extern "C"
|
||||
typedef enum {
|
||||
NO_AQ = 0,
|
||||
VARIANCE_AQ = 1,
|
||||
COMPLEXITY_AQ = 2,
|
||||
AQ_MODES_COUNT // This should always be the last member of the enum
|
||||
} AQ_MODES;
|
||||
|
||||
|
@ -360,6 +360,52 @@ void vp9_activity_masking(VP9_COMP *cpi, MACROBLOCK *x) {
|
||||
adjust_act_zbin(cpi, x);
|
||||
}
|
||||
|
||||
// Select a segment for the current SB64
|
||||
static void select_in_frame_q_segment(VP9_COMP *cpi,
|
||||
int mi_row, int mi_col,
|
||||
int output_enabled, int projected_rate) {
|
||||
VP9_COMMON * const cm = &cpi->common;
|
||||
int target_rate = cpi->rc.sb64_target_rate << 8; // convert to bits << 8
|
||||
|
||||
const int mi_offset = mi_row * cm->mi_cols + mi_col;
|
||||
const int bw = 1 << mi_width_log2(BLOCK_64X64);
|
||||
const int bh = 1 << mi_height_log2(BLOCK_64X64);
|
||||
const int xmis = MIN(cm->mi_cols - mi_col, bw);
|
||||
const int ymis = MIN(cm->mi_rows - mi_row, bh);
|
||||
int complexity_metric = 64;
|
||||
int x, y;
|
||||
|
||||
unsigned char segment;
|
||||
|
||||
if (!output_enabled) {
|
||||
segment = 0;
|
||||
} else {
|
||||
// Rate depends on fraction of a SB64 in frame (xmis * ymis / bw * bh).
|
||||
// It is converted to bits * 256 units
|
||||
target_rate = (cpi->rc.sb64_target_rate * xmis * ymis * 256) / (bw * bh);
|
||||
|
||||
if (projected_rate < (target_rate / 4)) {
|
||||
segment = 2;
|
||||
} else if (projected_rate < (target_rate / 2)) {
|
||||
segment = 1;
|
||||
} else {
|
||||
segment = 0;
|
||||
}
|
||||
|
||||
complexity_metric =
|
||||
clamp((int)((projected_rate * 64) / target_rate), 16, 255);
|
||||
}
|
||||
|
||||
// Fill in the entires in the segment map corresponding to this SB64
|
||||
for (y = 0; y < ymis; y++) {
|
||||
for (x = 0; x < xmis; x++) {
|
||||
cpi->segmentation_map[mi_offset + y * cm->mi_cols + x] = segment;
|
||||
cpi->complexity_map[mi_offset + y * cm->mi_cols + x] =
|
||||
(unsigned char)complexity_metric;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void update_state(VP9_COMP *cpi, PICK_MODE_CONTEXT *ctx,
|
||||
BLOCK_SIZE bsize, int output_enabled) {
|
||||
int i, x_idx, y;
|
||||
@ -383,6 +429,11 @@ static void update_state(VP9_COMP *cpi, PICK_MODE_CONTEXT *ctx,
|
||||
assert(mi->mbmi.ref_frame[1] < MAX_REF_FRAMES);
|
||||
assert(mi->mbmi.sb_type == bsize);
|
||||
|
||||
// For in frame adaptive Q copy over the chosen segment id into the
|
||||
// mode innfo context for the chosen mode / partition.
|
||||
if ((cpi->oxcf.aq_mode == COMPLEXITY_AQ) && output_enabled)
|
||||
mi->mbmi.segment_id = xd->mi_8x8[0]->mbmi.segment_id;
|
||||
|
||||
*mi_addr = *mi;
|
||||
|
||||
max_plane = is_inter_block(mbmi) ? MAX_MB_PLANE : 1;
|
||||
@ -405,10 +456,12 @@ static void update_state(VP9_COMP *cpi, PICK_MODE_CONTEXT *ctx,
|
||||
for (y = 0; y < mi_height; y++)
|
||||
for (x_idx = 0; x_idx < mi_width; x_idx++)
|
||||
if ((xd->mb_to_right_edge >> (3 + MI_SIZE_LOG2)) + mi_width > x_idx
|
||||
&& (xd->mb_to_bottom_edge >> (3 + MI_SIZE_LOG2)) + mi_height > y)
|
||||
&& (xd->mb_to_bottom_edge >> (3 + MI_SIZE_LOG2)) + mi_height > y) {
|
||||
xd->mi_8x8[x_idx + y * mis] = mi_addr;
|
||||
}
|
||||
|
||||
if (cpi->oxcf.aq_mode == VARIANCE_AQ) {
|
||||
if ((cpi->oxcf.aq_mode == VARIANCE_AQ) ||
|
||||
(cpi->oxcf.aq_mode == COMPLEXITY_AQ)) {
|
||||
vp9_mb_init_quantizer(cpi, x);
|
||||
}
|
||||
|
||||
@ -557,7 +610,7 @@ static void set_offsets(VP9_COMP *cpi, const TileInfo *const tile,
|
||||
|
||||
/* segment ID */
|
||||
if (seg->enabled) {
|
||||
if (!cpi->oxcf.aq_mode == VARIANCE_AQ) {
|
||||
if (cpi->oxcf.aq_mode != VARIANCE_AQ) {
|
||||
uint8_t *map = seg->update_map ? cpi->segmentation_map
|
||||
: cm->last_frame_seg_map;
|
||||
mbmi->segment_id = vp9_get_segment_id(cm, map, bsize, mi_row, mi_col);
|
||||
@ -653,6 +706,14 @@ static void pick_sb_modes(VP9_COMP *cpi, const TileInfo *const tile,
|
||||
if (cpi->oxcf.aq_mode == VARIANCE_AQ) {
|
||||
vp9_clear_system_state(); // __asm emms;
|
||||
x->rdmult = round(x->rdmult * rdmult_ratio);
|
||||
} else if (cpi->oxcf.aq_mode == COMPLEXITY_AQ) {
|
||||
const int mi_offset = mi_row * cm->mi_cols + mi_col;
|
||||
unsigned char complexity = cpi->complexity_map[mi_offset];
|
||||
const int is_edge = (mi_row == 0) || (mi_row == (cm->mi_rows - 1)) ||
|
||||
(mi_col == 0) || (mi_col == (cm->mi_cols - 1));
|
||||
|
||||
if (!is_edge && (complexity > 128))
|
||||
x->rdmult = x->rdmult + ((x->rdmult * (complexity - 128)) / 256);
|
||||
}
|
||||
|
||||
// Find best coding mode & reconstruct the MB so it is available
|
||||
@ -1261,8 +1322,19 @@ static void rd_use_partition(VP9_COMP *cpi,
|
||||
if ( bsize == BLOCK_64X64)
|
||||
assert(chosen_rate < INT_MAX && chosen_dist < INT_MAX);
|
||||
|
||||
if (do_recon)
|
||||
encode_sb(cpi, tile, tp, mi_row, mi_col, bsize == BLOCK_64X64, bsize);
|
||||
if (do_recon) {
|
||||
int output_enabled = (bsize == BLOCK_64X64);
|
||||
|
||||
// Check the projected output rate for this SB against it's target
|
||||
// and and if necessary apply a Q delta using segmentation to get
|
||||
// closer to the target.
|
||||
if ((cpi->oxcf.aq_mode == COMPLEXITY_AQ) && cm->seg.update_map) {
|
||||
select_in_frame_q_segment(cpi, mi_row, mi_col,
|
||||
output_enabled, chosen_rate);
|
||||
}
|
||||
|
||||
encode_sb(cpi, tile, tp, mi_row, mi_col, output_enabled, bsize);
|
||||
}
|
||||
|
||||
*rate = chosen_rate;
|
||||
*dist = chosen_dist;
|
||||
@ -1740,8 +1812,17 @@ static void rd_pick_partition(VP9_COMP *cpi, const TileInfo *const tile,
|
||||
*rate = best_rate;
|
||||
*dist = best_dist;
|
||||
|
||||
if (best_rate < INT_MAX && best_dist < INT64_MAX && do_recon)
|
||||
encode_sb(cpi, tile, tp, mi_row, mi_col, bsize == BLOCK_64X64, bsize);
|
||||
if (best_rate < INT_MAX && best_dist < INT64_MAX && do_recon) {
|
||||
int output_enabled = (bsize == BLOCK_64X64);
|
||||
|
||||
// Check the projected output rate for this SB against it's target
|
||||
// and and if necessary apply a Q delta using segmentation to get
|
||||
// closer to the target.
|
||||
if ((cpi->oxcf.aq_mode == COMPLEXITY_AQ) && cm->seg.update_map) {
|
||||
select_in_frame_q_segment(cpi, mi_row, mi_col, output_enabled, best_rate);
|
||||
}
|
||||
encode_sb(cpi, tile, tp, mi_row, mi_col, output_enabled, bsize);
|
||||
}
|
||||
if (bsize == BLOCK_64X64) {
|
||||
assert(tp_orig < *tp);
|
||||
assert(best_rate < INT_MAX);
|
||||
@ -2415,7 +2496,8 @@ static void encode_superblock(VP9_COMP *cpi, TOKENEXTRA **t, int output_enabled,
|
||||
const int mis = cm->mode_info_stride;
|
||||
const int mi_width = num_8x8_blocks_wide_lookup[bsize];
|
||||
const int mi_height = num_8x8_blocks_high_lookup[bsize];
|
||||
x->skip_recode = !x->select_txfm_size && mbmi->sb_type >= BLOCK_8X8;
|
||||
x->skip_recode = !x->select_txfm_size && mbmi->sb_type >= BLOCK_8X8 &&
|
||||
(cpi->oxcf.aq_mode != COMPLEXITY_AQ);
|
||||
x->skip_optimize = ctx->is_coded;
|
||||
ctx->is_coded = 1;
|
||||
x->use_lp32x32fdct = cpi->sf.use_lp32x32fdct;
|
||||
|
@ -109,6 +109,9 @@ extern unsigned __int64 Sectionbits[500];
|
||||
|
||||
extern void vp9_init_quantizer(VP9_COMP *cpi);
|
||||
|
||||
static const double in_frame_q_adj_ratio[MAX_SEGMENTS] =
|
||||
{1.0, 1.5, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0};
|
||||
|
||||
static INLINE void Scale2Ratio(int mode, int *hr, int *hs) {
|
||||
switch (mode) {
|
||||
case NORMAL:
|
||||
@ -192,6 +195,8 @@ static void dealloc_compressor_data(VP9_COMP *cpi) {
|
||||
vpx_free(cpi->coding_context.last_frame_seg_map_copy);
|
||||
cpi->coding_context.last_frame_seg_map_copy = 0;
|
||||
|
||||
vpx_free(cpi->complexity_map);
|
||||
cpi->complexity_map = 0;
|
||||
vpx_free(cpi->active_map);
|
||||
cpi->active_map = 0;
|
||||
|
||||
@ -243,6 +248,79 @@ int vp9_compute_qdelta(VP9_COMP *cpi, double qstart, double qtarget) {
|
||||
return target_index - start_index;
|
||||
}
|
||||
|
||||
// Computes a q delta (in "q index" terms) to get from a starting q value
|
||||
// to a value that should equate to thegiven rate ratio.
|
||||
|
||||
int vp9_compute_qdelta_by_rate(VP9_COMP *cpi,
|
||||
double base_q_index, double rate_target_ratio) {
|
||||
int i;
|
||||
int base_bits_per_mb;
|
||||
int target_bits_per_mb;
|
||||
int target_index = cpi->rc.worst_quality;
|
||||
|
||||
// Make SURE use of floating point in this function is safe.
|
||||
vp9_clear_system_state();
|
||||
|
||||
// Look up the current projected bits per block for the base index
|
||||
base_bits_per_mb = vp9_bits_per_mb(cpi->common.frame_type,
|
||||
base_q_index, 1.0);
|
||||
|
||||
// Find the target bits per mb based on the base value and given ratio.
|
||||
target_bits_per_mb = rate_target_ratio * base_bits_per_mb;
|
||||
|
||||
// Convert the q target to an index
|
||||
for (i = cpi->rc.best_quality; i < cpi->rc.worst_quality; i++) {
|
||||
target_index = i;
|
||||
if (vp9_bits_per_mb(cpi->common.frame_type,
|
||||
i, 1.0) <= target_bits_per_mb )
|
||||
break;
|
||||
}
|
||||
|
||||
return target_index - base_q_index;
|
||||
}
|
||||
|
||||
// This function sets up a set of segments with delta Q values around
|
||||
// the baseline frame quantizer.
|
||||
static void setup_in_frame_q_adj(VP9_COMP *cpi) {
|
||||
VP9_COMMON *cm = &cpi->common;
|
||||
struct segmentation *seg = &cm->seg;
|
||||
// double q_ratio;
|
||||
int segment;
|
||||
int qindex_delta;
|
||||
|
||||
// Make SURE use of floating point in this function is safe.
|
||||
vp9_clear_system_state();
|
||||
|
||||
if (cm->frame_type == KEY_FRAME ||
|
||||
cpi->refresh_alt_ref_frame ||
|
||||
(cpi->refresh_golden_frame && !cpi->is_src_frame_alt_ref)) {
|
||||
// Clear down the segment map
|
||||
vpx_memset(cpi->segmentation_map, 0, cm->mi_rows * cm->mi_cols);
|
||||
|
||||
// Clear down the complexity map used for rd
|
||||
vpx_memset(cpi->complexity_map, 0, cm->mi_rows * cm->mi_cols);
|
||||
|
||||
// Enable segmentation
|
||||
vp9_enable_segmentation((VP9_PTR)cpi);
|
||||
vp9_clearall_segfeatures(seg);
|
||||
|
||||
// Select delta coding method
|
||||
seg->abs_delta = SEGMENT_DELTADATA;
|
||||
|
||||
// Segment 0 "Q" feature is disabled so it defaults to the baseline Q
|
||||
vp9_disable_segfeature(seg, 0, SEG_LVL_ALT_Q);
|
||||
|
||||
// Use some of the segments for in frame Q adjustment
|
||||
for (segment = 1; segment < 3; segment++) {
|
||||
qindex_delta =
|
||||
vp9_compute_qdelta_by_rate(cpi, cm->base_qindex,
|
||||
in_frame_q_adj_ratio[segment]);
|
||||
vp9_enable_segfeature(seg, segment, SEG_LVL_ALT_Q);
|
||||
vp9_set_segdata(seg, segment, SEG_LVL_ALT_Q, qindex_delta);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void configure_static_seg_features(VP9_COMP *cpi) {
|
||||
VP9_COMMON *cm = &cpi->common;
|
||||
struct segmentation *seg = &cm->seg;
|
||||
@ -1446,6 +1524,11 @@ VP9_PTR vp9_create_compressor(VP9_CONFIG *oxcf) {
|
||||
CHECK_MEM_ERROR(cm, cpi->segmentation_map,
|
||||
vpx_calloc(cm->mi_rows * cm->mi_cols, 1));
|
||||
|
||||
// Create a complexity map used for rd adjustment
|
||||
CHECK_MEM_ERROR(cm, cpi->complexity_map,
|
||||
vpx_calloc(cm->mi_rows * cm->mi_cols, 1));
|
||||
|
||||
|
||||
// And a place holder structure is the coding context
|
||||
// for use if we want to save and restore it
|
||||
CHECK_MEM_ERROR(cm, cpi->coding_context.last_frame_seg_map_copy,
|
||||
@ -2630,8 +2713,12 @@ static void encode_with_recode_loop(VP9_COMP *cpi,
|
||||
}
|
||||
}
|
||||
|
||||
// Variance adaptive and in frame q adjustment experiments are mutually
|
||||
// exclusive.
|
||||
if (cpi->oxcf.aq_mode == VARIANCE_AQ) {
|
||||
vp9_vaq_frame_setup(cpi);
|
||||
vp9_vaq_frame_setup(cpi);
|
||||
} else if (cpi->oxcf.aq_mode == COMPLEXITY_AQ) {
|
||||
setup_in_frame_q_adj(cpi);
|
||||
}
|
||||
|
||||
// transform / motion compensation build reconstruction frame
|
||||
|
@ -293,6 +293,7 @@ typedef struct {
|
||||
// Rate targetting variables
|
||||
int this_frame_target;
|
||||
int projected_frame_size;
|
||||
int sb64_target_rate;
|
||||
int last_q[2]; // Separate values for Intra/Inter
|
||||
int last_boosted_qindex; // Last boosted GF/KF/ARF q
|
||||
|
||||
@ -516,6 +517,8 @@ typedef struct VP9_COMP {
|
||||
// segment threashold for encode breakout
|
||||
int segment_encode_breakout[MAX_SEGMENTS];
|
||||
|
||||
unsigned char *complexity_map;
|
||||
|
||||
unsigned char *active_map;
|
||||
unsigned int active_map_enabled;
|
||||
|
||||
|
@ -242,6 +242,10 @@ static void calc_iframe_target_size(VP9_COMP *cpi) {
|
||||
}
|
||||
|
||||
cpi->rc.this_frame_target = target;
|
||||
|
||||
// Target rate per SB64 (including partial SB64s.
|
||||
cpi->rc.sb64_target_rate = (cpi->rc.this_frame_target * 64 * 64) /
|
||||
(cpi->common.width * cpi->common.height);
|
||||
}
|
||||
|
||||
|
||||
@ -269,6 +273,11 @@ static void calc_pframe_target_size(VP9_COMP *cpi) {
|
||||
cpi->rc.this_frame_target = cpi->rc.per_frame_bandwidth;
|
||||
}
|
||||
|
||||
// Target rate per SB64 (including partial SB64s.
|
||||
cpi->rc.sb64_target_rate = (cpi->rc.this_frame_target * 64 * 64) /
|
||||
(cpi->common.width * cpi->common.height);
|
||||
|
||||
|
||||
// Check that the total sum of adjustments is not above the maximum allowed.
|
||||
// That is, having allowed for the KF and GF penalties, we have not pushed
|
||||
// the current inter-frame target too low. If the adjustment we apply here is
|
||||
|
2
vpxenc.c
2
vpxenc.c
@ -384,7 +384,7 @@ static const arg_def_t frame_parallel_decoding = ARG_DEF(
|
||||
NULL, "frame-parallel", 1, "Enable frame parallel decodability features");
|
||||
static const arg_def_t aq_mode = ARG_DEF(
|
||||
NULL, "aq-mode", 1,
|
||||
"Adaptive quantization mode (0: disabled (by default), 1: variance based)");
|
||||
"Adaptive q mode (0: off (by default), 1: variance 2: complexity)");
|
||||
#endif
|
||||
|
||||
#if CONFIG_VP8_ENCODER
|
||||
|
Loading…
x
Reference in New Issue
Block a user