vp9_encodeframe.c 116 KB
Newer Older
John Koleszar's avatar
John Koleszar committed
/*
 *  Copyright (c) 2010 The WebM project authors. All Rights Reserved.
John Koleszar's avatar
John Koleszar committed
 *
 *  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.
John Koleszar's avatar
John Koleszar committed
 */

#include <limits.h>
#include <math.h>
#include <stdio.h>

Jim Bankoski's avatar
Jim Bankoski committed
#include "./vp9_rtcd.h"
#include "./vpx_config.h"

#include "vpx_ports/vpx_timer.h"

#include "vp9/common/vp9_common.h"
#include "vp9/common/vp9_entropy.h"
#include "vp9/common/vp9_entropymode.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_reconintra.h"
#include "vp9/common/vp9_reconinter.h"
#include "vp9/common/vp9_seg_common.h"
#include "vp9/common/vp9_systemdependent.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_pickmode.h"
#include "vp9/encoder/vp9_rdopt.h"
#include "vp9/encoder/vp9_segmentation.h"
#include "vp9/encoder/vp9_tokenize.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:
    case BLOCK_32X16:
    case BLOCK_16X32:
    case BLOCK_16X16:
    case BLOCK_16X8:
    case BLOCK_8X16:
    case BLOCK_8X8:
    case BLOCK_8X4:
    case BLOCK_4X8:
    case BLOCK_4X4:
Jim Bankoski's avatar
Jim Bankoski committed
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,
  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 ROUND_POWER_OF_TWO(var, num_pels_log2_lookup[bs]);
static unsigned int get_sby_perpixel_diff_variance(VP9_COMP *cpi,
                                                   MACROBLOCK *x,
                                                   int mi_row,
                                                   int mi_col,
                                                   BLOCK_SIZE bs) {
  const YV12_BUFFER_CONFIG *yv12 = get_ref_frame_buffer(cpi, LAST_FRAME);
  int offset = (mi_row * MI_SIZE) * yv12->y_stride + (mi_col * MI_SIZE);
  unsigned int var, sse;
  var = cpi->fn_ptr[bs].vf(x->plane[0].src.buf,
                           x->plane[0].src.stride,
                           yv12->y_buffer + offset,
                           yv12->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,
                                                    mi_row, mi_col,
                                                    BLOCK_64X64);
  if (var < 8)
    return BLOCK_64X64;
  else if (var < 128)
    return BLOCK_32X32;
  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,
                                                    mi_row, mi_col,
                                                    BLOCK_64X64);
    return BLOCK_64X64;
  else if (var < 10)
    return BLOCK_32X32;
  else
    return BLOCK_16X16;
// 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->mode_info_stride * mi_row + mi_col;
  xd->mi_8x8 = cm->mi_grid_visible + idx_str;
  xd->prev_mi_8x8 = cm->prev_mi_grid_visible + idx_str;
  // xd->last_mi = cm->prev_mi ? xd->prev_mi_8x8[0] : NULL;
  xd->mi_8x8[0] = cm->mi + idx_str;
}

static int is_block_in_mb_map(VP9_COMP *cpi, int mi_row, int mi_col,
                              BLOCK_SIZE bsize) {
  VP9_COMMON *const cm = &cpi->common;
  const int mb_rows = cm->mb_rows;
  const int mb_cols = cm->mb_cols;
  const int mb_row = mi_row >> 1;
  const int mb_col = mi_col >> 1;
  const int mb_width = num_8x8_blocks_wide_lookup[bsize] >> 1;
  const int mb_height = num_8x8_blocks_high_lookup[bsize] >> 1;
  int r, c;
  if (bsize <= BLOCK_16X16) {
    return cpi->active_map[mb_row * mb_cols + mb_col];
  }
  for (r = 0; r < mb_height; ++r) {
    for (c = 0; c < mb_width; ++c) {
      int row = mb_row + r;
      int col = mb_col + c;
      if (row >= mb_rows || col >= mb_cols)
        continue;
      if (cpi->active_map[row * mb_cols + col])
        return 1;
    }
  }
  return 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 int mb_row = mi_row >> 1;
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 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 322 323 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 355 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 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592
  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];

  if (cpi->active_map_enabled && !x->e_mbd.lossless) {
    x->in_active_map = is_block_in_mb_map(cpi, mi_row, mi_col, bsize);
  } else {
    x->in_active_map = 1;
  }

  set_modeinfo_offsets(cm, xd, mi_row, mi_col);

  mbmi = &xd->mi_8x8[0]->mbmi;

  // Set up destination pointers.
  vp9_setup_dst_planes(xd, 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->RDDIV;
  x->rdmult = cpi->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);

    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];
  } else {
    mbmi->segment_id = 0;
    x->encode_breakout = cpi->encode_breakout;
  }
}

static void duplicate_modeinfo_in_sb(VP9_COMMON * const cm,
                                     MACROBLOCKD *const 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];
  const int mis = xd->mode_info_stride;
  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_8x8[j * mis + i] = xd->mi_8x8[0];
    }
}

static void set_block_size(VP9_COMP * const cpi,
                           const TileInfo *const tile,
                           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);
    xd->mi_8x8[0]->mbmi.sb_type = bsize;
    duplicate_modeinfo_in_sb(&cpi->common, xd, mi_row, mi_col, bsize);
  }
}

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;
  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);
    }
  }
}

// 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,
                               const TileInfo *const tile,
                               BLOCK_SIZE bsize,
                               int mi_row,
                               int mi_col,
                               int mi_size) {
  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 int64_t threshold_multiplier = 25;
  int64_t threshold = threshold_multiplier * cpi->common.base_qindex;
  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) {
    set_block_size(cpi, tile, mi_row, mi_col, bsize);
    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, tile, mi_row, mi_col, subsize);
    set_block_size(cpi, tile, 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, tile, mi_row, mi_col, subsize);
    set_block_size(cpi, tile, 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_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_8x8[0]->mbmi.ref_frame[0] = LAST_FRAME;
    xd->mi_8x8[0]->mbmi.sb_type = BLOCK_64X64;
    vp9_find_best_ref_mvs(xd, cm->allow_high_precision_mv,
                          xd->mi_8x8[0]->mbmi.ref_mvs[LAST_FRAME],
                          &nearest_mv, &near_mv);

    xd->mi_8x8[0]->mbmi.mv[0] = nearest_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;
  }

  // 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)
          vp9_get_sse_sum_8x8(s + y_idx * sp + x_idx, sp,
                              d + y_idx * dp + x_idx, dp, &sse, &sum);
        fill_variance(sse, sum, 64, &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 (!set_vt_partitioning(cpi, &vt, tile, BLOCK_64X64,
                           mi_row, mi_col, 8)) {
    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], tile, BLOCK_32X32,
                               (mi_row + y32_idx), (mi_col + x32_idx), 4)) {
        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) {
            set_block_size(cpi, tile,
                           (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);
              set_block_size(cpi, tile,
                             (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], tile,
                                   BLOCK_16X16,
                                   (mi_row + y32_idx + y16_idx),
                                   (mi_col + x32_idx + x16_idx), 2)) {
            for (k = 0; k < 4; ++k) {
              const int x8_idx = (k & 1);
              const int y8_idx = (k >> 1);
              set_block_size(cpi, tile,
                             (mi_row + y32_idx + y16_idx + y8_idx),
                             (mi_col + x32_idx + x16_idx + x8_idx),
                             BLOCK_8X8);
            }
          }
#endif
        }
      }
    }
  }
}

// Original activity measure from Tim T's code.
static unsigned int tt_activity_measure(MACROBLOCK *x) {
John Koleszar's avatar
John Koleszar committed
  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.).
  const unsigned int act = vp9_variance16x16(x->plane[0].src.buf,
                                             x->plane[0].src.stride,
                                             VP9_VAR_OFFS, 0, &sse) << 4;
  // If the region is flat, lower the activity some more.
  return act < (8 << 12) ? MIN(act, 5 << 12) : 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
#define ALT_ACT_MEASURE 1
static unsigned int mb_activity_measure(MACROBLOCK *x, int mb_row, int mb_col) {
John Koleszar's avatar
John Koleszar committed
  unsigned int mb_activity;
John Koleszar's avatar
John Koleszar committed
  if (ALT_ACT_MEASURE) {
    const int use_dc_pred = (mb_col || mb_row) && (!mb_col || !mb_row);
John Koleszar's avatar
John Koleszar committed
    // Or use and alternative.
    mb_activity = alt_activity_measure(x, use_dc_pred);
John Koleszar's avatar
John Koleszar committed
  } else {
    // Original activity measure from Tim T's code.
    mb_activity = tt_activity_measure(x);
John Koleszar's avatar
John Koleszar committed
  }
  return MAX(mb_activity, ACTIVITY_AVG_MIN);
}

// Calculate an "average" mb activity value for the frame
#define ACT_MEDIAN 0
static void calc_av_activity(VP9_COMP *cpi, int64_t activity_sum) {
#if ACT_MEDIAN
John Koleszar's avatar
John Koleszar committed
  // 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));
John Koleszar's avatar
John Koleszar committed

    // Copy map to sort list
    vpx_memcpy(sortlist, cpi->mb_activity_map,
Jim Bankoski's avatar
Jim Bankoski committed
        sizeof(unsigned int) * cpi->common.MBs);
John Koleszar's avatar
John Koleszar committed

    // 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;
John Koleszar's avatar
John Koleszar committed
      }
    }
John Koleszar's avatar
John Koleszar committed
    // Even number MBs so estimate median as mean of two either side.
    median = (1 + sortlist[cpi->common.MBs >> 1] +
Jim Bankoski's avatar
Jim Bankoski committed
        sortlist[(cpi->common.MBs >> 1) + 1]) >> 1;
John Koleszar's avatar
John Koleszar committed
    cpi->activity_avg = median;
John Koleszar's avatar
John Koleszar committed
    vpx_free(sortlist);
  }
John Koleszar's avatar
John Koleszar committed
  // Simple mean for now
Jim Bankoski's avatar
Jim Bankoski committed
  cpi->activity_avg = (unsigned int) (activity_sum / cpi->common.MBs);
#endif  // ACT_MEDIAN
  if (cpi->activity_avg < ACTIVITY_AVG_MIN)
    cpi->activity_avg = ACTIVITY_AVG_MIN;
John Koleszar's avatar
John Koleszar committed
  // Experimental code: return fixed value normalized for several clips
  if (ALT_ACT_MEASURE)
    cpi->activity_avg = 100000;
#define USE_ACT_INDEX   0
#define OUTPUT_NORM_ACT_STATS   0

#if USE_ACT_INDEX
// Calculate an activity index for each mb
static void calc_activity_index(VP9_COMP *cpi, MACROBLOCK *x) {
  VP9_COMMON *const cm = &cpi->common;
John Koleszar's avatar
John Koleszar committed
  int mb_row, mb_col;
John Koleszar's avatar
John Koleszar committed
  int64_t act;
  int64_t a;
  int64_t b;

#if OUTPUT_NORM_ACT_STATS
John Koleszar's avatar
John Koleszar committed
  FILE *f = fopen("norm_act.stt", "a");
  fprintf(f, "\n%12d\n", cpi->activity_avg);
John Koleszar's avatar
John Koleszar committed
  // Reset pointers to start of activity map
  x->mb_activity_ptr = cpi->mb_activity_map;
John Koleszar's avatar
John Koleszar committed
  // 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);
John Koleszar's avatar
John Koleszar committed
      // Calculate a normalized activity number
      a = act + 4 * cpi->activity_avg;
      b = 4 * act + cpi->activity_avg;
John Koleszar's avatar
John Koleszar committed
      if (b >= a)
Jim Bankoski's avatar
Jim Bankoski committed
      *(x->activity_ptr) = (int)((b + (a >> 1)) / a) - 1;
John Koleszar's avatar
John Koleszar committed
      else
Jim Bankoski's avatar
Jim Bankoski committed
      *(x->activity_ptr) = 1 - (int)((a + (b >> 1)) / b);

#if OUTPUT_NORM_ACT_STATS
John Koleszar's avatar
John Koleszar committed
      fprintf(f, " %6d", *(x->mb_activity_ptr));
John Koleszar's avatar
John Koleszar committed
      // Increment activity map pointers
      x->mb_activity_ptr++;
    }

#if OUTPUT_NORM_ACT_STATS
John Koleszar's avatar
John Koleszar committed
    fprintf(f, "\n");
John Koleszar's avatar
John Koleszar committed
  }

#if OUTPUT_NORM_ACT_STATS
John Koleszar's avatar
John Koleszar committed
  fclose(f);
#endif  // USE_ACT_INDEX

// 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) {
  MACROBLOCK *const x = &cpi->mb;
John Koleszar's avatar
John Koleszar committed
  MACROBLOCKD *xd = &x->e_mbd;
  VP9_COMMON *const cm = &cpi->common;
#if ALT_ACT_MEASURE
  YV12_BUFFER_CONFIG *new_yv12 = get_frame_new_buffer(cm);
John Koleszar's avatar
John Koleszar committed
  int recon_yoffset;
  int recon_y_stride = new_yv12->y_stride;
John Koleszar's avatar
John Koleszar committed
  int mb_row, mb_col;
  unsigned int mb_activity;
  int64_t activity_sum = 0;
  x->mb_activity_ptr = cpi->mb_activity_map;

John Koleszar's avatar
John Koleszar committed
  // for each macroblock row in image
  for (mb_row = 0; mb_row < cm->mb_rows; mb_row++) {
#if ALT_ACT_MEASURE
John Koleszar's avatar
John Koleszar committed
    // reset above block coeffs
    xd->up_available = (mb_row != 0);
    recon_yoffset = (mb_row * recon_y_stride * 16);
John Koleszar's avatar
John Koleszar committed
    // for each macroblock col in image
    for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) {
#if ALT_ACT_MEASURE
      xd->plane[0].dst.buf = new_yv12->y_buffer + recon_yoffset;
John Koleszar's avatar
John Koleszar committed
      xd->left_available = (mb_col != 0);
      recon_yoffset += 16;
John Koleszar's avatar
John Koleszar committed
      // measure activity
      mb_activity = mb_activity_measure(x, mb_row, mb_col);
John Koleszar's avatar
John Koleszar committed
      // Keep frame sum
      activity_sum += mb_activity;
John Koleszar's avatar
John Koleszar committed
      // Store MB level activity details.
      *x->mb_activity_ptr = mb_activity;
John Koleszar's avatar
John Koleszar committed
      // Increment activity map pointer
      x->mb_activity_ptr++;
John Koleszar's avatar
John Koleszar committed
      // adjust to the next column of source macroblocks
John Koleszar's avatar
John Koleszar committed
      x->plane[0].src.buf += 16;
John Koleszar's avatar
John Koleszar committed
    }
John Koleszar's avatar
John Koleszar committed
    // adjust to the next row of mbs
John Koleszar's avatar
John Koleszar committed
    x->plane[0].src.buf += 16 * x->plane[0].src.stride - 16 * cm->mb_cols;
John Koleszar's avatar
John Koleszar committed
  }
John Koleszar's avatar
John Koleszar committed
  // Calculate an "average" MB activity
  calc_av_activity(cpi, activity_sum);
#if USE_ACT_INDEX
John Koleszar's avatar
John Koleszar committed
  // Calculate an activity index number of each mb
  calc_activity_index(cpi, x);
// Macroblock activity masking
static void activity_masking(VP9_COMP *cpi, MACROBLOCK *x) {
#if USE_ACT_INDEX
John Koleszar's avatar
John Koleszar committed
  x->rdmult += *(x->mb_activity_ptr) * (x->rdmult >> 2);
  x->errorperbit = x->rdmult * 100 / (110 * x->rddiv);
  x->errorperbit += (x->errorperbit == 0);
  const int64_t act = *(x->mb_activity_ptr);
John Koleszar's avatar
John Koleszar committed
  // Apply the masking to the RD multiplier.
  const int64_t a = act + (2 * cpi->activity_avg);
  const int64_t b = (2 * act) + cpi->activity_avg;
Jim Bankoski's avatar
Jim Bankoski committed
  x->rdmult = (unsigned int) (((int64_t) x->rdmult * b + (a >> 1)) / a);
John Koleszar's avatar
John Koleszar committed
  x->errorperbit = x->rdmult * 100 / (110 * x->rddiv);
  x->errorperbit += (x->errorperbit == 0);
John Koleszar's avatar
John Koleszar committed
  // Activity based Zbin adjustment
  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;

  const int mi_offset = mi_row * cm->mi_cols + mi_col;
  const int bw = num_8x8_blocks_wide_lookup[BLOCK_64X64];
  const int bh = num_8x8_blocks_high_lookup[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
    const int target_rate = (cpi->rc.sb64_target_rate * xmis * ymis * 256) /
                            (bw * bh);

    if (projected_rate < (target_rate / 4)) {
      segment = 1;
    } else {
      segment = 0;
    }

Paul Wilkins's avatar
Paul Wilkins committed
    if (target_rate > 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;
    }
  }
}

Jim Bankoski's avatar
Jim Bankoski committed
static void update_state(VP9_COMP *cpi, PICK_MODE_CONTEXT *ctx,
                         BLOCK_SIZE bsize, int output_enabled) {
  int i, x_idx, y;
  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;
John Koleszar's avatar
John Koleszar committed
  MODE_INFO *mi = &ctx->mic;
  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;
Jim Bankoski's avatar
Jim Bankoski committed
  const int mi_width = num_8x8_blocks_wide_lookup[bsize];
Jim Bankoski's avatar
Jim Bankoski committed
  const int mi_height = num_8x8_blocks_high_lookup[bsize];
  int max_plane;
  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];
    p[i].qcoeff = ctx->qcoeff_pbuf[i][1];
    pd[i].dqcoeff = ctx->dqcoeff_pbuf[i][1];
    p[i].eobs = ctx->eobs_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];
    p[i].eobs = ctx->eobs_pbuf[i][2];
John Koleszar's avatar
John Koleszar committed
  // 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_init_plane_quantizers(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];
Ronald S. Bultje's avatar
Ronald S. Bultje committed
  }
  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;
John Koleszar's avatar
John Koleszar committed
  }

  vpx_memcpy(x->zcoeff_blk[mbmi->tx_size], ctx->zcoeff_blk,
             sizeof(uint8_t) * ctx->num_4x4_blk);
  if (!output_enabled)
    return;

  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)) {
John Koleszar's avatar
John Koleszar committed
    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*/,
John Koleszar's avatar
John Koleszar committed
      THR_D135_PRED /*D135_PRED*/,
      THR_D117_PRED /*D117_PRED*/,
      THR_D153_PRED /*D153_PRED*/,
Dmitry Kovalev's avatar
Dmitry Kovalev committed
      THR_D207_PRED /*D207_PRED*/,
      THR_D63_PRED  /*D63_PRED*/,
      THR_TM        /*TM_PRED*/,
John Koleszar's avatar
John Koleszar committed
    };
    ++cpi->mode_chosen_counts[kf_mode_index[mbmi->mode]];
John Koleszar's avatar
John Koleszar committed
  } else {
    // Note how often each mode chosen as best
    ++cpi->mode_chosen_counts[ctx->best_mode_index];
  }
#endif
  if (!frame_is_intra_only(cm)) {
    if (is_inter_block(mbmi)) {
      if (mbmi->sb_type < BLOCK_8X8 || mbmi->mode == NEWMV) {
        for (i = 0; i < 1 + has_second_ref(mbmi); ++i)
          best_mv[i] = mbmi->ref_mvs[mbmi->ref_frame[i]][0].as_mv;
        vp9_update_mv_count(cm, xd, best_mv);
      }

      if (cm->interp_filter == SWITCHABLE) {
        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];
John Koleszar's avatar
John Koleszar committed
  }
Jim Bankoski's avatar
Jim Bankoski committed
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};
  // 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,
Jim Bankoski's avatar
Jim Bankoski committed
                     NULL, x->e_mbd.plane[i].subsampling_x,
                     x->e_mbd.plane[i].subsampling_y);
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;
  MB_MODE_INFO *mbmi;
  struct macroblock_plane *const p = x->plane;
  struct macroblockd_plane *const pd = xd->plane;
  const AQ_MODE aq_mode = cpi->oxcf.aq_mode;
  int i, orig_rdmult = x->rdmult;
  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;
  if (bsize < BLOCK_8X8) {
    // When ab_index = 0 all sub-blocks are handled, so for ab_index != 0
    // there is nothing to be done.
      *totalrate = 0;
      *totaldist = 0;
James Zern's avatar
James Zern committed
  set_offsets(cpi, tile, mi_row, mi_col, bsize);
  mbmi = &xd->mi_8x8[0]->mbmi;
  mbmi->sb_type = bsize;
  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];
    p[i].eobs = ctx->eobs_pbuf[i][0];
  x->skip_recode = 0;
  // Set to zero to make sure we do not use the previous encoded frame stats
  mbmi->skip = 0;
  x->source_variance = get_sby_perpixel_variance(cpi, x, bsize);
  if (aq_mode == VARIANCE_AQ) {
    const int energy = bsize <= BLOCK_16X16 ? x->mb_energy
                                            : vp9_block_energy(cpi, x, bsize);
Paul Wilkins's avatar
Paul Wilkins committed

    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);
Paul Wilkins's avatar
Paul Wilkins committed
    } 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_init_plane_quantizers(cpi, x);
  if (cpi->oxcf.tuning == VP8_TUNE_SSIM)
    activity_masking(cpi, x);
  if (aq_mode == VARIANCE_AQ) {
    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];
Paul Wilkins's avatar
Paul Wilkins committed
    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);
  // 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)
James Zern's avatar
James Zern committed
      vp9_rd_pick_inter_mode_sb(cpi, x, tile, mi_row, mi_col,
                                totalrate, totaldist, bsize, ctx, best_rd);
James Zern's avatar
James Zern committed
      vp9_rd_pick_inter_mode_sub8x8(cpi, x, tile, mi_row, mi_col, totalrate,
                                    totaldist, bsize, ctx, best_rd);
  }
  if (aq_mode == VARIANCE_AQ) {
    x->rdmult = orig_rdmult;
    if (*totalrate != INT_MAX) {
      vp9_clear_system_state();
      *totalrate = (int)round(*totalrate * rdmult_ratio);
  } else if (aq_mode == COMPLEXITY_AQ) {
Paul Wilkins's avatar
Paul Wilkins committed
    x->rdmult = orig_rdmult;
  }
static void update_stats(VP9_COMP *cpi) {
  VP9_COMMON *const cm = &cpi->common;
  const MACROBLOCK *const x = &cpi->mb;
  const MACROBLOCKD *const xd = &x->e_mbd;
  const MODE_INFO *const mi = xd->mi_8x8[0];
  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,
    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]++;
        }
Ronald S. Bultje's avatar
Ronald S. Bultje committed
    }
static BLOCK_SIZE *get_sb_partitioning(MACROBLOCK *x, BLOCK_SIZE bsize) {
  switch (bsize) {
      return &x->sb64_partitioning;
      return &x->sb_partitioning[x->sb_index];
      return &x->mb_partitioning[x->sb_index][x->mb_index];
      return &x->b_partitioning[x->sb_index][x->mb_index][x->b_index];
    default:
      assert(0);
  }
}

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],
Jim Bankoski's avatar
Jim Bankoski committed
                            PARTITION_CONTEXT sa[8], PARTITION_CONTEXT sl[8],
Jim Bankoski's avatar
Jim Bankoski committed
  MACROBLOCK *const x = &cpi->mb;
  MACROBLOCKD *const xd = &x->e_mbd;
Jim Bankoski's avatar
Jim Bankoski committed
  const int num_4x4_blocks_wide = num_4x4_blocks_wide_lookup[bsize];
  const int num_4x4_blocks_high = num_4x4_blocks_high_lookup[bsize];
Jim Bankoski's avatar
Jim Bankoski committed
  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++) {
Jim Bankoski's avatar
Jim Bankoski committed
    vpx_memcpy(
        cpi->above_context[p] + ((mi_col * 2) >> xd->plane[p].subsampling_x),
Jim Bankoski's avatar
Jim Bankoski committed
        a + num_4x4_blocks_wide * p,
        (sizeof(ENTROPY_CONTEXT) * num_4x4_blocks_wide) >>
        xd->plane[p].subsampling_x);
Jim Bankoski's avatar
Jim Bankoski committed
    vpx_memcpy(
        cpi->left_context[p]
Jim Bankoski's avatar
Jim Bankoski committed
            + ((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);
Jim Bankoski's avatar
Jim Bankoski committed
static void save_context(VP9_COMP *cpi, int mi_row, int mi_col,
Jim Bankoski's avatar
Jim Bankoski committed
                         ENTROPY_CONTEXT a[16 * MAX_MB_PLANE],
                         ENTROPY_CONTEXT l[16 * MAX_MB_PLANE],
                         PARTITION_CONTEXT sa[8], PARTITION_CONTEXT sl[8],
Jim Bankoski's avatar
Jim Bankoski committed
  const MACROBLOCK *const x = &cpi->mb;
  const MACROBLOCKD *const xd = &x->e_mbd;
Jim Bankoski's avatar
Jim Bankoski committed
  int p;
Jim Bankoski's avatar
Jim Bankoski committed
  const int num_4x4_blocks_wide = num_4x4_blocks_wide_lookup[bsize];
  const int num_4x4_blocks_high = num_4x4_blocks_high_lookup[bsize];
Jim Bankoski's avatar
Jim Bankoski committed
  int mi_width = num_8x8_blocks_wide_lookup[bsize];
  int mi_height = num_8x8_blocks_high_lookup[bsize];
Jim Bankoski's avatar
Jim Bankoski committed

  // buffer the above/left context information of the block in search.
  for (p = 0; p < MAX_MB_PLANE; ++p) {
Jim Bankoski's avatar
Jim Bankoski committed
    vpx_memcpy(
Jim Bankoski's avatar
Jim Bankoski committed
        a + num_4x4_blocks_wide * p,
        cpi->above_context[p] + (mi_col * 2 >> xd->plane[p].subsampling_x),
Jim Bankoski's avatar
Jim Bankoski committed
        (sizeof(ENTROPY_CONTEXT) * num_4x4_blocks_wide) >>
        xd->plane[p].subsampling_x);
Jim Bankoski's avatar
Jim Bankoski committed
    vpx_memcpy(
Jim Bankoski's avatar
Jim Bankoski committed
        l + num_4x4_blocks_high * p,
        cpi->left_context[p]
Jim Bankoski's avatar
Jim Bankoski committed
            + ((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);
Jim Bankoski's avatar
Jim Bankoski committed
}
James Zern's avatar
James Zern committed
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) {
  MACROBLOCK *const x = &cpi->mb;
  if (bsize < BLOCK_8X8) {
    // When ab_index = 0 all sub-blocks are handled, so for ab_index != 0
    // there is nothing to be done.
James Zern's avatar
James Zern committed
  set_offsets(cpi, tile, mi_row, mi_col, bsize);
  update_state(cpi, get_block_context(x, bsize), bsize, output_enabled);
  encode_superblock(cpi, tp, output_enabled, mi_row, mi_col, bsize);
    update_stats(cpi);
John Koleszar's avatar
John Koleszar committed
  }
James Zern's avatar
James Zern committed
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;
  const int bsl = b_width_log2(bsize), hbs = (1 << bsl) / 4;
  int ctx;
Jim Bankoski's avatar
Jim Bankoski committed
  PARTITION_TYPE partition;
  if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols)
    return;
  if (bsize >= BLOCK_8X8) {
    ctx = partition_plane_context(cpi->above_seg_context, cpi->left_seg_context,
                                 mi_row, mi_col, bsize);
    subsize = *get_sb_partitioning(x, bsize);
  } else {
    ctx = 0;
    subsize = BLOCK_4X4;

  partition = partition_lookup[bsl][subsize];
Jim Bankoski's avatar
Jim Bankoski committed
  switch (partition) {
    case PARTITION_NONE:
      if (output_enabled && bsize >= BLOCK_8X8)
        cm->counts.partition[ctx][PARTITION_NONE]++;
      encode_b(cpi, tile, tp, mi_row, mi_col, output_enabled, subsize);
Jim Bankoski's avatar
Jim Bankoski committed
      break;
    case PARTITION_VERT:
      if (output_enabled)
        cm->counts.partition[ctx][PARTITION_VERT]++;
      *get_sb_index(x, subsize) = 0;
      encode_b(cpi, tile, tp, mi_row, mi_col, output_enabled, subsize);
      if (mi_col + hbs < cm->mi_cols) {
        *get_sb_index(x, subsize) = 1;
        encode_b(cpi, tile, tp, mi_row, mi_col + hbs, output_enabled, subsize);
      }
Jim Bankoski's avatar
Jim Bankoski committed
      break;
    case PARTITION_HORZ:
      if (output_enabled)
        cm->counts.partition[ctx][PARTITION_HORZ]++;
      *get_sb_index(x, subsize) = 0;
      encode_b(cpi, tile, tp, mi_row, mi_col, output_enabled, subsize);
      if (mi_row + hbs < cm->mi_rows) {
        *get_sb_index(x, subsize) = 1;
        encode_b(cpi, tile, tp, mi_row + hbs, mi_col, output_enabled, subsize);
      }
Jim Bankoski's avatar
Jim Bankoski committed
      break;
    case PARTITION_SPLIT:
      subsize = get_subsize(bsize, PARTITION_SPLIT);
      if (output_enabled)
        cm->counts.partition[ctx][PARTITION_SPLIT]++;

      *get_sb_index(x, subsize) = 0;
      encode_sb(cpi, tile, tp, mi_row, mi_col, output_enabled, subsize);
      *get_sb_index(x, subsize) = 1;
      encode_sb(cpi, tile, tp, mi_row, mi_col + hbs, output_enabled, subsize);
      *get_sb_index(x, subsize) = 2;
      encode_sb(cpi, tile, tp, mi_row + hbs, mi_col, output_enabled, subsize);
      *get_sb_index(x, subsize) = 3;
      encode_sb(cpi, tile, tp, mi_row + hbs, mi_col + hbs, output_enabled,
                subsize);
Jim Bankoski's avatar
Jim Bankoski committed
      break;
    default:
      assert("Invalid partition type.");
  if (partition != PARTITION_SPLIT || bsize == BLOCK_8X8)
    update_partition_context(cpi->above_seg_context, cpi->left_seg_context,
                             mi_row, mi_col, subsize, bsize);
Paul Wilkins's avatar
Paul Wilkins committed
// 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) {
Paul Wilkins's avatar
Paul Wilkins committed
    return MIN(bsize, BLOCK_8X8);
  } else {
    for (; bsize > 0; bsize -= 3) {
Paul Wilkins's avatar
Paul Wilkins committed
      *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_fixed_partitioning(VP9_COMP *cpi, const TileInfo *const tile,
                                   MODE_INFO **mi_8x8, int mi_row, int mi_col,
                                   BLOCK_SIZE bsize) {
  VP9_COMMON *const cm = &cpi->common;
Jim Bankoski's avatar
Jim Bankoski committed
  const int mis = cm->mode_info_stride;
James Zern's avatar
James Zern committed
  int row8x8_remaining = tile->mi_row_end - mi_row;
  int col8x8_remaining = tile->mi_col_end - mi_col;
Jim Bankoski's avatar
Jim Bankoski committed
  int block_row, block_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];
Paul Wilkins's avatar
Paul Wilkins committed

  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;
Paul Wilkins's avatar
Paul Wilkins committed
      }
    }
  } else {
    // Else this is a partial SB64.
    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;
Paul Wilkins's avatar
Paul Wilkins committed
        // Find a partition size that fits
        bsize = find_partition_size(bsize,
Paul Wilkins's avatar
Paul Wilkins committed
                                    (row8x8_remaining - block_row),
                                    (col8x8_remaining - block_col), &bh, &bw);
        mi_8x8[index] = mi_upper_left + index;
        mi_8x8[index]->mbmi.sb_type = bsize;
Paul Wilkins's avatar
Paul Wilkins committed
      }
static void copy_partitioning(VP9_COMMON *cm, MODE_INFO **mi_8x8,
                              MODE_INFO **prev_mi_8x8) {
  const int mis = cm->mode_info_stride;
  int block_row, block_col;
  for (block_row = 0; block_row < 8; ++block_row) {
    for (block_col = 0; block_col < 8; ++block_col) {
      MODE_INFO *const prev_mi = prev_mi_8x8[block_row * mis + block_col];
      const BLOCK_SIZE sb_type = prev_mi ? prev_mi->mbmi.sb_type : 0;
        const ptrdiff_t offset = prev_mi - cm->prev_mi;
        mi_8x8[block_row * mis + block_col] = cm->mi + offset;
        mi_8x8[block_row * mis + block_col]->mbmi.sb_type = sb_type;
      }
static int sb_has_motion(const VP9_COMMON *cm, MODE_INFO **prev_mi_8x8) {
  const int mis = cm->mode_info_stride;
  int block_row, block_col;

  if (cm->prev_mi) {
    for (block_row = 0; block_row < 8; ++block_row) {
      for (block_col = 0; block_col < 8; ++block_col) {
        const MODE_INFO *prev_mi = prev_mi_8x8[block_row * mis + block_col];
        if (prev_mi) {
          if (abs(prev_mi->mbmi.mv[0].as_mv.row) >= 8 ||
              abs(prev_mi->mbmi.mv[0].as_mv.col) >= 8)
            return 1;
        }
      }
    }
  }
  return 0;
}
static void update_state_rt(VP9_COMP *cpi, const PICK_MODE_CONTEXT *ctx) {
Jim Bankoski's avatar
Jim Bankoski committed
  int i;
  VP9_COMMON *const cm = &cpi->common;
  MACROBLOCK *const x = &cpi->mb;
Jim Bankoski's avatar
Jim Bankoski committed
  MACROBLOCKD *const xd = &x->e_mbd;
  MB_MODE_INFO *const mbmi = &xd->mi_8x8[0]->mbmi;
Jim Bankoski's avatar
Jim Bankoski committed
  x->skip = ctx->skip;

#if CONFIG_INTERNAL_STATS
  if (frame_is_intra_only(cm)) {
Jim Bankoski's avatar
Jim Bankoski committed
    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*/,
      THR_D207_PRED /*D207_PRED*/,
      THR_D63_PRED /*D63_PRED*/,
      THR_TM /*TM_PRED*/,
    };
    ++cpi->mode_chosen_counts[kf_mode_index[mbmi->mode]];
Jim Bankoski's avatar
Jim Bankoski committed
  } else {
    // Note how often each mode chosen as best
    ++cpi->mode_chosen_counts[ctx->best_mode_index];
  }
#endif
  if (!frame_is_intra_only(cm)) {
    if (is_inter_block(mbmi)) {
      if (mbmi->sb_type < BLOCK_8X8 || mbmi->mode == NEWMV) {
        for (i = 0; i < 1 + has_second_ref(mbmi); ++i)
          best_mv[i] = mbmi->ref_mvs[mbmi->ref_frame[i]][0].as_mv;
        vp9_update_mv_count(cm, xd, best_mv);
      if (cm->interp_filter == SWITCHABLE) {
        const int pred_ctx = vp9_get_pred_context_switchable_interp(xd);
        ++cm->counts.switchable_interp[pred_ctx][mbmi->interp_filter];
Jim Bankoski's avatar
Jim Bankoski committed
    }
  }
}

static void encode_b_rt(VP9_COMP *cpi, const TileInfo *const tile,
                     TOKENEXTRA **tp, int mi_row, int mi_col,
                     int output_enabled, BLOCK_SIZE bsize) {
  MACROBLOCK *const x = &cpi->mb;

  if (bsize < BLOCK_8X8) {
    // When ab_index = 0 all sub-blocks are handled, so for ab_index != 0
    // there is nothing to be done.
Jim Bankoski's avatar
Jim Bankoski committed
    if (x->ab_index > 0)
Jim Bankoski's avatar
Jim Bankoski committed
  }
  set_offsets(cpi, tile, mi_row, mi_col, bsize);
  update_state_rt(cpi, get_block_context(x, bsize));
Jim Bankoski's avatar
Jim Bankoski committed

  encode_superblock(cpi, tp, output_enabled, mi_row, mi_col, bsize);
  update_stats(cpi);

  (*tp)->token = EOSB_TOKEN;
  (*tp)++;
}

static void encode_sb_rt(VP9_COMP *cpi, const TileInfo *const tile,
                         TOKENEXTRA **tp, int mi_row, int mi_col,
                         int output_enabled, BLOCK_SIZE bsize) {
Jim Bankoski's avatar
Jim Bankoski committed
  VP9_COMMON *const cm = &cpi->common;
  MACROBLOCK *const x = &cpi->mb;
  const int bsl = b_width_log2(bsize), hbs = (1 << bsl) / 4;
  int ctx;
  PARTITION_TYPE partition;
  BLOCK_SIZE subsize;

  if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols)
    return;

  if (bsize >= BLOCK_8X8) {
    MACROBLOCKD *const xd = &cpi->mb.e_mbd;
    const int idx_str = xd->mode_info_stride * mi_row + mi_col;
    MODE_INFO ** mi_8x8 = cm->mi_grid_visible + idx_str;
    ctx = partition_plane_context(cpi->above_seg_context, cpi->left_seg_context,
                                 mi_row, mi_col, bsize);
    subsize = mi_8x8[0]->mbmi.sb_type;
  } else {
Jim Bankoski's avatar
Jim Bankoski committed
    ctx = 0;
    subsize = BLOCK_4X4;
Jim Bankoski's avatar
Jim Bankoski committed
  partition = partition_lookup[bsl][subsize];

  switch (partition) {
    case PARTITION_NONE:
Jim Bankoski's avatar
Jim Bankoski committed
      if (output_enabled && bsize >= BLOCK_8X8)
        cm->counts.partition[ctx][PARTITION_NONE]++;
      encode_b_rt(cpi, tile, tp, mi_row, mi_col, output_enabled, subsize);
Jim Bankoski's avatar
Jim Bankoski committed
    case PARTITION_VERT:
      if (output_enabled)
        cm->counts.partition[ctx][PARTITION_VERT]++;
      *get_sb_index(x, subsize) = 0;
Jim Bankoski's avatar
Jim Bankoski committed
      encode_b_rt(cpi, tile, tp, mi_row, mi_col, output_enabled, subsize);
      if (mi_col + hbs < cm->mi_cols) {
        *get_sb_index(x, subsize) = 1;
Jim Bankoski's avatar
Jim Bankoski committed
        encode_b_rt(cpi, tile, tp, mi_row, mi_col + hbs, output_enabled,
                    subsize);
Jim Bankoski's avatar
Jim Bankoski committed
    case PARTITION_HORZ:
      if (output_enabled)
        cm->counts.partition[ctx][PARTITION_HORZ]++;
      *get_sb_index(x, subsize) = 0;
Jim Bankoski's avatar
Jim Bankoski committed
      encode_b_rt(cpi, tile, tp, mi_row, mi_col, output_enabled, subsize);
      if (mi_row + hbs < cm->mi_rows) {
        *get_sb_index(x, subsize) = 1;
Jim Bankoski's avatar
Jim Bankoski committed
        encode_b_rt(cpi, tile, tp, mi_row + hbs, mi_col, output_enabled,
                    subsize);
      }
      break;
    case PARTITION_SPLIT:
Jim Bankoski's avatar
Jim Bankoski committed
      subsize = get_subsize(bsize, PARTITION_SPLIT);
      if (output_enabled)
        cm->counts.partition[ctx][PARTITION_SPLIT]++;
Jim Bankoski's avatar
Jim Bankoski committed
      *get_sb_index(x, subsize) = 0;
      encode_sb_rt(cpi, tile, tp, mi_row, mi_col, output_enabled, subsize);
      *get_sb_index(x, subsize) = 1;
      encode_sb_rt(cpi, tile, tp, mi_row, mi_col + hbs, output_enabled,
                   subsize);
      *get_sb_index(x, subsize) = 2;
      encode_sb_rt(cpi, tile, tp, mi_row + hbs, mi_col, output_enabled,
                   subsize);
      *get_sb_index(x, subsize) = 3;
      encode_sb_rt(cpi, tile, tp, mi_row + hbs, mi_col + hbs, output_enabled,
      break;
    default:
Jim Bankoski's avatar
Jim Bankoski committed
      assert("Invalid partition type.");
Jim Bankoski's avatar
Jim Bankoski committed
  if (partition != PARTITION_SPLIT || bsize == BLOCK_8X8)
    update_partition_context(cpi->above_seg_context, cpi->left_seg_context,
                             mi_row, mi_col, subsize, bsize);
James Zern's avatar
James Zern committed
static void rd_use_partition(VP9_COMP *cpi,
                             const TileInfo *const tile,
                             MODE_INFO **mi_8x8,
                             TOKENEXTRA **tp, int mi_row, int mi_col,
                             BLOCK_SIZE bsize, int *rate, int64_t *dist,
                             int do_recon) {
  VP9_COMMON *const cm = &cpi->common;
  MACROBLOCK *const x = &cpi->mb;
Jim Bankoski's avatar
Jim Bankoski committed
  const int mis = cm->mode_info_stride;
  const int bsl = b_width_log2(bsize);
Jim Bankoski's avatar
Jim Bankoski committed
  const int num_4x4_blocks_wide = num_4x4_blocks_wide_lookup[bsize];
  const int num_4x4_blocks_high = num_4x4_blocks_high_lookup[bsize];
  const int ms = num_4x4_blocks_wide / 2;
  const int mh = num_4x4_blocks_high / 2;
  const int bss = (1 << bsl) / 4;
Jim Bankoski's avatar
Jim Bankoski committed
  int i, pl;
  PARTITION_TYPE partition = PARTITION_NONE;
Jim Bankoski's avatar
Jim Bankoski committed
  ENTROPY_CONTEXT l[16 * MAX_MB_PLANE], a[16 * MAX_MB_PLANE];
  PARTITION_CONTEXT sl[8], sa[8];
  int last_part_rate = INT_MAX;
  int64_t last_part_dist = INT64_MAX;
  int64_t last_part_rd = INT64_MAX;
  int none_rate = INT_MAX;
  int64_t none_dist = INT64_MAX;
  int64_t none_rd = INT64_MAX;
  int chosen_rate = INT_MAX;
  int64_t chosen_dist = INT64_MAX;
  int64_t chosen_rd = INT64_MAX;
  BLOCK_SIZE sub_subsize = BLOCK_4X4;
  int splits_below = 0;
  BLOCK_SIZE bs_type = mi_8x8[0]->mbmi.sb_type;
Jim Bankoski's avatar
Jim Bankoski committed

  if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols)
    return;

Jim Bankoski's avatar
Jim Bankoski committed
  partition = partition_lookup[bsl][bs_type];
Jim Bankoski's avatar
Jim Bankoski committed
  subsize = get_subsize(bsize, partition);

  if (bsize < BLOCK_8X8) {
    // When ab_index = 0 all sub-blocks are handled, so for ab_index != 0
    // there is nothing to be done.
      *rate = 0;
      *dist = 0;
      return;
    }
  } else {
Jim Bankoski's avatar
Jim Bankoski committed
    *(get_sb_partitioning(x, bsize)) = subsize;
  }
  save_context(cpi, mi_row, mi_col, a, l, sa, sl, bsize);
  if (bsize == BLOCK_16X16) {
James Zern's avatar
James Zern committed
    set_offsets(cpi, tile, mi_row, mi_col, bsize);
    x->mb_energy = vp9_block_energy(cpi, x, bsize);
  }

  if (cpi->sf.partition_search_type == SEARCH_PARTITION &&
      cpi->sf.adjust_partitioning_from_last_frame) {
    // Check if any of the sub blocks are further split.
    if (partition == PARTITION_SPLIT && subsize > BLOCK_8X8) {
      sub_subsize = get_subsize(subsize, PARTITION_SPLIT);
      splits_below = 1;
      for (i = 0; i < 4; i++) {
        int jj = i >> 1, ii = i & 0x01;
        MODE_INFO * this_mi = mi_8x8[jj * bss * mis + ii * bss];
        if (this_mi && this_mi->mbmi.sb_type >= sub_subsize) {
          splits_below = 0;
        }
      }
    }

    // If partition is not none try none unless each of the 4 splits are split
    // even further..
    if (partition != PARTITION_NONE && !splits_below &&
        mi_row + (ms >> 1) < cm->mi_rows &&
        mi_col + (ms >> 1) < cm->mi_cols) {
      *(get_sb_partitioning(x, bsize)) = bsize;
      rd_pick_sb_modes(cpi, tile, mi_row, mi_col, &none_rate, &none_dist, bsize,
                       get_block_context(x, bsize), INT64_MAX);
      pl = partition_plane_context(cpi->above_seg_context,
                                   cpi->left_seg_context,
                                   mi_row, mi_col, bsize);

      if (none_rate < INT_MAX) {
        none_rate += x->partition_cost[pl][PARTITION_NONE];
        none_rd = RDCOST(x->rdmult, x->rddiv, none_rate, none_dist);
      }

      restore_context(cpi, mi_row, mi_col, a, l, sa, sl, bsize);
      mi_8x8[0]->mbmi.sb_type = bs_type;
      *(get_sb_partitioning(x, bsize)) = subsize;
    }
  }

Jim Bankoski's avatar
Jim Bankoski committed
  switch (partition) {
    case PARTITION_NONE:
      rd_pick_sb_modes(cpi, tile, mi_row, mi_col, &last_part_rate,
                       &last_part_dist, bsize,
                       get_block_context(x, bsize), INT64_MAX);
Jim Bankoski's avatar
Jim Bankoski committed
      break;
    case PARTITION_HORZ:
      *get_sb_index(x, subsize) = 0;
      rd_pick_sb_modes(cpi, tile, mi_row, mi_col, &last_part_rate,
                       &last_part_dist, subsize,
                       get_block_context(x, subsize), INT64_MAX);
Jim Bankoski's avatar
Jim Bankoski committed
      if (last_part_rate != INT_MAX &&
          bsize >= BLOCK_8X8 && mi_row + (mh >> 1) < cm->mi_rows) {
Yaowu Xu's avatar
Yaowu Xu committed
        int rt = 0;
        int64_t dt = 0;
Jim Bankoski's avatar
Jim Bankoski committed
        update_state(cpi, get_block_context(x, subsize), subsize, 0);
        encode_superblock(cpi, tp, 0, mi_row, mi_col, subsize);
        *get_sb_index(x, subsize) = 1;
        rd_pick_sb_modes(cpi, tile, mi_row + (ms >> 1), mi_col, &rt, &dt,
                         subsize, get_block_context(x, subsize), INT64_MAX);
        if (rt == INT_MAX || dt == INT64_MAX) {
Jim Bankoski's avatar
Jim Bankoski committed
          last_part_rate = INT_MAX;
          last_part_dist = INT64_MAX;
        last_part_rate += rt;
        last_part_dist += dt;
Jim Bankoski's avatar
Jim Bankoski committed
      }
      break;
    case PARTITION_VERT:
      *get_sb_index(x, subsize) = 0;
      rd_pick_sb_modes(cpi, tile, mi_row, mi_col, &last_part_rate,
                       &last_part_dist, subsize,
                       get_block_context(x, subsize), INT64_MAX);
Jim Bankoski's avatar
Jim Bankoski committed
      if (last_part_rate != INT_MAX &&
          bsize >= BLOCK_8X8 && mi_col + (ms >> 1) < cm->mi_cols) {
Yaowu Xu's avatar
Yaowu Xu committed
        int rt = 0;
        int64_t dt = 0;
Jim Bankoski's avatar
Jim Bankoski committed
        update_state(cpi, get_block_context(x, subsize), subsize, 0);
        encode_superblock(cpi, tp, 0, mi_row, mi_col, subsize);
        *get_sb_index(x, subsize) = 1;
        rd_pick_sb_modes(cpi, tile, mi_row, mi_col + (ms >> 1), &rt, &dt,
                         subsize, get_block_context(x, subsize), INT64_MAX);
        if (rt == INT_MAX || dt == INT64_MAX) {
Jim Bankoski's avatar
Jim Bankoski committed
          last_part_rate = INT_MAX;
          last_part_dist = INT64_MAX;
Jim Bankoski's avatar
Jim Bankoski committed
          break;
        }
        last_part_rate += rt;
        last_part_dist += dt;
Jim Bankoski's avatar
Jim Bankoski committed
      }
      break;
    case PARTITION_SPLIT:
      // Split partition.
      last_part_rate = 0;
      last_part_dist = 0;
Jim Bankoski's avatar
Jim Bankoski committed
      for (i = 0; i < 4; i++) {
        int x_idx = (i & 1) * (ms >> 1);
        int y_idx = (i >> 1) * (ms >> 1);
Jim Bankoski's avatar
Jim Bankoski committed
        int jj = i >> 1, ii = i & 0x01;
        int rt;
        int64_t dt;
Jim Bankoski's avatar
Jim Bankoski committed

        if ((mi_row + y_idx >= cm->mi_rows) || (mi_col + x_idx >= cm->mi_cols))
          continue;

        *get_sb_index(x, subsize) = i;
James Zern's avatar
James Zern committed
        rd_use_partition(cpi, tile, mi_8x8 + jj * bss * mis + ii * bss, tp,
                         mi_row + y_idx, mi_col + x_idx, subsize, &rt, &dt,
                         i != 3);
        if (rt == INT_MAX || dt == INT64_MAX) {
          last_part_rate = INT_MAX;
          last_part_dist = INT64_MAX;
        last_part_rate += rt;
        last_part_dist += dt;
Jim Bankoski's avatar
Jim Bankoski committed
      }
      break;
    default:
      assert(0);
  }
  pl = partition_plane_context(cpi->above_seg_context, cpi->left_seg_context,
                               mi_row, mi_col, bsize);
  if (last_part_rate < INT_MAX) {
    last_part_rate += x->partition_cost[pl][partition];
    last_part_rd = RDCOST(x->rdmult, x->rddiv, last_part_rate, last_part_dist);
  }
  if (cpi->sf.adjust_partitioning_from_last_frame
      && cpi->sf.partition_search_type == SEARCH_PARTITION
      && partition != PARTITION_SPLIT && bsize > BLOCK_8X8
      && (mi_row + ms < cm->mi_rows || mi_row + (ms >> 1) == cm->mi_rows)
      && (mi_col + ms < cm->mi_cols || mi_col + (ms >> 1) == cm->mi_cols)) {
    BLOCK_SIZE split_subsize = get_subsize(bsize, PARTITION_SPLIT);
    chosen_rate = 0;
    chosen_dist = 0;
    restore_context(cpi, mi_row, mi_col, a, l, sa, sl, bsize);

    // Split partition.
    for (i = 0; i < 4; i++) {
Jim Bankoski's avatar
Jim Bankoski committed
      int x_idx = (i & 1) * (num_4x4_blocks_wide >> 2);
      int y_idx = (i >> 1) * (num_4x4_blocks_wide >> 2);
      int rt = 0;
      int64_t dt = 0;
      ENTROPY_CONTEXT l[16 * MAX_MB_PLANE], a[16 * MAX_MB_PLANE];
      PARTITION_CONTEXT sl[8], sa[8];

      if ((mi_row + y_idx >= cm->mi_rows) || (mi_col + x_idx >= cm->mi_cols))
      *get_sb_index(x, split_subsize) = i;
Dmitry Kovalev's avatar
Dmitry Kovalev committed
      *get_sb_partitioning(x, bsize) = split_subsize;
      *get_sb_partitioning(x, split_subsize) = split_subsize;

      save_context(cpi, mi_row, mi_col, a, l, sa, sl, bsize);

      rd_pick_sb_modes(cpi, tile, mi_row + y_idx, mi_col + x_idx, &rt, &dt,
                       split_subsize, get_block_context(x, split_subsize),
                       INT64_MAX);

      restore_context(cpi, mi_row, mi_col, a, l, sa, sl, bsize);

      if (rt == INT_MAX || dt == INT64_MAX) {
        chosen_rate = INT_MAX;
        chosen_dist = INT64_MAX;
      chosen_rate += rt;
      chosen_dist += dt;

Jim Bankoski's avatar
Jim Bankoski committed
      if (i != 3)
James Zern's avatar
James Zern committed
        encode_sb(cpi, tile, tp,  mi_row + y_idx, mi_col + x_idx, 0,
                  split_subsize);

      pl = partition_plane_context(cpi->above_seg_context,
                                   cpi->left_seg_context,
Yaowu Xu's avatar
Yaowu Xu committed
                                   mi_row + y_idx, mi_col + x_idx,
                                   split_subsize);
      chosen_rate += x->partition_cost[pl][PARTITION_NONE];
    pl = partition_plane_context(cpi->above_seg_context, cpi->left_seg_context,
                                 mi_row, mi_col, bsize);
    if (chosen_rate < INT_MAX) {
      chosen_rate += x->partition_cost[pl][PARTITION_SPLIT];
      chosen_rd = RDCOST(x->rdmult, x->rddiv, chosen_rate, chosen_dist);
Jim Bankoski's avatar
Jim Bankoski committed
    }
  }

  // If last_part is better set the partitioning to that...
  if (last_part_rd < chosen_rd) {
    mi_8x8[0]->mbmi.sb_type = bsize;
    if (bsize >= BLOCK_8X8)
      *(get_sb_partitioning(x, bsize)) = subsize;
    chosen_rate = last_part_rate;
    chosen_dist = last_part_dist;
    chosen_rd = last_part_rd;
  }
  // If none was better set the partitioning to that...
  if (none_rd < chosen_rd) {
    if (bsize >= BLOCK_8X8)
      *(get_sb_partitioning(x, bsize)) = bsize;
    chosen_rate = none_rate;
    chosen_dist = none_dist;
  }
Jim Bankoski's avatar
Jim Bankoski committed

  restore_context(cpi, mi_row, mi_col, a, l, sa, sl, bsize);

  // We must have chosen a partitioning and encoding or we'll fail later on.
  // No other opportunities for success.
  if ( bsize == BLOCK_64X64)
    assert(chosen_rate < INT_MAX && chosen_dist < INT64_MAX);
  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;
static const BLOCK_SIZE min_partition_size[BLOCK_SIZES] = {
  BLOCK_4X4,   BLOCK_4X4,   BLOCK_4X4,
  BLOCK_4X4,   BLOCK_4X4,   BLOCK_4X4,
  BLOCK_8X8,   BLOCK_8X8,   BLOCK_8X8,
  BLOCK_16X16, BLOCK_16X16, BLOCK_16X16,
  BLOCK_16X16
};

static const BLOCK_SIZE max_partition_size[BLOCK_SIZES] = {
  BLOCK_8X8,   BLOCK_16X16, BLOCK_16X16,
  BLOCK_16X16, BLOCK_32X32, BLOCK_32X32,
  BLOCK_32X32, BLOCK_64X64, BLOCK_64X64,
  BLOCK_64X64, BLOCK_64X64, BLOCK_64X64,
  BLOCK_64X64
// Look at all the mode_info entries for blocks that are part of this
// partition and find the min and max values for sb_type.
// At the moment this is designed to work on a 64x64 SB but could be
// adjusted to use a size parameter.
//
// The min and max are assumed to have been initialized prior to calling this
// function so repeat calls can accumulate a min and max of more than one sb64.
static void get_sb_partition_size_range(VP9_COMP *cpi, MODE_INFO ** mi_8x8,
                                        BLOCK_SIZE * min_block_size,
                                        BLOCK_SIZE * max_block_size ) {
  MACROBLOCKD *const xd = &cpi->mb.e_mbd;
  int sb_width_in_blocks = MI_BLOCK_SIZE;
  int sb_height_in_blocks  = MI_BLOCK_SIZE;
  int i, j;
  int index = 0;

  // Check the sb_type for each block that belongs to this region.
  for (i = 0; i < sb_height_in_blocks; ++i) {
    for (j = 0; j < sb_width_in_blocks; ++j) {
      MODE_INFO * mi = mi_8x8[index+j];
      BLOCK_SIZE sb_type = mi ? mi->mbmi.sb_type : 0;
      *min_block_size = MIN(*min_block_size, sb_type);
      *max_block_size = MAX(*max_block_size, sb_type);
    }
    index += xd->mode_info_stride;
  }
}
// Next square block size less or equal than current block size.
static const BLOCK_SIZE next_square_size[BLOCK_SIZES] = {
  BLOCK_4X4, BLOCK_4X4, BLOCK_4X4,
  BLOCK_8X8, BLOCK_8X8, BLOCK_8X8,
  BLOCK_16X16, BLOCK_16X16, BLOCK_16X16,
  BLOCK_32X32, BLOCK_32X32, BLOCK_32X32,
  BLOCK_64X64
};

// Look at neighboring blocks and set a min and max partition size based on
// what they chose.
James Zern's avatar
James Zern committed
static void rd_auto_partition_range(VP9_COMP *cpi, const TileInfo *const tile,
                                    int row, int col,
                                    BLOCK_SIZE *min_block_size,
                                    BLOCK_SIZE *max_block_size) {
  VP9_COMMON * const cm = &cpi->common;
  MACROBLOCKD *const xd = &cpi->mb.e_mbd;
  MODE_INFO ** mi_8x8 = xd->mi_8x8;
  MODE_INFO ** prev_mi_8x8 = xd->prev_mi_8x8;

  const int left_in_image = xd->left_available && mi_8x8[-1];
  const int above_in_image = xd->up_available &&
                             mi_8x8[-xd->mode_info_stride];
  MODE_INFO ** above_sb64_mi_8x8;
  MODE_INFO ** left_sb64_mi_8x8;
James Zern's avatar
James Zern committed
  int row8x8_remaining = tile->mi_row_end - row;
  int col8x8_remaining = tile->mi_col_end - col;
  int bh, bw;

  // Trap case where we do not have a prediction.
  if (!left_in_image && !above_in_image &&
      ((cm->frame_type == KEY_FRAME) || !cm->prev_mi)) {
    *min_block_size = BLOCK_4X4;
    *max_block_size = BLOCK_64X64;
  } else {
    // Default "min to max" and "max to min"
    *min_block_size = BLOCK_64X64;
    *max_block_size = BLOCK_4X4;

    // NOTE: each call to get_sb_partition_size_range() uses the previous
    // passed in values for min and max as a starting point.
    //
    // Find the min and max partition used in previous frame at this location
    if (cm->prev_mi && (cm->frame_type != KEY_FRAME)) {
      get_sb_partition_size_range(cpi, prev_mi_8x8,
                                  min_block_size, max_block_size);
    }
    // Find the min and max partition sizes used in the left SB64
    if (left_in_image) {
      left_sb64_mi_8x8 = &mi_8x8[-MI_BLOCK_SIZE];
      get_sb_partition_size_range(cpi, left_sb64_mi_8x8,
                                  min_block_size, max_block_size);
    }
    // Find the min and max partition sizes used in the above SB64.
    if (above_in_image) {
      above_sb64_mi_8x8 = &mi_8x8[-xd->mode_info_stride * MI_BLOCK_SIZE];
      get_sb_partition_size_range(cpi, above_sb64_mi_8x8,
                                  min_block_size, max_block_size);
  // adjust observed min and max
  if (cpi->sf.auto_min_max_partition_size == RELAXED_NEIGHBORING_MIN_MAX) {
    *min_block_size = min_partition_size[*min_block_size];
    *max_block_size = max_partition_size[*max_block_size];
  }

  // Check border cases where max and min from neighbours may not be legal.
  *max_block_size = find_partition_size(*max_block_size,
                                        row8x8_remaining, col8x8_remaining,
                                        &bh, &bw);
  *min_block_size = MIN(*min_block_size, *max_block_size);

  // When use_square_partition_only is true, make sure at least one square
  // partition is allowed by selecting the next smaller square size as
  // *min_block_size.
  if (cpi->sf.use_square_partition_only &&
      next_square_size[*max_block_size] < *min_block_size) {
    *min_block_size = next_square_size[*max_block_size];
static INLINE void store_pred_mv(MACROBLOCK *x, PICK_MODE_CONTEXT *ctx) {
  vpx_memcpy(ctx->pred_mv, x->pred_mv, sizeof(x->pred_mv));
}

static INLINE void load_pred_mv(MACROBLOCK *x, PICK_MODE_CONTEXT *ctx) {
  vpx_memcpy(x->pred_mv, ctx->pred_mv, sizeof(x->pred_mv));
}

// TODO(jingning,jimbankoski,rbultje): properly skip partition types that are
// unlikely to be selected depending on previous rate-distortion optimization
// results, for encoding speed-up.
James Zern's avatar
James Zern committed
static void rd_pick_partition(VP9_COMP *cpi, const TileInfo *const tile,
                              TOKENEXTRA **tp, int mi_row,
                              int mi_col, BLOCK_SIZE bsize, int *rate,
                              int64_t *dist, int do_recon, int64_t best_rd) {
  VP9_COMMON *const cm = &cpi->common;
  MACROBLOCK *const x = &cpi->mb;
Dmitry Kovalev's avatar
Dmitry Kovalev committed
  const int ms = num_8x8_blocks_wide_lookup[bsize] / 2;
Jim Bankoski's avatar
Jim Bankoski committed
  ENTROPY_CONTEXT l[16 * MAX_MB_PLANE], a[16 * MAX_MB_PLANE];
  PARTITION_CONTEXT sl[8], sa[8];
  TOKENEXTRA *tp_orig = *tp;
  PICK_MODE_CONTEXT *ctx = get_block_context(x, bsize);
Jim Bankoski's avatar
Jim Bankoski committed
  int i, pl;
  int this_rate, sum_rate = 0, best_rate = INT_MAX;
  int64_t this_dist, sum_dist = 0, best_dist = INT64_MAX;
  int do_split = bsize >= BLOCK_8X8;
  int do_rect = 1;
  // Override skipping rectangular partition operations for edge blocks
Dmitry Kovalev's avatar
Dmitry Kovalev committed
  const int force_horz_split = (mi_row + ms >= cm->mi_rows);
  const int force_vert_split = (mi_col + ms >= cm->mi_cols);
  const int xss = x->e_mbd.plane[1].subsampling_x;
  const int yss = x->e_mbd.plane[1].subsampling_y;
  int partition_none_allowed = !force_horz_split && !force_vert_split;
  int partition_horz_allowed = !force_vert_split && yss <= xss &&
                               bsize >= BLOCK_8X8;
  int partition_vert_allowed = !force_horz_split && xss <= yss &&
                               bsize >= BLOCK_8X8;
  (void) *tp_orig;

  if (bsize < BLOCK_8X8) {
    // When ab_index = 0 all sub-blocks are handled, so for ab_index != 0
    // there is nothing to be done.
      *rate = 0;
      *dist = 0;
      return;
    }
  assert(num_8x8_blocks_wide_lookup[bsize] ==
             num_8x8_blocks_high_lookup[bsize]);
  if (bsize == BLOCK_16X16) {
James Zern's avatar
James Zern committed
    set_offsets(cpi, tile, mi_row, mi_col, bsize);
    x->mb_energy = vp9_block_energy(cpi, x, bsize);
  }

  // Determine partition types in search according to the speed features.
  // The threshold set here has to be of square block size.
  if (cpi->sf.auto_min_max_partition_size) {
    partition_none_allowed &= (bsize <= cpi->sf.max_partition_size &&
                               bsize >= cpi->sf.min_partition_size);
    partition_horz_allowed &= ((bsize <= cpi->sf.max_partition_size &&
                                bsize >  cpi->sf.min_partition_size) ||
                                force_horz_split);
    partition_vert_allowed &= ((bsize <= cpi->sf.max_partition_size &&
                                bsize >  cpi->sf.min_partition_size) ||
                                force_vert_split);
    do_split &= bsize > cpi->sf.min_partition_size;
  }
  if (cpi->sf.use_square_partition_only) {
    partition_horz_allowed &= force_horz_split;
    partition_vert_allowed &= force_vert_split;
  }

Jim Bankoski's avatar
Jim Bankoski committed
  save_context(cpi, mi_row, mi_col, a, l, sa, sl, bsize);
  if (cpi->sf.disable_split_var_thresh && partition_none_allowed) {
    unsigned int source_variancey;
    vp9_setup_src_planes(x, cpi->Source, mi_row, mi_col);
    source_variancey = get_sby_perpixel_variance(cpi, x, bsize);
    if (source_variancey < cpi->sf.disable_split_var_thresh) {
      if (source_variancey < cpi->sf.disable_split_var_thresh / 2)
        do_rect = 0;
    }
  if (!x->in_active_map && (partition_horz_allowed || partition_vert_allowed))
    do_split = 0;
  // PARTITION_NONE
  if (partition_none_allowed) {
    rd_pick_sb_modes(cpi, tile, mi_row, mi_col, &this_rate, &this_dist, bsize,
                     ctx, best_rd);
    if (this_rate != INT_MAX) {
      if (bsize >= BLOCK_8X8) {
        pl = partition_plane_context(cpi->above_seg_context,
                                     cpi->left_seg_context,
                                     mi_row, mi_col, bsize);
        this_rate += x->partition_cost[pl][PARTITION_NONE];
      }
      sum_rd = RDCOST(x->rdmult, x->rddiv, this_rate, this_dist);
      if (sum_rd < best_rd) {
        int64_t stop_thresh = 4096;
        int64_t stop_thresh_rd;
        best_rate = this_rate;
        best_dist = this_dist;
        best_rd = sum_rd;
        if (bsize >= BLOCK_8X8)
          *(get_sb_partitioning(x, bsize)) = bsize;

        // Adjust threshold according to partition size.
        stop_thresh >>= 8 - (b_width_log2_lookup[bsize] +
            b_height_log2_lookup[bsize]);

        stop_thresh_rd = RDCOST(x->rdmult, x->rddiv, 0, stop_thresh);
        // If obtained distortion is very small, choose current partition
        // and stop splitting.
        if (!x->e_mbd.lossless && best_rd < stop_thresh_rd) {
    if (!x->in_active_map) {
      do_split = 0;
      do_rect = 0;
    }
    restore_context(cpi, mi_row, mi_col, a, l, sa, sl, bsize);
  }
  // store estimated motion vector
  if (cpi->sf.adaptive_motion_search)
    store_pred_mv(x, ctx);
  // PARTITION_SPLIT
  sum_rd = 0;
  // TODO(jingning): use the motion vectors given by the above search as
  // the starting point of motion search in the following partition type check.
  if (do_split) {
    subsize = get_subsize(bsize, PARTITION_SPLIT);
    for (i = 0; i < 4 && sum_rd < best_rd; ++i) {
Dmitry Kovalev's avatar
Dmitry Kovalev committed
      const int x_idx = (i & 1) * ms;
      const int y_idx = (i >> 1) * ms;
Dmitry Kovalev's avatar
Dmitry Kovalev committed
      if (mi_row + y_idx >= cm->mi_rows || mi_col + x_idx >= cm->mi_cols)
      *get_sb_index(x, subsize) = i;
      if (cpi->sf.adaptive_motion_search)
        load_pred_mv(x, ctx);
      if (cpi->sf.adaptive_pred_interp_filter && bsize == BLOCK_8X8 &&
          partition_none_allowed)
        get_block_context(x, subsize)->pred_interp_filter =
            ctx->mic.mbmi.interp_filter;
James Zern's avatar
James Zern committed
      rd_pick_partition(cpi, tile, tp, mi_row + y_idx, mi_col + x_idx, subsize,
                        &this_rate, &this_dist, i != 3, best_rd - sum_rd);

      if (this_rate == INT_MAX) {
        sum_rd = INT64_MAX;
      } else {
        sum_rate += this_rate;
        sum_dist += this_dist;
        sum_rd = RDCOST(x->rdmult, x->rddiv, sum_rate, sum_dist);
    if (sum_rd < best_rd && i == 4) {
      pl = partition_plane_context(cpi->above_seg_context,
                                   cpi->left_seg_context,
                                   mi_row, mi_col, bsize);
      sum_rate += x->partition_cost[pl][PARTITION_SPLIT];
      sum_rd = RDCOST(x->rdmult, x->rddiv, sum_rate, sum_dist);
      if (sum_rd < best_rd) {
        best_rate = sum_rate;
        best_dist = sum_dist;
        best_rd = sum_rd;
        *(get_sb_partitioning(x, bsize)) = subsize;
      }
    } else {
      // skip rectangular partition test when larger block size
      // gives better rd cost
      if (cpi->sf.less_rectangular_check)
        do_rect &= !partition_none_allowed;
    }
    restore_context(cpi, mi_row, mi_col, a, l, sa, sl, bsize);
  // PARTITION_HORZ
  if (partition_horz_allowed && do_rect) {
Loading full blame...