Newer
Older
* Copyright (c) 2010 The WebM project authors. All Rights Reserved.
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
#include <limits.h>
#include <math.h>
#include <stdio.h>
#include "./vpx_config.h"
#include "vpx_ports/vpx_timer.h"
#include "vp9/common/vp9_entropymode.h"
#include "vp9/common/vp9_findnearmv.h"
#include "vp9/common/vp9_idct.h"
#include "vp9/common/vp9_mvref_common.h"
#include "vp9/common/vp9_pred_common.h"
#include "vp9/common/vp9_quant_common.h"
#include "vp9/common/vp9_tile_common.h"
#include "vp9/encoder/vp9_encodeframe.h"
#include "vp9/encoder/vp9_encodemb.h"
#include "vp9/encoder/vp9_encodemv.h"
#include "vp9/encoder/vp9_extend.h"
#include "vp9/encoder/vp9_onyx_int.h"
#include "vp9/encoder/vp9_rdopt.h"
#include "vp9/encoder/vp9_segmentation.h"
#include "vp9/common/vp9_systemdependent.h"
#include "vp9/encoder/vp9_vaq.h"
static INLINE uint8_t *get_sb_index(MACROBLOCK *x, BLOCK_SIZE subsize) {
switch (subsize) {
case BLOCK_64X64:
case BLOCK_64X32:
case BLOCK_32X64:
case BLOCK_32X32:
return &x->sb_index;
case BLOCK_32X16:
case BLOCK_16X32:
case BLOCK_16X16:
return &x->mb_index;
case BLOCK_16X8:
case BLOCK_8X16:
case BLOCK_8X8:
return &x->b_index;
case BLOCK_8X4:
case BLOCK_4X8:
case BLOCK_4X4:
return &x->ab_index;
default:
assert(0);
return NULL;
}
}
static void encode_superblock(VP9_COMP *cpi, TOKENEXTRA **t, int output_enabled,
int mi_row, int mi_col, BLOCK_SIZE bsize);
static void adjust_act_zbin(VP9_COMP *cpi, MACROBLOCK *x);
/* activity_avg must be positive, or flat regions could get a zero weight
* (infinite lambda), which confounds analysis.
* This also avoids the need for divide by zero checks in
* vp9_activity_masking().
#define ACTIVITY_AVG_MIN (64)
/* Motion vector component magnitude threshold for defining fast motion. */
#define FAST_MOTION_MV_THRESH (24)
/* This is used as a reference when computing the source variance for the
* purposes of activity masking.
* Eventually this should be replaced by custom no-reference routines,
* which will be faster.
*/
static const uint8_t VP9_VAR_OFFS[64] = {
128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128
};
static unsigned int get_sby_perpixel_variance(VP9_COMP *cpi, MACROBLOCK *x,
BLOCK_SIZE bs) {
unsigned int var, sse;
var = cpi->fn_ptr[bs].vf(x->plane[0].src.buf,
x->plane[0].src.stride,
VP9_VAR_OFFS, 0, &sse);
return (var + (1 << (num_pels_log2_lookup[bs] - 1))) >>
num_pels_log2_lookup[bs];
}
// Original activity measure from Tim T's code.
static unsigned int tt_activity_measure(MACROBLOCK *x) {
unsigned int act;
unsigned int sse;
/* TODO: This could also be done over smaller areas (8x8), but that would
* require extensive changes elsewhere, as lambda is assumed to be fixed
* over an entire MB in most of the code.
* Another option is to compute four 8x8 variances, and pick a single
* lambda using a non-linear combination (e.g., the smallest, or second
* smallest, etc.).
*/
act = vp9_variance16x16(x->plane[0].src.buf, x->plane[0].src.stride,
VP9_VAR_OFFS, 0, &sse);
/* If the region is flat, lower the activity some more. */
if (act < 8 << 12)
act = act < 5 << 12 ? act : 5 << 12;
return act;
// Stub for alternative experimental activity measures.
static unsigned int alt_activity_measure(MACROBLOCK *x, int use_dc_pred) {
return vp9_encode_intra(x, use_dc_pred);
}
// Measure the activity of the current macroblock
// What we measure here is TBD so abstracted to this function
static unsigned int mb_activity_measure(MACROBLOCK *x, int mb_row, int mb_col) {
if (ALT_ACT_MEASURE) {
int use_dc_pred = (mb_col || mb_row) && (!mb_col || !mb_row);
mb_activity = alt_activity_measure(x, use_dc_pred);
} else {
// Original activity measure from Tim T's code.
mb_activity = tt_activity_measure(x);
if (mb_activity < ACTIVITY_AVG_MIN)
mb_activity = ACTIVITY_AVG_MIN;
}
// Calculate an "average" mb activity value for the frame
static void calc_av_activity(VP9_COMP *cpi, int64_t activity_sum) {
// Find median: Simple n^2 algorithm for experimentation
{
unsigned int median;
unsigned int i, j;
unsigned int *sortlist;
unsigned int tmp;
// Create a list to sort to
CHECK_MEM_ERROR(&cpi->common, sortlist, vpx_calloc(sizeof(unsigned int),
cpi->common.MBs));
// Copy map to sort list
vpx_memcpy(sortlist, cpi->mb_activity_map,
// Ripple each value down to its correct position
for (i = 1; i < cpi->common.MBs; i ++) {
for (j = i; j > 0; j --) {
if (sortlist[j] < sortlist[j - 1]) {
// Swap values
tmp = sortlist[j - 1];
sortlist[j - 1] = sortlist[j];
sortlist[j] = tmp;
// Even number MBs so estimate median as mean of two either side.
median = (1 + sortlist[cpi->common.MBs >> 1] +
cpi->activity_avg = (unsigned int) (activity_sum / cpi->common.MBs);
if (cpi->activity_avg < ACTIVITY_AVG_MIN)
cpi->activity_avg = ACTIVITY_AVG_MIN;
// Experimental code: return fixed value normalized for several clips
if (ALT_ACT_MEASURE)
cpi->activity_avg = 100000;
// Calculate an activity index for each mb
static void calc_activity_index(VP9_COMP *cpi, MACROBLOCK *x) {
VP9_COMMON *const cm = &cpi->common;
FILE *f = fopen("norm_act.stt", "a");
fprintf(f, "\n%12d\n", cpi->activity_avg);
// Reset pointers to start of activity map
x->mb_activity_ptr = cpi->mb_activity_map;
// Calculate normalized mb activity number.
for (mb_row = 0; mb_row < cm->mb_rows; mb_row++) {
// for each macroblock col in image
for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) {
// Read activity from the map
act = *(x->mb_activity_ptr);
// Calculate a normalized activity number
a = act + 4 * cpi->activity_avg;
b = 4 * act + cpi->activity_avg;
*(x->activity_ptr) = (int)((b + (a >> 1)) / a) - 1;
*(x->activity_ptr) = 1 - (int)((a + (b >> 1)) / b);
// Increment activity map pointers
x->mb_activity_ptr++;
}
// Loop through all MBs. Note activity of each, average activity and
// calculate a normalized activity for each
static void build_activity_map(VP9_COMP *cpi) {
YV12_BUFFER_CONFIG *new_yv12 = get_frame_new_buffer(cm);
int recon_yoffset;
int recon_y_stride = new_yv12->y_stride;
int mb_row, mb_col;
unsigned int mb_activity;
int64_t activity_sum = 0;
x->mb_activity_ptr = cpi->mb_activity_map;
// for each macroblock row in image
for (mb_row = 0; mb_row < cm->mb_rows; mb_row++) {
// reset above block coeffs
xd->up_available = (mb_row != 0);
recon_yoffset = (mb_row * recon_y_stride * 16);
// for each macroblock col in image
for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) {
xd->plane[0].dst.buf = new_yv12->y_buffer + recon_yoffset;
xd->left_available = (mb_col != 0);
recon_yoffset += 16;
mb_activity = mb_activity_measure(x, mb_row, mb_col);
// Store MB level activity details.
*x->mb_activity_ptr = mb_activity;
// Increment activity map pointer
x->mb_activity_ptr++;
x->plane[0].src.buf += 16 * x->plane[0].src.stride - 16 * cm->mb_cols;
// Calculate an "average" MB activity
calc_av_activity(cpi, activity_sum);
// Calculate an activity index number of each mb
calc_activity_index(cpi, x);
void vp9_activity_masking(VP9_COMP *cpi, MACROBLOCK *x) {
x->rdmult += *(x->mb_activity_ptr) * (x->rdmult >> 2);
x->errorperbit = x->rdmult * 100 / (110 * x->rddiv);
x->errorperbit += (x->errorperbit == 0);
int64_t a;
int64_t b;
int64_t act = *(x->mb_activity_ptr);
// Apply the masking to the RD multiplier.
a = act + (2 * cpi->activity_avg);
b = (2 * act) + cpi->activity_avg;
x->rdmult = (unsigned int) (((int64_t) x->rdmult * b + (a >> 1)) / a);
x->errorperbit = x->rdmult * 100 / (110 * x->rddiv);
x->errorperbit += (x->errorperbit == 0);
// Activity based Zbin adjustment
adjust_act_zbin(cpi, x);
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
// 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) {
VP9_COMMON *const cm = &cpi->common;
MACROBLOCK *const x = &cpi->mb;
MACROBLOCKD *const xd = &x->e_mbd;
struct macroblock_plane *const p = x->plane;
struct macroblockd_plane *const pd = xd->plane;
MB_MODE_INFO *const mbmi = &xd->mi_8x8[0]->mbmi;
MODE_INFO *mi_addr = xd->mi_8x8[0];
const int mis = cm->mode_info_stride;
const int mi_height = num_8x8_blocks_high_lookup[bsize];
assert(mi->mbmi.mode < MB_MODE_COUNT);
assert(mi->mbmi.ref_frame[0] < MAX_REF_FRAMES);
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;
max_plane = is_inter_block(mbmi) ? MAX_MB_PLANE : 1;
for (i = 0; i < max_plane; ++i) {
p[i].coeff = ctx->coeff_pbuf[i][1];
pd[i].qcoeff = ctx->qcoeff_pbuf[i][1];
pd[i].dqcoeff = ctx->dqcoeff_pbuf[i][1];
pd[i].eobs = ctx->eobs_pbuf[i][1];
}
for (i = max_plane; i < MAX_MB_PLANE; ++i) {
p[i].coeff = ctx->coeff_pbuf[i][2];
pd[i].qcoeff = ctx->qcoeff_pbuf[i][2];
pd[i].dqcoeff = ctx->dqcoeff_pbuf[i][2];
pd[i].eobs = ctx->eobs_pbuf[i][2];
}
// Restore the coding context of the MB to that that was in place
// when the mode was picked for it
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->mi_8x8[x_idx + y * mis] = mi_addr;
if ((cpi->oxcf.aq_mode == VARIANCE_AQ) ||
(cpi->oxcf.aq_mode == COMPLEXITY_AQ)) {
vp9_mb_init_quantizer(cpi, x);
}
// FIXME(rbultje) I'm pretty sure this should go to the end of this block
// (i.e. after the output_enabled)
if (bsize < BLOCK_32X32) {
if (bsize < BLOCK_16X16)
ctx->tx_rd_diff[ALLOW_16X16] = ctx->tx_rd_diff[ALLOW_8X8];
ctx->tx_rd_diff[ALLOW_32X32] = ctx->tx_rd_diff[ALLOW_16X16];
if (is_inter_block(mbmi) && mbmi->sb_type < BLOCK_8X8) {
mbmi->mv[0].as_int = mi->bmi[3].as_mv[0].as_int;
mbmi->mv[1].as_int = mi->bmi[3].as_mv[1].as_int;
x->skip = ctx->skip;
vpx_memcpy(x->zcoeff_blk[mbmi->tx_size], ctx->zcoeff_blk,
sizeof(uint8_t) * ctx->num_4x4_blk);
if (!vp9_segfeature_active(&cm->seg, mbmi->segment_id, SEG_LVL_SKIP)) {
for (i = 0; i < TX_MODES; i++)
cpi->rd_tx_select_diff[i] += ctx->tx_rd_diff[i];
if (frame_is_intra_only(cm)) {
#if CONFIG_INTERNAL_STATS
static const int kf_mode_index[] = {
THR_DC /*DC_PRED*/,
THR_V_PRED /*V_PRED*/,
THR_H_PRED /*H_PRED*/,
THR_D45_PRED /*D45_PRED*/,
THR_D135_PRED /*D135_PRED*/,
THR_D117_PRED /*D117_PRED*/,
THR_D153_PRED /*D153_PRED*/,
cpi->mode_chosen_counts[kf_mode_index[mi->mbmi.mode]]++;
} else {
// Note how often each mode chosen as best
cpi->mode_chosen_counts[mb_mode_index]++;
&& (mbmi->sb_type < BLOCK_8X8 || mbmi->mode == NEWMV)) {
const MV_REFERENCE_FRAME rf1 = mbmi->ref_frame[0];
const MV_REFERENCE_FRAME rf2 = mbmi->ref_frame[1];
best_mv[0].as_int = ctx->best_ref_mv.as_int;
best_mv[1].as_int = ctx->second_best_ref_mv.as_int;
best_mv[0].as_int = mbmi->ref_mvs[rf1][0].as_int;
best_mv[1].as_int = mbmi->ref_mvs[rf2][0].as_int;
mbmi->best_mv[0].as_int = best_mv[0].as_int;
mbmi->best_mv[1].as_int = best_mv[1].as_int;
vp9_update_mv_count(cpi, x, best_mv);
if (cm->mcomp_filter_type == SWITCHABLE && is_inter_mode(mbmi->mode)) {
const int ctx = vp9_get_pred_context_switchable_interp(xd);
++cm->counts.switchable_interp[ctx][mbmi->interp_filter];
cpi->rd_comp_pred_diff[SINGLE_REFERENCE] += ctx->single_pred_diff;
cpi->rd_comp_pred_diff[COMPOUND_REFERENCE] += ctx->comp_pred_diff;
cpi->rd_comp_pred_diff[REFERENCE_MODE_SELECT] += ctx->hybrid_pred_diff;
for (i = 0; i < SWITCHABLE_FILTER_CONTEXTS; i++)
cpi->rd_filter_diff[i] += ctx->best_filter_diff[i];
void vp9_setup_src_planes(MACROBLOCK *x, const YV12_BUFFER_CONFIG *src,
int mi_row, int mi_col) {
uint8_t *const buffers[4] = {src->y_buffer, src->u_buffer, src->v_buffer,
src->alpha_buffer};
const int strides[4] = {src->y_stride, src->uv_stride, src->uv_stride,
src->alpha_stride};
for (i = 0; i < MAX_MB_PLANE; i++)
setup_pred_plane(&x->plane[i].src, buffers[i], strides[i], mi_row, mi_col,
x->e_mbd.plane[i].subsampling_y);
static void set_offsets(VP9_COMP *cpi, const TileInfo *const tile,
int mi_row, int mi_col, BLOCK_SIZE bsize) {
MACROBLOCK *const x = &cpi->mb;
VP9_COMMON *const cm = &cpi->common;
MACROBLOCKD *const xd = &x->e_mbd;
MB_MODE_INFO *mbmi;
const int dst_fb_idx = cm->new_fb_idx;
const int idx_str = xd->mode_info_stride * mi_row + mi_col;
const int mi_width = num_8x8_blocks_wide_lookup[bsize];
const int mi_height = num_8x8_blocks_high_lookup[bsize];
const int mb_row = mi_row >> 1;
const int mb_col = mi_col >> 1;
const int idx_map = mb_row * cm->mb_cols + mb_col;
const struct segmentation *const seg = &cm->seg;
set_skip_context(xd, cpi->above_context, cpi->left_context, mi_row, mi_col);
// Activity map pointer
x->mb_activity_ptr = &cpi->mb_activity_map[idx_map];
x->active_ptr = cpi->active_map + idx_map;
xd->mi_8x8 = cm->mi_grid_visible + idx_str;
xd->prev_mi_8x8 = cm->prev_mi_grid_visible + idx_str;
// Special case: if prev_mi is NULL, the previous mode info context
// cannot be used.
xd->last_mi = cm->prev_mi ? xd->prev_mi_8x8[0] : NULL;
xd->mi_8x8[0] = cm->mi + idx_str;
mbmi = &xd->mi_8x8[0]->mbmi;
setup_dst_planes(xd, &cm->yv12_fb[dst_fb_idx], mi_row, mi_col);
// Set up limit values for MV components
// mv beyond the range do not produce new/different prediction block
x->mv_row_min = -(((mi_row + mi_height) * MI_SIZE) + VP9_INTERP_EXTEND);
x->mv_col_min = -(((mi_col + mi_width) * MI_SIZE) + VP9_INTERP_EXTEND);
x->mv_row_max = (cm->mi_rows - mi_row) * MI_SIZE + VP9_INTERP_EXTEND;
x->mv_col_max = (cm->mi_cols - mi_col) * MI_SIZE + VP9_INTERP_EXTEND;
// Set up distance of MB to edge of frame in 1/8th pel units
assert(!(mi_col & (mi_width - 1)) && !(mi_row & (mi_height - 1)));
set_mi_row_col(xd, tile, mi_row, mi_height, mi_col, mi_width,
cm->mi_rows, cm->mi_cols);
vp9_setup_src_planes(x, cpi->Source, mi_row, mi_col);
/* R/D setup */
x->rddiv = cpi->RDDIV;
x->rdmult = cpi->RDMULT;
/* segment ID */
if (seg->enabled) {
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);
}
if (seg->enabled && cpi->seg0_cnt > 0
&& !vp9_segfeature_active(seg, 0, SEG_LVL_REF_FRAME)
&& vp9_segfeature_active(seg, 1, SEG_LVL_REF_FRAME)) {
cpi->seg0_progress = (cpi->seg0_idx << 16) / cpi->seg0_cnt;
} else {
const int y = mb_row & ~3;
const int x = mb_col & ~3;
const int p16 = ((mb_row & 1) << 1) + (mb_col & 1);
const int p32 = ((mb_row & 2) << 2) + ((mb_col & 2) << 1);
const int tile_progress = tile->mi_col_start * cm->mb_rows >> 1;
const int mb_cols = (tile->mi_col_end - tile->mi_col_start) >> 1;
cpi->seg0_progress = ((y * mb_cols + x * 4 + p32 + p16 + tile_progress)
<< 16) / cm->MBs;
x->encode_breakout = cpi->segment_encode_breakout[mbmi->segment_id];
x->encode_breakout = cpi->oxcf.encode_breakout;
static void pick_sb_modes(VP9_COMP *cpi, const TileInfo *const tile,
int mi_row, int mi_col,
int *totalrate, int64_t *totaldist,
BLOCK_SIZE bsize, PICK_MODE_CONTEXT *ctx,
VP9_COMMON *const cm = &cpi->common;
MACROBLOCK *const x = &cpi->mb;
MACROBLOCKD *const xd = &x->e_mbd;
struct macroblock_plane *const p = x->plane;
struct macroblockd_plane *const pd = xd->plane;
int i;
int orig_rdmult = x->rdmult;
double rdmult_ratio;
vp9_clear_system_state(); // __asm emms;
rdmult_ratio = 1.0; // avoid uninitialized warnings
// Use the lower precision, but faster, 32x32 fdct for mode selection.
x->use_lp32x32fdct = 1;
if (bsize < BLOCK_8X8) {
// When ab_index = 0 all sub-blocks are handled, so for ab_index != 0
// there is nothing to be done.
if (x->ab_index != 0) {
*totalrate = 0;
*totaldist = 0;
xd->mi_8x8[0]->mbmi.sb_type = bsize;
for (i = 0; i < MAX_MB_PLANE; ++i) {
p[i].coeff = ctx->coeff_pbuf[i][0];
pd[i].qcoeff = ctx->qcoeff_pbuf[i][0];
pd[i].dqcoeff = ctx->dqcoeff_pbuf[i][0];
pd[i].eobs = ctx->eobs_pbuf[i][0];
// Set to zero to make sure we do not use the previous encoded frame stats
xd->mi_8x8[0]->mbmi.skip_coeff = 0;
x->source_variance = get_sby_perpixel_variance(cpi, x, bsize);
if (cpi->oxcf.aq_mode == VARIANCE_AQ) {
int energy;
if (bsize <= BLOCK_16X16) {
energy = x->mb_energy;
} else {
energy = vp9_block_energy(cpi, x, bsize);
}
xd->mi_8x8[0]->mbmi.segment_id = vp9_vaq_segment_id(energy);
rdmult_ratio = vp9_vaq_rdmult_ratio(energy);
vp9_mb_init_quantizer(cpi, x);
}
vp9_activity_masking(cpi, x);
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
// as a predictor for MBs that follow in the SB
if (frame_is_intra_only(cm)) {
vp9_rd_pick_intra_mode_sb(cpi, x, totalrate, totaldist, bsize, ctx,
best_rd);
} else {
if (bsize >= BLOCK_8X8)
vp9_rd_pick_inter_mode_sb(cpi, x, tile, mi_row, mi_col,
totalrate, totaldist, bsize, ctx, best_rd);
vp9_rd_pick_inter_mode_sub8x8(cpi, x, tile, mi_row, mi_col, totalrate,
totaldist, bsize, ctx, best_rd);
}
if (cpi->oxcf.aq_mode == VARIANCE_AQ) {
x->rdmult = orig_rdmult;
if (*totalrate != INT_MAX) {
vp9_clear_system_state(); // __asm emms;
*totalrate = round(*totalrate * rdmult_ratio);
}
}
static void update_stats(VP9_COMP *cpi) {
VP9_COMMON *const cm = &cpi->common;
MACROBLOCK *const x = &cpi->mb;
MACROBLOCKD *const xd = &x->e_mbd;
MODE_INFO *mi = xd->mi_8x8[0];
MB_MODE_INFO *const mbmi = &mi->mbmi;
if (!frame_is_intra_only(cm)) {
const int seg_ref_active = vp9_segfeature_active(&cm->seg, mbmi->segment_id,
SEG_LVL_REF_FRAME);
if (!seg_ref_active)
cpi->intra_inter_count[vp9_get_pred_context_intra_inter(xd)]
[is_inter_block(mbmi)]++;
// If the segment reference feature is enabled we have only a single
// reference frame allowed for the segment so exclude it from
// the reference frame counts used to work out probabilities.
if (is_inter_block(mbmi) && !seg_ref_active) {
if (cm->comp_pred_mode == REFERENCE_MODE_SELECT)
cpi->comp_inter_count[vp9_get_pred_context_comp_inter_inter(cm, xd)]
if (has_second_ref(mbmi)) {
cpi->comp_ref_count[vp9_get_pred_context_comp_ref_p(cm, xd)]
[mbmi->ref_frame[0] == GOLDEN_FRAME]++;
cpi->single_ref_count[vp9_get_pred_context_single_ref_p1(xd)][0]
[mbmi->ref_frame[0] != LAST_FRAME]++;
cpi->single_ref_count[vp9_get_pred_context_single_ref_p2(xd)][1]
static BLOCK_SIZE *get_sb_partitioning(MACROBLOCK *x, BLOCK_SIZE bsize) {
case BLOCK_64X64:
case BLOCK_32X32:
return &x->sb_partitioning[x->sb_index];
case BLOCK_16X16:
return &x->mb_partitioning[x->sb_index][x->mb_index];
case BLOCK_8X8:
return &x->b_partitioning[x->sb_index][x->mb_index][x->b_index];
}
}
static void restore_context(VP9_COMP *cpi, int mi_row, int mi_col,
ENTROPY_CONTEXT a[16 * MAX_MB_PLANE],
ENTROPY_CONTEXT l[16 * MAX_MB_PLANE],
PARTITION_CONTEXT sa[8], PARTITION_CONTEXT sl[8],
BLOCK_SIZE bsize) {
MACROBLOCK *const x = &cpi->mb;
MACROBLOCKD *const xd = &x->e_mbd;
const int num_4x4_blocks_wide = num_4x4_blocks_wide_lookup[bsize];
const int num_4x4_blocks_high = num_4x4_blocks_high_lookup[bsize];
int mi_width = num_8x8_blocks_wide_lookup[bsize];
int mi_height = num_8x8_blocks_high_lookup[bsize];
for (p = 0; p < MAX_MB_PLANE; p++) {
cpi->above_context[p] + ((mi_col * 2) >> xd->plane[p].subsampling_x),
a + num_4x4_blocks_wide * p,
(sizeof(ENTROPY_CONTEXT) * num_4x4_blocks_wide) >>
xd->plane[p].subsampling_x);
+ ((mi_row & MI_MASK) * 2 >> xd->plane[p].subsampling_y),
l + num_4x4_blocks_high * p,
(sizeof(ENTROPY_CONTEXT) * num_4x4_blocks_high) >>
xd->plane[p].subsampling_y);
}
vpx_memcpy(cpi->above_seg_context + mi_col, sa,
sizeof(*cpi->above_seg_context) * mi_width);
vpx_memcpy(cpi->left_seg_context + (mi_row & MI_MASK), sl,
sizeof(cpi->left_seg_context[0]) * mi_height);
static void save_context(VP9_COMP *cpi, int mi_row, int mi_col,
ENTROPY_CONTEXT a[16 * MAX_MB_PLANE],
ENTROPY_CONTEXT l[16 * MAX_MB_PLANE],
PARTITION_CONTEXT sa[8], PARTITION_CONTEXT sl[8],
BLOCK_SIZE bsize) {
const MACROBLOCK *const x = &cpi->mb;
const MACROBLOCKD *const xd = &x->e_mbd;
const int num_4x4_blocks_wide = num_4x4_blocks_wide_lookup[bsize];
const int num_4x4_blocks_high = num_4x4_blocks_high_lookup[bsize];
int mi_width = num_8x8_blocks_wide_lookup[bsize];
int mi_height = num_8x8_blocks_high_lookup[bsize];
// buffer the above/left context information of the block in search.
for (p = 0; p < MAX_MB_PLANE; ++p) {
cpi->above_context[p] + (mi_col * 2 >> xd->plane[p].subsampling_x),
(sizeof(ENTROPY_CONTEXT) * num_4x4_blocks_wide) >>
xd->plane[p].subsampling_x);
+ ((mi_row & MI_MASK) * 2 >> xd->plane[p].subsampling_y),
(sizeof(ENTROPY_CONTEXT) * num_4x4_blocks_high) >>
xd->plane[p].subsampling_y);
}
vpx_memcpy(sa, cpi->above_seg_context + mi_col,
sizeof(*cpi->above_seg_context) * mi_width);
vpx_memcpy(sl, cpi->left_seg_context + (mi_row & MI_MASK),
sizeof(cpi->left_seg_context[0]) * mi_height);
static void encode_b(VP9_COMP *cpi, const TileInfo *const tile,
TOKENEXTRA **tp, int mi_row, int mi_col,
int output_enabled, BLOCK_SIZE bsize, int sub_index) {
VP9_COMMON *const cm = &cpi->common;
MACROBLOCK *const x = &cpi->mb;
if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols)
return;
if (sub_index != -1)
*get_sb_index(x, bsize) = sub_index;
if (bsize < BLOCK_8X8) {
// When ab_index = 0 all sub-blocks are handled, so for ab_index != 0
// there is nothing to be done.
if (x->ab_index > 0)
update_state(cpi, get_block_context(x, bsize), bsize, output_enabled);
encode_superblock(cpi, tp, output_enabled, mi_row, mi_col, bsize);
if (output_enabled) {
(*tp)->token = EOSB_TOKEN;
(*tp)++;
static void encode_sb(VP9_COMP *cpi, const TileInfo *const tile,
TOKENEXTRA **tp, int mi_row, int mi_col,
int output_enabled, BLOCK_SIZE bsize) {
VP9_COMMON *const cm = &cpi->common;
MACROBLOCK *const x = &cpi->mb;
BLOCK_SIZE c1 = BLOCK_8X8;
const int bsl = b_width_log2(bsize), bs = (1 << bsl) / 4;
BLOCK_SIZE subsize;
if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols)
return;
c1 = BLOCK_4X4;
if (bsize >= BLOCK_8X8) {
pl = partition_plane_context(cpi->above_seg_context, cpi->left_seg_context,
c1 = *(get_sb_partitioning(x, bsize));
if (output_enabled && bsize >= BLOCK_8X8)
cm->counts.partition[pl][PARTITION_NONE]++;
encode_b(cpi, tile, tp, mi_row, mi_col, output_enabled, c1, -1);
cm->counts.partition[pl][PARTITION_VERT]++;
encode_b(cpi, tile, tp, mi_row, mi_col, output_enabled, c1, 0);
encode_b(cpi, tile, tp, mi_row, mi_col + bs, output_enabled, c1, 1);
cm->counts.partition[pl][PARTITION_HORZ]++;
encode_b(cpi, tile, tp, mi_row, mi_col, output_enabled, c1, 0);
encode_b(cpi, tile, tp, mi_row + bs, mi_col, output_enabled, c1, 1);
break;
case PARTITION_SPLIT:
subsize = get_subsize(bsize, PARTITION_SPLIT);
cm->counts.partition[pl][PARTITION_SPLIT]++;
for (i = 0; i < 4; i++) {
const int x_idx = i & 1, y_idx = i >> 1;
*get_sb_index(x, subsize) = i;
encode_sb(cpi, tile, tp, mi_row + y_idx * bs, mi_col + x_idx * bs,
output_enabled, subsize);
}
break;
default:
assert(0);
break;
if (partition != PARTITION_SPLIT || bsize == BLOCK_8X8)
update_partition_context(cpi->above_seg_context, cpi->left_seg_context,
mi_row, mi_col, c1, bsize);
// Check to see if the given partition size is allowed for a specified number
// of 8x8 block rows and columns remaining in the image.
// If not then return the largest allowed partition size
static BLOCK_SIZE find_partition_size(BLOCK_SIZE bsize,
int rows_left, int cols_left,
int *bh, int *bw) {
if ((rows_left <= 0) || (cols_left <= 0)) {
return MIN(bsize, BLOCK_8X8);
} else {
for (; bsize > 0; --bsize) {
*bh = num_8x8_blocks_high_lookup[bsize];
*bw = num_8x8_blocks_wide_lookup[bsize];
if ((*bh <= rows_left) && (*bw <= cols_left)) {
break;
}
}
}
return bsize;
}
// This function attempts to set all mode info entries in a given SB64
// to the same block partition size.
// However, at the bottom and right borders of the image the requested size
// may not be allowed in which case this code attempts to choose the largest
// allowable partition.
static void set_partitioning(VP9_COMP *cpi, const TileInfo *const tile,
MODE_INFO **mi_8x8, int mi_row, int mi_col) {
VP9_COMMON *const cm = &cpi->common;
BLOCK_SIZE bsize = cpi->sf.always_this_block_size;
int row8x8_remaining = tile->mi_row_end - mi_row;
int col8x8_remaining = tile->mi_col_end - mi_col;
MODE_INFO * mi_upper_left = cm->mi + mi_row * mis + mi_col;
int bh = num_8x8_blocks_high_lookup[bsize];
int bw = num_8x8_blocks_wide_lookup[bsize];
assert((row8x8_remaining > 0) && (col8x8_remaining > 0));
// Apply the requested partition size to the SB64 if it is all "in image"
if ((col8x8_remaining >= MI_BLOCK_SIZE) &&
(row8x8_remaining >= MI_BLOCK_SIZE)) {
for (block_row = 0; block_row < MI_BLOCK_SIZE; block_row += bh) {
for (block_col = 0; block_col < MI_BLOCK_SIZE; block_col += bw) {
int index = block_row * mis + block_col;
mi_8x8[index] = mi_upper_left + index;
mi_8x8[index]->mbmi.sb_type = bsize;