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_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_systemdependent.h"
#include "vp9/common/vp9_tile_common.h"
#include "vp9/encoder/vp9_aq_complexity.h"
#include "vp9/encoder/vp9_aq_cyclicrefresh.h"
#include "vp9/encoder/vp9_aq_variance.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_rd.h"
#include "vp9/encoder/vp9_rdopt.h"
#include "vp9/encoder/vp9_segmentation.h"
#define GF_ZEROMV_ZBIN_BOOST 0
#define LF_ZEROMV_ZBIN_BOOST 0
#define MV_ZBIN_BOOST 0
#define SPLIT_MV_ZBIN_BOOST 0
#define INTRA_ZBIN_BOOST 0
static void encode_superblock(VP9_COMP *cpi, TOKENEXTRA **t, int output_enabled,
int mi_row, int mi_col, BLOCK_SIZE bsize,
PICK_MODE_CONTEXT *ctx);
// Motion vector component magnitude threshold for defining fast motion.
// 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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#if CONFIG_VP9_HIGHBITDEPTH
static const uint16_t VP9_HIGH_VAR_OFFS_8[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 const uint16_t VP9_HIGH_VAR_OFFS_10[64] = {
128*4, 128*4, 128*4, 128*4, 128*4, 128*4, 128*4, 128*4,
128*4, 128*4, 128*4, 128*4, 128*4, 128*4, 128*4, 128*4,
128*4, 128*4, 128*4, 128*4, 128*4, 128*4, 128*4, 128*4,
128*4, 128*4, 128*4, 128*4, 128*4, 128*4, 128*4, 128*4,
128*4, 128*4, 128*4, 128*4, 128*4, 128*4, 128*4, 128*4,
128*4, 128*4, 128*4, 128*4, 128*4, 128*4, 128*4, 128*4,
128*4, 128*4, 128*4, 128*4, 128*4, 128*4, 128*4, 128*4,
128*4, 128*4, 128*4, 128*4, 128*4, 128*4, 128*4, 128*4
};
static const uint16_t VP9_HIGH_VAR_OFFS_12[64] = {
128*16, 128*16, 128*16, 128*16, 128*16, 128*16, 128*16, 128*16,
128*16, 128*16, 128*16, 128*16, 128*16, 128*16, 128*16, 128*16,
128*16, 128*16, 128*16, 128*16, 128*16, 128*16, 128*16, 128*16,
128*16, 128*16, 128*16, 128*16, 128*16, 128*16, 128*16, 128*16,
128*16, 128*16, 128*16, 128*16, 128*16, 128*16, 128*16, 128*16,
128*16, 128*16, 128*16, 128*16, 128*16, 128*16, 128*16, 128*16,
128*16, 128*16, 128*16, 128*16, 128*16, 128*16, 128*16, 128*16,
128*16, 128*16, 128*16, 128*16, 128*16, 128*16, 128*16, 128*16
};
#endif // CONFIG_VP9_HIGHBITDEPTH
static unsigned int get_sby_perpixel_variance(VP9_COMP *cpi,
const struct buf_2d *ref,
BLOCK_SIZE bs) {
unsigned int sse;
const unsigned int var = cpi->fn_ptr[bs].vf(ref->buf, ref->stride,
VP9_VAR_OFFS, 0, &sse);
return ROUND_POWER_OF_TWO(var, num_pels_log2_lookup[bs]);
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#if CONFIG_VP9_HIGHBITDEPTH
static unsigned int high_get_sby_perpixel_variance(
VP9_COMP *cpi, const struct buf_2d *ref, BLOCK_SIZE bs, int bd) {
unsigned int var, sse;
switch (bd) {
case 10:
var = cpi->fn_ptr[bs].vf(ref->buf, ref->stride,
CONVERT_TO_BYTEPTR(VP9_HIGH_VAR_OFFS_10),
0, &sse);
break;
case 12:
var = cpi->fn_ptr[bs].vf(ref->buf, ref->stride,
CONVERT_TO_BYTEPTR(VP9_HIGH_VAR_OFFS_12),
0, &sse);
break;
case 8:
default:
var = cpi->fn_ptr[bs].vf(ref->buf, ref->stride,
CONVERT_TO_BYTEPTR(VP9_HIGH_VAR_OFFS_8),
0, &sse);
break;
}
return ROUND_POWER_OF_TWO(var, num_pels_log2_lookup[bs]);
}
#endif // CONFIG_VP9_HIGHBITDEPTH
static unsigned int get_sby_perpixel_diff_variance(VP9_COMP *cpi,
const struct buf_2d *ref,
int mi_row, int mi_col,
const YV12_BUFFER_CONFIG *last = get_ref_frame_buffer(cpi, LAST_FRAME);
const uint8_t* last_y = &last->y_buffer[mi_row * MI_SIZE * last->y_stride +
mi_col * MI_SIZE];
unsigned int sse;
const unsigned int var = cpi->fn_ptr[bs].vf(ref->buf, ref->stride,
last_y, last->y_stride, &sse);
return ROUND_POWER_OF_TWO(var, num_pels_log2_lookup[bs]);
}
static BLOCK_SIZE get_rd_var_based_fixed_partition(VP9_COMP *cpi,
int mi_row,
int mi_col) {
unsigned int var = get_sby_perpixel_diff_variance(cpi, &cpi->mb.plane[0].src,
mi_row, mi_col,
BLOCK_64X64);
if (var < 8)
else if (var < 2048)
return BLOCK_16X16;
else
return BLOCK_8X8;
static BLOCK_SIZE get_nonrd_var_based_fixed_partition(VP9_COMP *cpi,
int mi_row,
int mi_col) {
unsigned int var = get_sby_perpixel_diff_variance(cpi, &cpi->mb.plane[0].src,
mi_row, mi_col,
BLOCK_64X64);
return BLOCK_32X32;
else
// Lighter version of set_offsets that only sets the mode info
// pointers.
static INLINE void set_modeinfo_offsets(VP9_COMMON *const cm,
MACROBLOCKD *const xd,
int mi_row,
int mi_col) {
const int idx_str = xd->mi_stride * mi_row + mi_col;
xd->mi = cm->mi + idx_str;
xd->mi[0].src_mi = &xd->mi[0];
}
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 mi_width = num_8x8_blocks_wide_lookup[bsize];
const int mi_height = num_8x8_blocks_high_lookup[bsize];
const struct segmentation *const seg = &cm->seg;
set_skip_context(xd, mi_row, mi_col);
set_modeinfo_offsets(cm, xd, mi_row, mi_col);
// Set up destination pointers.
vp9_setup_dst_planes(xd->plane, get_frame_new_buffer(cm), 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);
// Set up source buffers.
vp9_setup_src_planes(x, cpi->Source, mi_row, mi_col);
// R/D setup.
x->rddiv = cpi->rd.RDDIV;
x->rdmult = cpi->rd.RDMULT;
// Setup segment ID.
if (seg->enabled) {
if (cpi->oxcf.aq_mode != VARIANCE_AQ) {
const uint8_t *const 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);
}
vp9_init_plane_quantizers(cpi, x);
x->encode_breakout = cpi->segment_encode_breakout[mbmi->segment_id];
} else {
mbmi->segment_id = 0;
x->encode_breakout = cpi->encode_breakout;
}
}
static void duplicate_mode_info_in_sb(VP9_COMMON *cm, MACROBLOCKD *xd,
int mi_row, int mi_col,
BLOCK_SIZE bsize) {
const int block_width = num_8x8_blocks_wide_lookup[bsize];
const int block_height = num_8x8_blocks_high_lookup[bsize];
int i, j;
for (j = 0; j < block_height; ++j)
for (i = 0; i < block_width; ++i) {
if (mi_row + j < cm->mi_rows && mi_col + i < cm->mi_cols)
xd->mi[j * xd->mi_stride + i].src_mi = &xd->mi[0];
}
}
static void set_block_size(VP9_COMP * const cpi,
int mi_row, int mi_col,
BLOCK_SIZE bsize) {
if (cpi->common.mi_cols > mi_col && cpi->common.mi_rows > mi_row) {
MACROBLOCKD *const xd = &cpi->mb.e_mbd;
set_modeinfo_offsets(&cpi->common, xd, mi_row, mi_col);
duplicate_mode_info_in_sb(&cpi->common, xd, mi_row, mi_col, bsize);
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
}
}
typedef struct {
int64_t sum_square_error;
int64_t sum_error;
int count;
int variance;
} var;
typedef struct {
var none;
var horz[2];
var vert[2];
} partition_variance;
typedef struct {
partition_variance part_variances;
var split[4];
} v8x8;
typedef struct {
partition_variance part_variances;
v8x8 split[4];
} v16x16;
typedef struct {
partition_variance part_variances;
v16x16 split[4];
} v32x32;
typedef struct {
partition_variance part_variances;
v32x32 split[4];
} v64x64;
typedef struct {
partition_variance *part_variances;
var *split[4];
} variance_node;
typedef enum {
V16X16,
V32X32,
V64X64,
} TREE_LEVEL;
static void tree_to_node(void *data, BLOCK_SIZE bsize, variance_node *node) {
int i;
node->part_variances = NULL;
vpx_memset(node->split, 0, sizeof(node->split));
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
switch (bsize) {
case BLOCK_64X64: {
v64x64 *vt = (v64x64 *) data;
node->part_variances = &vt->part_variances;
for (i = 0; i < 4; i++)
node->split[i] = &vt->split[i].part_variances.none;
break;
}
case BLOCK_32X32: {
v32x32 *vt = (v32x32 *) data;
node->part_variances = &vt->part_variances;
for (i = 0; i < 4; i++)
node->split[i] = &vt->split[i].part_variances.none;
break;
}
case BLOCK_16X16: {
v16x16 *vt = (v16x16 *) data;
node->part_variances = &vt->part_variances;
for (i = 0; i < 4; i++)
node->split[i] = &vt->split[i].part_variances.none;
break;
}
case BLOCK_8X8: {
v8x8 *vt = (v8x8 *) data;
node->part_variances = &vt->part_variances;
for (i = 0; i < 4; i++)
node->split[i] = &vt->split[i];
break;
}
default: {
assert(0);
356
357
358
359
360
361
362
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
}
}
}
// Set variance values given sum square error, sum error, count.
static void fill_variance(int64_t s2, int64_t s, int c, var *v) {
v->sum_square_error = s2;
v->sum_error = s;
v->count = c;
if (c > 0)
v->variance = (int)(256 *
(v->sum_square_error - v->sum_error * v->sum_error /
v->count) / v->count);
else
v->variance = 0;
}
void sum_2_variances(const var *a, const var *b, var *r) {
fill_variance(a->sum_square_error + b->sum_square_error,
a->sum_error + b->sum_error, a->count + b->count, r);
}
static void fill_variance_tree(void *data, BLOCK_SIZE bsize) {
variance_node node;
tree_to_node(data, bsize, &node);
sum_2_variances(node.split[0], node.split[1], &node.part_variances->horz[0]);
sum_2_variances(node.split[2], node.split[3], &node.part_variances->horz[1]);
sum_2_variances(node.split[0], node.split[2], &node.part_variances->vert[0]);
sum_2_variances(node.split[1], node.split[3], &node.part_variances->vert[1]);
sum_2_variances(&node.part_variances->vert[0], &node.part_variances->vert[1],
&node.part_variances->none);
}
static int set_vt_partitioning(VP9_COMP *cpi,
void *data,
BLOCK_SIZE bsize,
int mi_row,
VP9_COMMON * const cm = &cpi->common;
variance_node vt;
const int block_width = num_8x8_blocks_wide_lookup[bsize];
const int block_height = num_8x8_blocks_high_lookup[bsize];
// TODO(debargha): Choose this more intelligently.
const int threshold_multiplier = cm->frame_type == KEY_FRAME ? 64 : 4;
int64_t threshold =
(int64_t)(threshold_multiplier *
vp9_convert_qindex_to_q(cm->base_qindex, cm->bit_depth));
assert(block_height == block_width);
tree_to_node(data, bsize, &vt);
// Split none is available only if we have more than half a block size
// in width and height inside the visible image.
if (mi_col + block_width / 2 < cm->mi_cols &&
mi_row + block_height / 2 < cm->mi_rows &&
vt.part_variances->none.variance < threshold) {
return 1;
}
// Vertical split is available on all but the bottom border.
if (mi_row + block_height / 2 < cm->mi_rows &&
vt.part_variances->vert[0].variance < threshold &&
vt.part_variances->vert[1].variance < threshold) {
BLOCK_SIZE subsize = get_subsize(bsize, PARTITION_VERT);
set_block_size(cpi, mi_row, mi_col, subsize);
set_block_size(cpi, mi_row, mi_col + block_width / 2, subsize);
return 1;
}
// Horizontal split is available on all but the right border.
if (mi_col + block_width / 2 < cm->mi_cols &&
vt.part_variances->horz[0].variance < threshold &&
vt.part_variances->horz[1].variance < threshold) {
BLOCK_SIZE subsize = get_subsize(bsize, PARTITION_HORZ);
set_block_size(cpi, mi_row, mi_col, subsize);
set_block_size(cpi, mi_row + block_height / 2, mi_col, subsize);
return 1;
}
return 0;
}
// TODO(debargha): Fix this function and make it work as expected.
static void choose_partitioning(VP9_COMP *cpi,
const TileInfo *const tile,
int mi_row, int mi_col) {
VP9_COMMON * const cm = &cpi->common;
MACROBLOCK *x = &cpi->mb;
MACROBLOCKD *xd = &cpi->mb.e_mbd;
int i, j, k;
v64x64 vt;
uint8_t *s;
const uint8_t *d;
int sp;
int dp;
int pixels_wide = 64, pixels_high = 64;
int_mv nearest_mv, near_mv;
const YV12_BUFFER_CONFIG *yv12 = get_ref_frame_buffer(cpi, LAST_FRAME);
const struct scale_factors *const sf = &cm->frame_refs[LAST_FRAME - 1].sf;
vp9_clear_system_state();
vp9_zero(vt);
set_offsets(cpi, tile, mi_row, mi_col, BLOCK_64X64);
if (xd->mb_to_right_edge < 0)
pixels_wide += (xd->mb_to_right_edge >> 3);
if (xd->mb_to_bottom_edge < 0)
pixels_high += (xd->mb_to_bottom_edge >> 3);
s = x->plane[0].src.buf;
sp = x->plane[0].src.stride;
if (cm->frame_type != KEY_FRAME) {
vp9_setup_pre_planes(xd, 0, yv12, mi_row, mi_col, sf);
xd->mi[0].src_mi->mbmi.ref_frame[0] = LAST_FRAME;
xd->mi[0].src_mi->mbmi.sb_type = BLOCK_64X64;
vp9_find_best_ref_mvs(xd, cm->allow_high_precision_mv,
&nearest_mv, &near_mv);
vp9_build_inter_predictors_sby(xd, mi_row, mi_col, BLOCK_64X64);
d = xd->plane[0].dst.buf;
dp = xd->plane[0].dst.stride;
} else {
d = VP9_VAR_OFFS;
dp = 0;
#if CONFIG_VP9_HIGHBITDEPTH
if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) {
switch (xd->bd) {
case 10:
d = CONVERT_TO_BYTEPTR(VP9_HIGH_VAR_OFFS_10);
break;
case 12:
d = CONVERT_TO_BYTEPTR(VP9_HIGH_VAR_OFFS_12);
break;
case 8:
default:
d = CONVERT_TO_BYTEPTR(VP9_HIGH_VAR_OFFS_8);
break;
}
}
#endif // CONFIG_VP9_HIGHBITDEPTH
}
// Fill in the entire tree of 8x8 variances for splits.
for (i = 0; i < 4; i++) {
const int x32_idx = ((i & 1) << 5);
const int y32_idx = ((i >> 1) << 5);
for (j = 0; j < 4; j++) {
const int x16_idx = x32_idx + ((j & 1) << 4);
const int y16_idx = y32_idx + ((j >> 1) << 4);
v16x16 *vst = &vt.split[i].split[j];
for (k = 0; k < 4; k++) {
int x_idx = x16_idx + ((k & 1) << 3);
int y_idx = y16_idx + ((k >> 1) << 3);
unsigned int sse = 0;
int sum = 0;
if (x_idx < pixels_wide && y_idx < pixels_high) {
int s_avg = vp9_avg_8x8(s + y_idx * sp + x_idx, sp);
int d_avg = vp9_avg_8x8(d + y_idx * dp + x_idx, dp);
sum = s_avg - d_avg;
sse = sum * sum;
}
// For an 8x8 block we have just one value the average of all 64
// pixels, so use 1. This means of course that there is no variance
// in an 8x8 block.
fill_variance(sse, sum, 1, &vst->split[k].part_variances.none);
}
}
}
// Fill the rest of the variance tree by summing split partition values.
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
fill_variance_tree(&vt.split[i].split[j], BLOCK_16X16);
}
fill_variance_tree(&vt.split[i], BLOCK_32X32);
}
fill_variance_tree(&vt, BLOCK_64X64);
// Now go through the entire structure, splitting every block size until
// we get to one that's got a variance lower than our threshold, or we
// hit 8x8.
if ( mi_col + 8 > cm->mi_cols || mi_row + 8 > cm->mi_rows ||
!set_vt_partitioning(cpi, &vt, BLOCK_64X64, mi_row, mi_col)) {
for (i = 0; i < 4; ++i) {
const int x32_idx = ((i & 1) << 2);
const int y32_idx = ((i >> 1) << 2);
if (!set_vt_partitioning(cpi, &vt.split[i], BLOCK_32X32,
(mi_row + y32_idx), (mi_col + x32_idx))) {
for (j = 0; j < 4; ++j) {
const int x16_idx = ((j & 1) << 1);
const int y16_idx = ((j >> 1) << 1);
// NOTE: This is a temporary hack to disable 8x8 partitions,
// since it works really bad - possibly due to a bug
#define DISABLE_8X8_VAR_BASED_PARTITION
#ifdef DISABLE_8X8_VAR_BASED_PARTITION
if (mi_row + y32_idx + y16_idx + 1 < cm->mi_rows &&
mi_row + x32_idx + x16_idx + 1 < cm->mi_cols) {
(mi_row + y32_idx + y16_idx),
(mi_col + x32_idx + x16_idx),
BLOCK_16X16);
} else {
for (k = 0; k < 4; ++k) {
const int x8_idx = (k & 1);
const int y8_idx = (k >> 1);
(mi_row + y32_idx + y16_idx + y8_idx),
(mi_col + x32_idx + x16_idx + x8_idx),
BLOCK_8X8);
}
}
#else
if (!set_vt_partitioning(cpi, &vt.split[i].split[j],
mi_row + y32_idx + y16_idx,
mi_col + x32_idx + x16_idx)) {
for (k = 0; k < 4; ++k) {
const int x8_idx = (k & 1);
const int y8_idx = (k >> 1);
(mi_row + y32_idx + y16_idx + y8_idx),
(mi_col + x32_idx + x16_idx + x8_idx),
BLOCK_8X8);
}
}
#endif
}
}
}
}
}
static void update_state(VP9_COMP *cpi, PICK_MODE_CONTEXT *ctx,
int mi_row, int mi_col, 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[0].src_mi->mbmi;
MODE_INFO *mi_addr = &xd->mi[0];
const struct segmentation *const seg = &cm->seg;
const int mis = cm->mi_stride;
const int mi_height = num_8x8_blocks_high_lookup[bsize];
assert(mi->mbmi.sb_type == bsize);
*mi_addr = *mi;
// If segmentation in use
if (seg->enabled && output_enabled) {
// For in frame complexity AQ copy the segment id from the segment map.
if (cpi->oxcf.aq_mode == COMPLEXITY_AQ) {
const uint8_t *const map = seg->update_map ? cpi->segmentation_map
: cm->last_frame_seg_map;
mi_addr->mbmi.segment_id =
vp9_get_segment_id(cm, map, bsize, mi_row, mi_col);
}
// Else for cyclic refresh mode update the segment map, set the segment id
// and then update the quantizer.
if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ) {
vp9_cyclic_refresh_update_segment(cpi, &xd->mi[0].src_mi->mbmi,
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];
p[i].qcoeff = ctx->qcoeff_pbuf[i][1];
pd[i].dqcoeff = ctx->dqcoeff_pbuf[i][1];
for (i = max_plane; i < MAX_MB_PLANE; ++i) {
p[i].coeff = ctx->coeff_pbuf[i][2];
p[i].qcoeff = ctx->qcoeff_pbuf[i][2];
pd[i].dqcoeff = ctx->dqcoeff_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) {
if (cpi->oxcf.aq_mode)
// 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++)
#if CONFIG_INTERNAL_STATS
if (frame_is_intra_only(cm)) {
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*/,
THR_D63_PRED /*D63_PRED*/,
THR_TM /*TM_PRED*/,
++cpi->mode_chosen_counts[kf_mode_index[mbmi->mode]];
++cpi->mode_chosen_counts[ctx->best_mode_index];
}
#endif
if (!frame_is_intra_only(cm)) {
vp9_update_mv_count(cm, xd);
if (cm->interp_filter == SWITCHABLE) {
const int ctx = vp9_get_pred_context_switchable_interp(xd);
++cm->counts.switchable_interp[ctx][mbmi->interp_filter];
}
rd_opt->comp_pred_diff[SINGLE_REFERENCE] += ctx->single_pred_diff;
rd_opt->comp_pred_diff[COMPOUND_REFERENCE] += ctx->comp_pred_diff;
rd_opt->comp_pred_diff[REFERENCE_MODE_SELECT] += ctx->hybrid_pred_diff;
for (i = 0; i < SWITCHABLE_FILTER_CONTEXTS; ++i)
rd_opt->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[3] = {src->y_buffer, src->u_buffer, src->v_buffer };
const int strides[3] = {src->y_stride, src->uv_stride, src->uv_stride };
// Set current frame pointer.
x->e_mbd.cur_buf = src;
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_mode_info_seg_skip(MACROBLOCK *x, TX_MODE tx_mode, int *rate,
int64_t *dist, BLOCK_SIZE bsize) {
MACROBLOCKD *const xd = &x->e_mbd;
MB_MODE_INFO *const mbmi = &xd->mi[0].src_mi->mbmi;
INTERP_FILTER filter_ref;
if (xd->up_available)
filter_ref = xd->mi[-xd->mi_stride].src_mi->mbmi.interp_filter;
else if (xd->left_available)
filter_ref = xd->mi[-1].src_mi->mbmi.interp_filter;
else
filter_ref = EIGHTTAP;
mbmi->sb_type = bsize;
mbmi->mode = ZEROMV;
mbmi->tx_size = MIN(max_txsize_lookup[bsize],
tx_mode_to_biggest_tx_size[tx_mode]);
mbmi->skip = 1;
mbmi->uv_mode = DC_PRED;
mbmi->ref_frame[0] = LAST_FRAME;
mbmi->ref_frame[1] = NONE;
mbmi->mv[0].as_int = 0;
mbmi->interp_filter = filter_ref;
x->skip = 1;
*rate = 0;
*dist = 0;
}
static void rd_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,
int64_t best_rd) {
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;
const AQ_MODE aq_mode = cpi->oxcf.aq_mode;
double rdmult_ratio;
vp9_clear_system_state();
rdmult_ratio = 1.0; // avoid uninitialized warnings
// Use the lower precision, but faster, 32x32 fdct for mode selection.
x->use_lp32x32fdct = 1;
for (i = 0; i < MAX_MB_PLANE; ++i) {
p[i].coeff = ctx->coeff_pbuf[i][0];
p[i].qcoeff = ctx->qcoeff_pbuf[i][0];
pd[i].dqcoeff = ctx->dqcoeff_pbuf[i][0];
// Set to zero to make sure we do not use the previous encoded frame stats
#if CONFIG_VP9_HIGHBITDEPTH
if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) {
x->source_variance =
high_get_sby_perpixel_variance(cpi, &x->plane[0].src, bsize, xd->bd);
} else {
x->source_variance =
get_sby_perpixel_variance(cpi, &x->plane[0].src, bsize);
}
#else
x->source_variance = get_sby_perpixel_variance(cpi, &x->plane[0].src, bsize);
#endif // CONFIG_VP9_HIGHBITDEPTH
// Save rdmult before it might be changed, so it can be restored later.
orig_rdmult = x->rdmult;
const int energy = bsize <= BLOCK_16X16 ? x->mb_energy
: vp9_block_energy(cpi, x, bsize);
if (cm->frame_type == KEY_FRAME ||
cpi->refresh_alt_ref_frame ||
(cpi->refresh_golden_frame && !cpi->rc.is_src_frame_alt_ref)) {
mbmi->segment_id = vp9_vaq_segment_id(energy);
} else {
const uint8_t *const map = cm->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);
rdmult_ratio = vp9_vaq_rdmult_ratio(energy);
vp9_clear_system_state();
x->rdmult = (int)round(x->rdmult * rdmult_ratio);
} else if (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 <= 1) || (mi_row >= (cm->mi_rows - 2)) ||
(mi_col <= 1) || (mi_col >= (cm->mi_cols - 2));
if (!is_edge && (complexity > 128))
x->rdmult += ((x->rdmult * (complexity - 128)) / 256);
} else if (aq_mode == CYCLIC_REFRESH_AQ) {
const uint8_t *const map = cm->seg.update_map ? cpi->segmentation_map
// If segment 1, use rdmult for that segment.
if (vp9_get_segment_id(cm, map, bsize, mi_row, mi_col))
x->rdmult = vp9_cyclic_refresh_get_rdmult(cpi->cyclic_refresh);
// 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);
if (bsize >= BLOCK_8X8) {
if (vp9_segfeature_active(&cm->seg, mbmi->segment_id, SEG_LVL_SKIP))
vp9_rd_pick_inter_mode_sb_seg_skip(cpi, x, totalrate, totaldist, bsize,
ctx, best_rd);
else
vp9_rd_pick_inter_mode_sb(cpi, x, tile, mi_row, mi_col,
totalrate, totaldist, bsize, ctx, best_rd);
} else {
vp9_rd_pick_inter_mode_sub8x8(cpi, x, tile, mi_row, mi_col, totalrate,
totaldist, bsize, ctx, best_rd);
x->rdmult = orig_rdmult;
if (aq_mode == VARIANCE_AQ && *totalrate != INT_MAX) {
vp9_clear_system_state();
*totalrate = (int)round(*totalrate * rdmult_ratio);
static void update_stats(VP9_COMMON *cm, const MACROBLOCK *x) {
const MACROBLOCKD *const xd = &x->e_mbd;
const 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) {
FRAME_COUNTS *const counts = &cm->counts;
const int inter_block = is_inter_block(mbmi);
counts->intra_inter[vp9_get_intra_inter_context(xd)][inter_block]++;
// 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 (inter_block) {
const MV_REFERENCE_FRAME ref0 = mbmi->ref_frame[0];
if (cm->reference_mode == REFERENCE_MODE_SELECT)
counts->comp_inter[vp9_get_reference_mode_context(cm, xd)]
[has_second_ref(mbmi)]++;
if (has_second_ref(mbmi)) {
counts->comp_ref[vp9_get_pred_context_comp_ref_p(cm, xd)]
[ref0 == GOLDEN_FRAME]++;
} else {
counts->single_ref[vp9_get_pred_context_single_ref_p1(xd)][0]
[ref0 != LAST_FRAME]++;
if (ref0 != LAST_FRAME)
counts->single_ref[vp9_get_pred_context_single_ref_p2(xd)][1]
[ref0 != GOLDEN_FRAME]++;
}
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++) {
xd->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(xd->above_seg_context + mi_col, sa,
sizeof(*xd->above_seg_context) * mi_width);
vpx_memcpy(xd->left_seg_context + (mi_row & MI_MASK), sl,
sizeof(xd->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) {
xd->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, xd->above_seg_context + mi_col,
sizeof(*xd->above_seg_context) * mi_width);
vpx_memcpy(sl, xd->left_seg_context + (mi_row & MI_MASK),
sizeof(xd->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,
PICK_MODE_CONTEXT *ctx) {
update_state(cpi, ctx, mi_row, mi_col, bsize, output_enabled);
encode_superblock(cpi, tp, output_enabled, mi_row, mi_col, bsize, ctx);
if (output_enabled) {
(*tp)->token = EOSB_TOKEN;
(*tp)++;