• Paul Wilkins's avatar
    Further work on Segmentation Experiment: · 661b2c2d
    Paul Wilkins authored
    This check in includes quite a lot of clean up and refactoring.
    
    Most of the analysis and set up for the different coding options for the
    segment map (currently simple distribution based coding or temporaly
    predicted coding), has been moved to one location (the function
    choose_segmap_coding_method() in segmenation.c). This code was previously
    scattered around in various locations making integration with other
    experiments and modification / debug more difficult.
    
    Currently the functionality is as it was with the exception that the
    prediction probabilities are now only transmitted when the temporal
    prediction mode is selected.
    
    There is still quite a bit more clean up work that will be possible
    when the #ifdef is removed. Also at that time I may rename and alter
    the sense of macroblock based variable "segment_flag" which indicates
    (1 that the segmnet id is not predicted vs 0 that it is predicted).
    
    I also intend to experiment with a spatial prediction mode that can be
    used when coding a key frame segment map or in cases where temporal
    prediction does not work well but there is spatial correlation.
    
    In a later check in when the ifdefs have gone I may also move the call
    to choose_segmap_coding_method() to just before where the bitsream is
    packed (currently it is in vp8_encode_frame()) to further reduce the
    possibility of clashes with other experiments and prevent it being called
    on each itteration of the recode loop.
    
    Change-Id: I3d4aba2a2826ec21f367678d5b07c1d1c36db168
    661b2c2d
vp9_encodeframe.c 86.32 KiB
/*
 *  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 "./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_extend.h"
#include "vp9/common/vp9_findnearmv.h"
#include "vp9/common/vp9_idct.h"
#include "vp9/common/vp9_mvref_common.h"
#include "vp9/common/vp9_pred_common.h"
#include "vp9/common/vp9_quant_common.h"
#include "vp9/common/vp9_reconintra.h"
#include "vp9/common/vp9_reconinter.h"
#include "vp9/common/vp9_seg_common.h"
#include "vp9/common/vp9_tile_common.h"
#include "vp9/encoder/vp9_encodeframe.h"
#include "vp9/encoder/vp9_encodeintra.h"
#include "vp9/encoder/vp9_encodemb.h"
#include "vp9/encoder/vp9_encodemv.h"
#include "vp9/encoder/vp9_onyx_int.h"
#include "vp9/encoder/vp9_rdopt.h"
#include "vp9/encoder/vp9_segmentation.h"
#include "vp9/common/vp9_systemdependent.h"
#include "vp9/encoder/vp9_tokenize.h"
#include "vp9/encoder/vp9_vaq.h"
#define DBG_PRNT_SEGMAP 0
static const TX_SIZE tx_mode_to_biggest_tx_size[TX_MODES] = {
  TX_4X4,  // ONLY_4X4
  TX_8X8,  // ONLY_8X8
  TX_16X16,  // ONLY_16X16
  TX_32X32,  // ONLY_32X32
  TX_32X32,  // TX_MODE_SELECT
// #define ENC_DEBUG
#ifdef ENC_DEBUG
int enc_debug = 0;
#endif
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().
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
*/ #define ACTIVITY_AVG_MIN (64) /* Motion vector component magnitude threshold for defining fast motion. */ #define FAST_MOTION_MV_THRESH (24) /* This is used as a reference when computing the source variance for the * purposes of activity masking. * Eventually this should be replaced by custom no-reference routines, * which will be faster. */ static const uint8_t VP9_VAR_OFFS[64] = { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }; static unsigned int get_sby_perpixel_variance(VP9_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bs) { unsigned int var, sse; var = cpi->fn_ptr[bs].vf(x->plane[0].src.buf, x->plane[0].src.stride, VP9_VAR_OFFS, 0, &sse); return (var + (1 << (num_pels_log2_lookup[bs] - 1))) >> num_pels_log2_lookup[bs]; } // Original activity measure from Tim T's code. static unsigned int tt_activity_measure(MACROBLOCK *x) { unsigned int act; unsigned int sse; /* TODO: This could also be done over smaller areas (8x8), but that would * require extensive changes elsewhere, as lambda is assumed to be fixed * over an entire MB in most of the code. * Another option is to compute four 8x8 variances, and pick a single * lambda using a non-linear combination (e.g., the smallest, or second * smallest, etc.). */ act = vp9_variance16x16(x->plane[0].src.buf, x->plane[0].src.stride, VP9_VAR_OFFS, 0, &sse); act <<= 4; /* If the region is flat, lower the activity some more. */ if (act < 8 << 12) act = act < 5 << 12 ? act : 5 << 12; return act; } // Stub for alternative experimental activity measures. static unsigned int alt_activity_measure(MACROBLOCK *x, int use_dc_pred) { return vp9_encode_intra(x, use_dc_pred); } // Measure the activity of the current macroblock // What we measure here is TBD so abstracted to this function #define ALT_ACT_MEASURE 1 static unsigned int mb_activity_measure(MACROBLOCK *x, int mb_row, int mb_col) { unsigned int mb_activity; if (ALT_ACT_MEASURE) { int use_dc_pred = (mb_col || mb_row) && (!mb_col || !mb_row); // Or use and alternative. mb_activity = alt_activity_measure(x, use_dc_pred);
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
} else { // Original activity measure from Tim T's code. mb_activity = tt_activity_measure(x); } if (mb_activity < ACTIVITY_AVG_MIN) mb_activity = ACTIVITY_AVG_MIN; return mb_activity; } // 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 // Find median: Simple n^2 algorithm for experimentation { unsigned int median; unsigned int i, j; unsigned int *sortlist; unsigned int tmp; // Create a list to sort to CHECK_MEM_ERROR(&cpi->common, sortlist, vpx_calloc(sizeof(unsigned int), cpi->common.MBs)); // Copy map to sort list vpx_memcpy(sortlist, cpi->mb_activity_map, sizeof(unsigned int) * cpi->common.MBs); // 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; } else { break; } } } // Even number MBs so estimate median as mean of two either side. median = (1 + sortlist[cpi->common.MBs >> 1] + sortlist[(cpi->common.MBs >> 1) + 1]) >> 1; cpi->activity_avg = median; vpx_free(sortlist); } #else // Simple mean for now 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; // 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
211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
static void calc_activity_index(VP9_COMP *cpi, MACROBLOCK *x) { VP9_COMMON *const cm = &cpi->common; int mb_row, mb_col; int64_t act; int64_t a; int64_t b; #if OUTPUT_NORM_ACT_STATS FILE *f = fopen("norm_act.stt", "a"); fprintf(f, "\n%12d\n", cpi->activity_avg); #endif // Reset pointers to start of activity map x->mb_activity_ptr = cpi->mb_activity_map; // Calculate normalized mb activity number. for (mb_row = 0; mb_row < cm->mb_rows; mb_row++) { // for each macroblock col in image for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) { // Read activity from the map act = *(x->mb_activity_ptr); // Calculate a normalized activity number a = act + 4 * cpi->activity_avg; b = 4 * act + cpi->activity_avg; if (b >= a) *(x->activity_ptr) = (int)((b + (a >> 1)) / a) - 1; else *(x->activity_ptr) = 1 - (int)((a + (b >> 1)) / b); #if OUTPUT_NORM_ACT_STATS fprintf(f, " %6d", *(x->mb_activity_ptr)); #endif // Increment activity map pointers x->mb_activity_ptr++; } #if OUTPUT_NORM_ACT_STATS fprintf(f, "\n"); #endif } #if OUTPUT_NORM_ACT_STATS fclose(f); #endif } #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; MACROBLOCKD *xd = &x->e_mbd; VP9_COMMON * const cm = &cpi->common; #if ALT_ACT_MEASURE YV12_BUFFER_CONFIG *new_yv12 = &cm->yv12_fb[cm->new_fb_idx]; int recon_yoffset; int recon_y_stride = new_yv12->y_stride; #endif int mb_row, mb_col; unsigned int mb_activity; int64_t activity_sum = 0; x->mb_activity_ptr = cpi->mb_activity_map; // for each macroblock row in image
281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
for (mb_row = 0; mb_row < cm->mb_rows; mb_row++) { #if ALT_ACT_MEASURE // reset above block coeffs xd->up_available = (mb_row != 0); recon_yoffset = (mb_row * recon_y_stride * 16); #endif // 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; xd->left_available = (mb_col != 0); recon_yoffset += 16; #endif // measure activity mb_activity = mb_activity_measure(x, mb_row, mb_col); // Keep frame sum activity_sum += mb_activity; // Store MB level activity details. *x->mb_activity_ptr = mb_activity; // Increment activity map pointer x->mb_activity_ptr++; // adjust to the next column of source macroblocks x->plane[0].src.buf += 16; } // adjust to the next row of mbs x->plane[0].src.buf += 16 * x->plane[0].src.stride - 16 * cm->mb_cols; } // Calculate an "average" MB activity calc_av_activity(cpi, activity_sum); #if USE_ACT_INDEX // Calculate an activity index number of each mb calc_activity_index(cpi, x); #endif } // Macroblock activity masking void vp9_activity_masking(VP9_COMP *cpi, MACROBLOCK *x) { #if USE_ACT_INDEX x->rdmult += *(x->mb_activity_ptr) * (x->rdmult >> 2); x->errorperbit = x->rdmult * 100 / (110 * x->rddiv); x->errorperbit += (x->errorperbit == 0); #else int64_t a; int64_t b; int64_t act = *(x->mb_activity_ptr); // Apply the masking to the RD multiplier. a = act + (2 * cpi->activity_avg); b = (2 * act) + cpi->activity_avg; x->rdmult = (unsigned int) (((int64_t) x->rdmult * b + (a >> 1)) / a); x->errorperbit = x->rdmult * 100 / (110 * x->rddiv); x->errorperbit += (x->errorperbit == 0); #endif // Activity based Zbin adjustment adjust_act_zbin(cpi, x); } static void update_state(VP9_COMP *cpi, PICK_MODE_CONTEXT *ctx, BLOCK_SIZE bsize, int output_enabled) { int i, x_idx, y;
351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
VP9_COMMON *const cm = &cpi->common; MACROBLOCK *const x = &cpi->mb; MACROBLOCKD *const xd = &x->e_mbd; MODE_INFO *mi = &ctx->mic; MB_MODE_INFO *const mbmi = &xd->mi_8x8[0]->mbmi; MODE_INFO *mi_addr = xd->mi_8x8[0]; int mb_mode_index = ctx->best_mode_index; const int mis = cm->mode_info_stride; const int mi_width = num_8x8_blocks_wide_lookup[bsize]; const int mi_height = num_8x8_blocks_high_lookup[bsize]; assert(mi->mbmi.mode < MB_MODE_COUNT); assert(mi->mbmi.ref_frame[0] < MAX_REF_FRAMES); assert(mi->mbmi.ref_frame[1] < MAX_REF_FRAMES); assert(mi->mbmi.sb_type == bsize); *mi_addr = *mi; // 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->sf.variance_adaptive_quantization) { vp9_mb_init_quantizer(cpi, x); } // FIXME(rbultje) I'm pretty sure this should go to the end of this block // (i.e. after the output_enabled) if (bsize < BLOCK_32X32) { if (bsize < BLOCK_16X16) ctx->tx_rd_diff[ALLOW_16X16] = ctx->tx_rd_diff[ALLOW_8X8]; ctx->tx_rd_diff[ALLOW_32X32] = ctx->tx_rd_diff[ALLOW_16X16]; } if (is_inter_block(mbmi) && mbmi->sb_type < BLOCK_8X8) { mbmi->mv[0].as_int = mi->bmi[3].as_mv[0].as_int; mbmi->mv[1].as_int = mi->bmi[3].as_mv[1].as_int; } x->skip = ctx->skip; vpx_memcpy(x->zcoeff_blk[mbmi->tx_size], ctx->zcoeff_blk, sizeof(ctx->zcoeff_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)) { #if CONFIG_INTERNAL_STATS static const int kf_mode_index[] = { THR_DC /*DC_PRED*/, THR_V_PRED /*V_PRED*/, THR_H_PRED /*H_PRED*/, THR_D45_PRED /*D45_PRED*/, THR_D135_PRED /*D135_PRED*/, THR_D117_PRED /*D117_PRED*/, THR_D153_PRED /*D153_PRED*/, THR_D207_PRED /*D207_PRED*/, THR_D63_PRED /*D63_PRED*/, THR_TM /*TM_PRED*/, };
421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
cpi->mode_chosen_counts[kf_mode_index[mi->mbmi.mode]]++; #endif } else { // Note how often each mode chosen as best cpi->mode_chosen_counts[mb_mode_index]++; if (is_inter_block(mbmi) && (mbmi->sb_type < BLOCK_8X8 || mbmi->mode == NEWMV)) { int_mv best_mv[2]; const MV_REFERENCE_FRAME rf1 = mbmi->ref_frame[0]; const MV_REFERENCE_FRAME rf2 = mbmi->ref_frame[1]; best_mv[0].as_int = ctx->best_ref_mv.as_int; best_mv[1].as_int = ctx->second_best_ref_mv.as_int; if (mbmi->mode == NEWMV) { best_mv[0].as_int = mbmi->ref_mvs[rf1][0].as_int; if (rf2 > 0) best_mv[1].as_int = mbmi->ref_mvs[rf2][0].as_int; } mbmi->best_mv[0].as_int = best_mv[0].as_int; mbmi->best_mv[1].as_int = best_mv[1].as_int; vp9_update_mv_count(cpi, x, best_mv); } if (cm->mcomp_filter_type == SWITCHABLE && is_inter_mode(mbmi->mode)) { const int ctx = vp9_get_pred_context_switchable_interp(xd); ++cm->counts.switchable_interp[ctx][mbmi->interp_filter]; } cpi->rd_comp_pred_diff[SINGLE_PREDICTION_ONLY] += ctx->single_pred_diff; cpi->rd_comp_pred_diff[COMP_PREDICTION_ONLY] += ctx->comp_pred_diff; cpi->rd_comp_pred_diff[HYBRID_PREDICTION] += ctx->hybrid_pred_diff; for (i = 0; i <= SWITCHABLE_FILTERS; i++) cpi->rd_filter_diff[i] += ctx->best_filter_diff[i]; } } void vp9_setup_src_planes(MACROBLOCK *x, const YV12_BUFFER_CONFIG *src, int mi_row, int mi_col) { uint8_t *const buffers[4] = {src->y_buffer, src->u_buffer, src->v_buffer, src->alpha_buffer}; const int strides[4] = {src->y_stride, src->uv_stride, src->uv_stride, src->alpha_stride}; int i; for (i = 0; i < MAX_MB_PLANE; i++) setup_pred_plane(&x->plane[i].src, buffers[i], strides[i], mi_row, mi_col, NULL, x->e_mbd.plane[i].subsampling_x, x->e_mbd.plane[i].subsampling_y); } static void set_offsets(VP9_COMP *cpi, int mi_row, int mi_col, BLOCK_SIZE bsize) { MACROBLOCK *const x = &cpi->mb; VP9_COMMON *const cm = &cpi->common; MACROBLOCKD *const xd = &x->e_mbd; MB_MODE_INFO *mbmi; const int dst_fb_idx = cm->new_fb_idx; const int idx_str = xd->mode_info_stride * mi_row + mi_col; const int mi_width = num_8x8_blocks_wide_lookup[bsize]; const int mi_height = num_8x8_blocks_high_lookup[bsize]; const int mb_row = mi_row >> 1; const int mb_col = mi_col >> 1; const int idx_map = mb_row * cm->mb_cols + mb_col; const struct segmentation *const seg = &cm->seg; set_skip_context(cm, xd, mi_row, mi_col); set_partition_seg_context(cm, xd, mi_row, mi_col); // Activity map pointer x->mb_activity_ptr = &cpi->mb_activity_map[idx_map];
491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
x->active_ptr = cpi->active_map + idx_map; xd->mi_8x8 = cm->mi_grid_visible + idx_str; xd->prev_mi_8x8 = cm->prev_mi_grid_visible + idx_str; // Special case: if prev_mi is NULL, the previous mode info context // cannot be used. xd->last_mi = cm->prev_mi ? xd->prev_mi_8x8[0] : NULL; xd->mi_8x8[0] = cm->mi + idx_str; mbmi = &xd->mi_8x8[0]->mbmi; // Set up destination pointers setup_dst_planes(xd, &cm->yv12_fb[dst_fb_idx], mi_row, mi_col); // Set up limit values for MV components // mv beyond the range do not produce new/different prediction block x->mv_row_min = -(((mi_row + mi_height) * MI_SIZE) + VP9_INTERP_EXTEND); x->mv_col_min = -(((mi_col + mi_width) * MI_SIZE) + VP9_INTERP_EXTEND); x->mv_row_max = (cm->mi_rows - mi_row) * MI_SIZE + VP9_INTERP_EXTEND; x->mv_col_max = (cm->mi_cols - mi_col) * MI_SIZE + VP9_INTERP_EXTEND; // Set up distance of MB to edge of frame in 1/8th pel units assert(!(mi_col & (mi_width - 1)) && !(mi_row & (mi_height - 1))); set_mi_row_col(cm, xd, mi_row, mi_height, mi_col, mi_width); /* 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; /* segment ID */ if (seg->enabled) { if (!cpi->sf.variance_adaptive_quantization) { uint8_t *map = seg->update_map ? cpi->segmentation_map : cm->last_frame_seg_map; mbmi->segment_id = vp9_get_segment_id(cm, map, bsize, mi_row, mi_col); } vp9_mb_init_quantizer(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 = cm->cur_tile_mi_col_start * cm->mb_rows >> 1; const int mb_cols = (cm->cur_tile_mi_col_end - cm->cur_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->oxcf.encode_breakout; } } static void pick_sb_modes(VP9_COMP *cpi, int mi_row, int mi_col, int *totalrate, int64_t *totaldist, BLOCK_SIZE bsize, PICK_MODE_CONTEXT *ctx,
561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630
int64_t best_rd) { VP9_COMMON *const cm = &cpi->common; MACROBLOCK *const x = &cpi->mb; MACROBLOCKD *const xd = &x->e_mbd; int orig_rdmult = x->rdmult; double rdmult_ratio; vp9_clear_system_state(); // __asm emms; rdmult_ratio = 1.0; // avoid uninitialized warnings // Use the lower precision, but faster, 32x32 fdct for mode selection. x->use_lp32x32fdct = 1; if (bsize < BLOCK_8X8) { // When ab_index = 0 all sub-blocks are handled, so for ab_index != 0 // there is nothing to be done. if (xd->ab_index != 0) { *totalrate = 0; *totaldist = 0; return; } } set_offsets(cpi, mi_row, mi_col, bsize); xd->mi_8x8[0]->mbmi.sb_type = bsize; // Set to zero to make sure we do not use the previous encoded frame stats xd->mi_8x8[0]->mbmi.skip_coeff = 0; x->source_variance = get_sby_perpixel_variance(cpi, x, bsize); if (cpi->sf.variance_adaptive_quantization) { int energy; if (bsize <= BLOCK_16X16) { energy = x->mb_energy; } else { energy = vp9_block_energy(cpi, x, bsize); } xd->mi_8x8[0]->mbmi.segment_id = vp9_vaq_segment_id(energy); rdmult_ratio = vp9_vaq_rdmult_ratio(energy); vp9_mb_init_quantizer(cpi, x); } if (cpi->oxcf.tuning == VP8_TUNE_SSIM) vp9_activity_masking(cpi, x); if (cpi->sf.variance_adaptive_quantization) { vp9_clear_system_state(); // __asm emms; x->rdmult = round(x->rdmult * rdmult_ratio); } // Find best coding mode & reconstruct the MB so it is available // as a predictor for MBs that follow in the SB if (frame_is_intra_only(cm)) { vp9_rd_pick_intra_mode_sb(cpi, x, totalrate, totaldist, bsize, ctx, best_rd); } else { if (bsize >= BLOCK_8X8) vp9_rd_pick_inter_mode_sb(cpi, x, mi_row, mi_col, totalrate, totaldist, bsize, ctx, best_rd); else vp9_rd_pick_inter_mode_sub8x8(cpi, x, mi_row, mi_col, totalrate, totaldist, bsize, ctx, best_rd); } if (cpi->sf.variance_adaptive_quantization) { x->rdmult = orig_rdmult; if (*totalrate != INT_MAX) { vp9_clear_system_state(); // __asm emms;
631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700
*totalrate = round(*totalrate * rdmult_ratio); } } } static void update_stats(VP9_COMP *cpi) { VP9_COMMON *const cm = &cpi->common; MACROBLOCK *const x = &cpi->mb; MACROBLOCKD *const xd = &x->e_mbd; MODE_INFO *mi = xd->mi_8x8[0]; MB_MODE_INFO *const mbmi = &mi->mbmi; if (!frame_is_intra_only(cm)) { const int seg_ref_active = vp9_segfeature_active(&cm->seg, mbmi->segment_id, SEG_LVL_REF_FRAME); if (!seg_ref_active) cpi->intra_inter_count[vp9_get_pred_context_intra_inter(xd)] [is_inter_block(mbmi)]++; // If the segment reference feature is enabled we have only a single // reference frame allowed for the segment so exclude it from // the reference frame counts used to work out probabilities. if (is_inter_block(mbmi) && !seg_ref_active) { if (cm->comp_pred_mode == HYBRID_PREDICTION) cpi->comp_inter_count[vp9_get_pred_context_comp_inter_inter(cm, xd)] [has_second_ref(mbmi)]++; if (has_second_ref(mbmi)) { cpi->comp_ref_count[vp9_get_pred_context_comp_ref_p(cm, xd)] [mbmi->ref_frame[0] == GOLDEN_FRAME]++; } else { cpi->single_ref_count[vp9_get_pred_context_single_ref_p1(xd)][0] [mbmi->ref_frame[0] != LAST_FRAME]++; if (mbmi->ref_frame[0] != LAST_FRAME) cpi->single_ref_count[vp9_get_pred_context_single_ref_p2(xd)][1] [mbmi->ref_frame[0] != GOLDEN_FRAME]++; } } // Count of last ref frame 0,0 usage if (mbmi->mode == ZEROMV && mbmi->ref_frame[0] == LAST_FRAME) cpi->inter_zz_count++; } } // TODO(jingning): the variables used here are little complicated. need further // refactoring on organizing the temporary buffers, when recursive // partition down to 4x4 block size is enabled. static PICK_MODE_CONTEXT *get_block_context(MACROBLOCK *x, BLOCK_SIZE bsize) { MACROBLOCKD *const xd = &x->e_mbd; switch (bsize) { case BLOCK_64X64: return &x->sb64_context; case BLOCK_64X32: return &x->sb64x32_context[xd->sb_index]; case BLOCK_32X64: return &x->sb32x64_context[xd->sb_index]; case BLOCK_32X32: return &x->sb32_context[xd->sb_index]; case BLOCK_32X16: return &x->sb32x16_context[xd->sb_index][xd->mb_index]; case BLOCK_16X32: return &x->sb16x32_context[xd->sb_index][xd->mb_index]; case BLOCK_16X16: return &x->mb_context[xd->sb_index][xd->mb_index]; case BLOCK_16X8: return &x->sb16x8_context[xd->sb_index][xd->mb_index][xd->b_index]; case BLOCK_8X16:
701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770
return &x->sb8x16_context[xd->sb_index][xd->mb_index][xd->b_index]; case BLOCK_8X8: return &x->sb8x8_context[xd->sb_index][xd->mb_index][xd->b_index]; case BLOCK_8X4: return &x->sb8x4_context[xd->sb_index][xd->mb_index][xd->b_index]; case BLOCK_4X8: return &x->sb4x8_context[xd->sb_index][xd->mb_index][xd->b_index]; case BLOCK_4X4: return &x->ab4x4_context[xd->sb_index][xd->mb_index][xd->b_index]; default: assert(0); return NULL; } } static BLOCK_SIZE *get_sb_partitioning(MACROBLOCK *x, BLOCK_SIZE bsize) { MACROBLOCKD *const xd = &x->e_mbd; switch (bsize) { case BLOCK_64X64: return &x->sb64_partitioning; case BLOCK_32X32: return &x->sb_partitioning[xd->sb_index]; case BLOCK_16X16: return &x->mb_partitioning[xd->sb_index][xd->mb_index]; case BLOCK_8X8: return &x->b_partitioning[xd->sb_index][xd->mb_index][xd->b_index]; default: assert(0); return NULL; } } 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) { VP9_COMMON *const cm = &cpi->common; MACROBLOCK *const x = &cpi->mb; MACROBLOCKD *const xd = &x->e_mbd; int p; 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++) { vpx_memcpy( cm->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); vpx_memcpy( cm->left_context[p] + ((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(cm->above_seg_context + mi_col, sa, sizeof(PARTITION_CONTEXT) * mi_width); vpx_memcpy(cm->left_seg_context + (mi_row & MI_MASK), sl, sizeof(PARTITION_CONTEXT) * 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 VP9_COMMON *const cm = &cpi->common; const MACROBLOCK *const x = &cpi->mb;
771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840
const MACROBLOCKD *const xd = &x->e_mbd; int p; 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) { vpx_memcpy( a + num_4x4_blocks_wide * p, cm->above_context[p] + (mi_col * 2 >> xd->plane[p].subsampling_x), (sizeof(ENTROPY_CONTEXT) * num_4x4_blocks_wide) >> xd->plane[p].subsampling_x); vpx_memcpy( l + num_4x4_blocks_high * p, cm->left_context[p] + ((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, cm->above_seg_context + mi_col, sizeof(PARTITION_CONTEXT) * mi_width); vpx_memcpy(sl, cm->left_seg_context + (mi_row & MI_MASK), sizeof(PARTITION_CONTEXT) * mi_height); } static void encode_b(VP9_COMP *cpi, TOKENEXTRA **tp, int mi_row, int mi_col, int output_enabled, BLOCK_SIZE bsize, int sub_index) { VP9_COMMON * const cm = &cpi->common; MACROBLOCK * const x = &cpi->mb; MACROBLOCKD * const xd = &x->e_mbd; if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols) return; if (sub_index != -1) *get_sb_index(xd, bsize) = sub_index; if (bsize < BLOCK_8X8) { // When ab_index = 0 all sub-blocks are handled, so for ab_index != 0 // there is nothing to be done. if (xd->ab_index > 0) return; } set_offsets(cpi, 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); if (output_enabled) { update_stats(cpi); (*tp)->token = EOSB_TOKEN; (*tp)++; } } static void encode_sb(VP9_COMP *cpi, 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; MACROBLOCKD * const xd = &x->e_mbd; BLOCK_SIZE c1 = BLOCK_8X8; const int bsl = b_width_log2(bsize), bs = (1 << bsl) / 4; int pl = 0; PARTITION_TYPE partition; BLOCK_SIZE subsize; int i; if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols)
841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910
return; c1 = BLOCK_4X4; if (bsize >= BLOCK_8X8) { set_partition_seg_context(cm, xd, mi_row, mi_col); pl = partition_plane_context(xd, bsize); c1 = *(get_sb_partitioning(x, bsize)); } partition = partition_lookup[bsl][c1]; switch (partition) { case PARTITION_NONE: if (output_enabled && bsize >= BLOCK_8X8) cpi->partition_count[pl][PARTITION_NONE]++; encode_b(cpi, tp, mi_row, mi_col, output_enabled, c1, -1); break; case PARTITION_VERT: if (output_enabled) cpi->partition_count[pl][PARTITION_VERT]++; encode_b(cpi, tp, mi_row, mi_col, output_enabled, c1, 0); encode_b(cpi, tp, mi_row, mi_col + bs, output_enabled, c1, 1); break; case PARTITION_HORZ: if (output_enabled) cpi->partition_count[pl][PARTITION_HORZ]++; encode_b(cpi, tp, mi_row, mi_col, output_enabled, c1, 0); encode_b(cpi, tp, mi_row + bs, mi_col, output_enabled, c1, 1); break; case PARTITION_SPLIT: subsize = get_subsize(bsize, PARTITION_SPLIT); if (output_enabled) cpi->partition_count[pl][PARTITION_SPLIT]++; for (i = 0; i < 4; i++) { const int x_idx = i & 1, y_idx = i >> 1; *get_sb_index(xd, subsize) = i; encode_sb(cpi, tp, mi_row + y_idx * bs, mi_col + x_idx * bs, output_enabled, subsize); } break; default: assert(0); break; } if (partition != PARTITION_SPLIT || bsize == BLOCK_8X8) { set_partition_seg_context(cm, xd, mi_row, mi_col); update_partition_context(xd, c1, bsize); } } // Check to see if the given partition size is allowed for a specified number // of 8x8 block rows and columns remaining in the image. // If not then return the largest allowed partition size static BLOCK_SIZE find_partition_size(BLOCK_SIZE bsize, int rows_left, int cols_left, int *bh, int *bw) { if ((rows_left <= 0) || (cols_left <= 0)) { return MIN(bsize, BLOCK_8X8); } else { for (; bsize > 0; --bsize) { *bh = num_8x8_blocks_high_lookup[bsize]; *bw = num_8x8_blocks_wide_lookup[bsize]; if ((*bh <= rows_left) && (*bw <= cols_left)) { break; } } }
911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980
return bsize; } // This function attempts to set all mode info entries in a given SB64 // to the same block partition size. // However, at the bottom and right borders of the image the requested size // may not be allowed in which case this code attempts to choose the largest // allowable partition. static void set_partitioning(VP9_COMP *cpi, MODE_INFO **mi_8x8, int mi_row, int mi_col) { VP9_COMMON *const cm = &cpi->common; BLOCK_SIZE bsize = cpi->sf.always_this_block_size; const int mis = cm->mode_info_stride; int row8x8_remaining = cm->cur_tile_mi_row_end - mi_row; int col8x8_remaining = cm->cur_tile_mi_col_end - mi_col; 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]; 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; } } } 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; // Find a partition size that fits bsize = find_partition_size(cpi->sf.always_this_block_size, (row8x8_remaining - block_row), (col8x8_remaining - block_col), &bh, &bw); mi_8x8[index] = mi_upper_left + index; mi_8x8[index]->mbmi.sb_type = bsize; } } } } static void copy_partitioning(VP9_COMP *cpi, MODE_INFO **mi_8x8, MODE_INFO **prev_mi_8x8) { VP9_COMMON *const cm = &cpi->common; 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 * prev_mi = prev_mi_8x8[block_row * mis + block_col]; BLOCK_SIZE sb_type = prev_mi ? prev_mi->mbmi.sb_type : 0; ptrdiff_t offset; if (prev_mi) { 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(VP9_COMP *cpi, MODE_INFO **prev_mi_8x8) {
981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050
VP9_COMMON *const cm = &cpi->common; 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) { 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 rd_use_partition(VP9_COMP *cpi, 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; MACROBLOCKD *xd = &cpi->mb.e_mbd; const int mis = cm->mode_info_stride; int bsl = b_width_log2(bsize); 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 ms = num_4x4_blocks_wide / 2; int mh = num_4x4_blocks_high / 2; int bss = (1 << bsl) / 4; int i, pl; PARTITION_TYPE partition = PARTITION_NONE; BLOCK_SIZE subsize; 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 = INT_MAX; int split_rate = INT_MAX; int64_t split_dist = INT_MAX; int none_rate = INT_MAX; int64_t none_dist = INT_MAX; int chosen_rate = INT_MAX; int64_t chosen_dist = INT_MAX; BLOCK_SIZE sub_subsize = BLOCK_4X4; int splits_below = 0; BLOCK_SIZE bs_type = mi_8x8[0]->mbmi.sb_type; if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols) return; partition = partition_lookup[bsl][bs_type]; 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. if (xd->ab_index != 0) { *rate = 0; *dist = 0; return; } } else { *(get_sb_partitioning(x, bsize)) = subsize; } save_context(cpi, mi_row, mi_col, a, l, sa, sl, bsize);
1051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120
if (bsize == BLOCK_16X16) { set_offsets(cpi, mi_row, mi_col, bsize); x->mb_energy = vp9_block_energy(cpi, x, bsize); } x->fast_ms = 0; x->subblock_ref = 0; if (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; pick_sb_modes(cpi, mi_row, mi_col, &none_rate, &none_dist, bsize, get_block_context(x, bsize), INT64_MAX); set_partition_seg_context(cm, xd, mi_row, mi_col); pl = partition_plane_context(xd, bsize); none_rate += x->partition_cost[pl][PARTITION_NONE]; 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; } } switch (partition) { case PARTITION_NONE: pick_sb_modes(cpi, mi_row, mi_col, &last_part_rate, &last_part_dist, bsize, get_block_context(x, bsize), INT64_MAX); break; case PARTITION_HORZ: *get_sb_index(xd, subsize) = 0; pick_sb_modes(cpi, mi_row, mi_col, &last_part_rate, &last_part_dist, subsize, get_block_context(x, subsize), INT64_MAX); if (last_part_rate != INT_MAX && bsize >= BLOCK_8X8 && mi_row + (mh >> 1) < cm->mi_rows) { int rt = 0; int64_t dt = 0; update_state(cpi, get_block_context(x, subsize), subsize, 0); encode_superblock(cpi, tp, 0, mi_row, mi_col, subsize); *get_sb_index(xd, subsize) = 1; pick_sb_modes(cpi, mi_row + (ms >> 1), mi_col, &rt, &dt, subsize, get_block_context(x, subsize), INT64_MAX); if (rt == INT_MAX || dt == INT_MAX) { last_part_rate = INT_MAX; last_part_dist = INT_MAX; break; } last_part_rate += rt; last_part_dist += dt; } break; case PARTITION_VERT:
1121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190
*get_sb_index(xd, subsize) = 0; pick_sb_modes(cpi, mi_row, mi_col, &last_part_rate, &last_part_dist, subsize, get_block_context(x, subsize), INT64_MAX); if (last_part_rate != INT_MAX && bsize >= BLOCK_8X8 && mi_col + (ms >> 1) < cm->mi_cols) { int rt = 0; int64_t dt = 0; update_state(cpi, get_block_context(x, subsize), subsize, 0); encode_superblock(cpi, tp, 0, mi_row, mi_col, subsize); *get_sb_index(xd, subsize) = 1; pick_sb_modes(cpi, mi_row, mi_col + (ms >> 1), &rt, &dt, subsize, get_block_context(x, subsize), INT64_MAX); if (rt == INT_MAX || dt == INT_MAX) { last_part_rate = INT_MAX; last_part_dist = INT_MAX; break; } last_part_rate += rt; last_part_dist += dt; } break; case PARTITION_SPLIT: // Split partition. last_part_rate = 0; last_part_dist = 0; for (i = 0; i < 4; i++) { int x_idx = (i & 1) * (ms >> 1); int y_idx = (i >> 1) * (ms >> 1); int jj = i >> 1, ii = i & 0x01; int rt; int64_t dt; if ((mi_row + y_idx >= cm->mi_rows) || (mi_col + x_idx >= cm->mi_cols)) continue; *get_sb_index(xd, subsize) = i; rd_use_partition(cpi, 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 == INT_MAX) { last_part_rate = INT_MAX; last_part_dist = INT_MAX; break; } last_part_rate += rt; last_part_dist += dt; } break; default: assert(0); } set_partition_seg_context(cm, xd, mi_row, mi_col); pl = partition_plane_context(xd, bsize); if (last_part_rate < INT_MAX) last_part_rate += x->partition_cost[pl][partition]; if (cpi->sf.adjust_partitioning_from_last_frame && 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); split_rate = 0; split_dist = 0; restore_context(cpi, mi_row, mi_col, a, l, sa, sl, bsize); // Split partition. for (i = 0; i < 4; i++) { int x_idx = (i & 1) * (num_4x4_blocks_wide >> 2); int y_idx = (i >> 1) * (num_4x4_blocks_wide >> 2);
1191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260
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)) continue; *get_sb_index(xd, split_subsize) = i; *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); pick_sb_modes(cpi, 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 == INT_MAX) { split_rate = INT_MAX; split_dist = INT_MAX; break; } if (i != 3) encode_sb(cpi, tp, mi_row + y_idx, mi_col + x_idx, 0, split_subsize); split_rate += rt; split_dist += dt; set_partition_seg_context(cm, xd, mi_row + y_idx, mi_col + x_idx); pl = partition_plane_context(xd, bsize); split_rate += x->partition_cost[pl][PARTITION_NONE]; } set_partition_seg_context(cm, xd, mi_row, mi_col); pl = partition_plane_context(xd, bsize); if (split_rate < INT_MAX) { split_rate += x->partition_cost[pl][PARTITION_SPLIT]; chosen_rate = split_rate; chosen_dist = split_dist; } } // If last_part is better set the partitioning to that... if (RDCOST(x->rdmult, x->rddiv, last_part_rate, last_part_dist) < RDCOST(x->rdmult, x->rddiv, chosen_rate, chosen_dist)) { 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; } // If none was better set the partitioning to that... if (RDCOST(x->rdmult, x->rddiv, chosen_rate, chosen_dist) > RDCOST(x->rdmult, x->rddiv, none_rate, none_dist)) { if (bsize >= BLOCK_8X8) *(get_sb_partitioning(x, bsize)) = bsize; chosen_rate = none_rate; chosen_dist = none_dist; } 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)
1261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330
assert(chosen_rate < INT_MAX && chosen_dist < INT_MAX); if (do_recon) encode_sb(cpi, tp, mi_row, mi_col, bsize == BLOCK_64X64, 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; } } // Look at neighboring blocks and set a min and max partition size based on // what they chose. static void rd_auto_partition_range(VP9_COMP *cpi, 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; int row8x8_remaining = cm->cur_tile_mi_row_end - row; int col8x8_remaining = cm->cur_tile_mi_col_end - col; int bh, bw; // Trap case where we do not have a prediction.
1331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400
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); } } // Give a bit of leaway either side of the observed min and 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); } static void compute_fast_motion_search_level(VP9_COMP *cpi, BLOCK_SIZE bsize) { VP9_COMMON *const cm = &cpi->common; MACROBLOCK *const x = &cpi->mb; MACROBLOCKD *const xd = &x->e_mbd; // Only use 8x8 result for non HD videos. // int use_8x8 = (MIN(cpi->common.width, cpi->common.height) < 720) ? 1 : 0; int use_8x8 = 1; if (cm->frame_type && !cpi->is_src_frame_alt_ref && ((use_8x8 && bsize == BLOCK_16X16) || bsize == BLOCK_32X32 || bsize == BLOCK_64X64)) { int ref0 = 0, ref1 = 0, ref2 = 0, ref3 = 0; PICK_MODE_CONTEXT *block_context = NULL; if (bsize == BLOCK_16X16) { block_context = x->sb8x8_context[xd->sb_index][xd->mb_index]; } else if (bsize == BLOCK_32X32) { block_context = x->mb_context[xd->sb_index]; } else if (bsize == BLOCK_64X64) { block_context = x->sb32_context; } if (block_context) { ref0 = block_context[0].mic.mbmi.ref_frame[0]; ref1 = block_context[1].mic.mbmi.ref_frame[0];
1401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470
ref2 = block_context[2].mic.mbmi.ref_frame[0]; ref3 = block_context[3].mic.mbmi.ref_frame[0]; } // Currently, only consider 4 inter reference frames. if (ref0 && ref1 && ref2 && ref3) { int d01, d23, d02, d13; // Motion vectors for the four subblocks. int16_t mvr0 = block_context[0].mic.mbmi.mv[0].as_mv.row; int16_t mvc0 = block_context[0].mic.mbmi.mv[0].as_mv.col; int16_t mvr1 = block_context[1].mic.mbmi.mv[0].as_mv.row; int16_t mvc1 = block_context[1].mic.mbmi.mv[0].as_mv.col; int16_t mvr2 = block_context[2].mic.mbmi.mv[0].as_mv.row; int16_t mvc2 = block_context[2].mic.mbmi.mv[0].as_mv.col; int16_t mvr3 = block_context[3].mic.mbmi.mv[0].as_mv.row; int16_t mvc3 = block_context[3].mic.mbmi.mv[0].as_mv.col; // Adjust sign if ref is alt_ref. if (cm->ref_frame_sign_bias[ref0]) { mvr0 *= -1; mvc0 *= -1; } if (cm->ref_frame_sign_bias[ref1]) { mvr1 *= -1; mvc1 *= -1; } if (cm->ref_frame_sign_bias[ref2]) { mvr2 *= -1; mvc2 *= -1; } if (cm->ref_frame_sign_bias[ref3]) { mvr3 *= -1; mvc3 *= -1; } // Calculate mv distances. d01 = MAX(abs(mvr0 - mvr1), abs(mvc0 - mvc1)); d23 = MAX(abs(mvr2 - mvr3), abs(mvc2 - mvc3)); d02 = MAX(abs(mvr0 - mvr2), abs(mvc0 - mvc2)); d13 = MAX(abs(mvr1 - mvr3), abs(mvc1 - mvc3)); if (d01 < FAST_MOTION_MV_THRESH && d23 < FAST_MOTION_MV_THRESH && d02 < FAST_MOTION_MV_THRESH && d13 < FAST_MOTION_MV_THRESH) { // Set fast motion search level. x->fast_ms = 1; if (ref0 == ref1 && ref1 == ref2 && ref2 == ref3 && d01 < 2 && d23 < 2 && d02 < 2 && d13 < 2) { // Set fast motion search level. x->fast_ms = 2; if (!d01 && !d23 && !d02 && !d13) { x->fast_ms = 3; x->subblock_ref = ref0; } } } } } } 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) {
1471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540
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. static void rd_pick_partition(VP9_COMP *cpi, 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; MACROBLOCKD * const xd = &x->e_mbd; const int ms = num_8x8_blocks_wide_lookup[bsize] / 2; ENTROPY_CONTEXT l[16 * MAX_MB_PLANE], a[16 * MAX_MB_PLANE]; PARTITION_CONTEXT sl[8], sa[8]; TOKENEXTRA *tp_orig = *tp; int i, pl; BLOCK_SIZE subsize; int this_rate, sum_rate = 0, best_rate = INT_MAX; int64_t this_dist, sum_dist = 0, best_dist = INT64_MAX; int64_t sum_rd = 0; int do_split = bsize >= BLOCK_8X8; int do_rect = 1; // Override skipping rectangular partition operations for edge blocks const int force_horz_split = (mi_row + ms >= cm->mi_rows); const int force_vert_split = (mi_col + ms >= cm->mi_cols); int partition_none_allowed = !force_horz_split && !force_vert_split; int partition_horz_allowed = !force_vert_split && bsize >= BLOCK_8X8; int partition_vert_allowed = !force_horz_split && bsize >= BLOCK_8X8; int partition_split_done = 0; (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. if (xd->ab_index != 0) { *rate = 0; *dist = 0; return; } } assert(mi_height_log2(bsize) == mi_width_log2(bsize)); if (bsize == BLOCK_16X16) { set_offsets(cpi, 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; } save_context(cpi, mi_row, mi_col, a, l, sa, sl, bsize);