Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/media/libvpx/libvpx/vp8/encoder/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 179 kB image not shown  

Quelle  onyx_if.c   Sprache: C

 
/*
 *  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 "vpx_config.h"
#include "./vpx_scale_rtcd.h"
#include "./vpx_dsp_rtcd.h"
#include "./vp8_rtcd.h"
#include "bitstream.h"
#include "vp8/common/onyxc_int.h"
#include "vp8/common/blockd.h"
#include "onyx_int.h"
#include "vp8/common/systemdependent.h"
#include "vp8/common/vp8_skin_detection.h"
#include "vp8/encoder/quantize.h"
#include "vp8/common/alloccommon.h"
#include "mcomp.h"
#include "firstpass.h"
#include "vpx_dsp/psnr.h"
#include "vpx_scale/vpx_scale.h"
#include "vp8/common/extend.h"
#include "ratectrl.h"
#include "vp8/common/quant_common.h"
#include "segmentation.h"
#if CONFIG_POSTPROC
#include "vp8/common/postproc.h"
#endif
#include "vpx_mem/vpx_mem.h"
#include "vp8/common/reconintra.h"
#include "vp8/common/swapyv12buffer.h"
#include "vp8/common/threading.h"
#include "vpx_ports/system_state.h"
#include "vpx_ports/vpx_once.h"
#include "vpx_ports/vpx_timer.h"
#include "vpx_util/vpx_write_yuv_frame.h"
#if VPX_ARCH_ARM
#include "vpx_ports/arm.h"
#endif
#if CONFIG_MULTI_RES_ENCODING
#include "mr_dissim.h"
#endif
#include "encodeframe.h"
#if CONFIG_MULTITHREAD
#include "ethreading.h"
#endif
#include "picklpf.h"
#if !CONFIG_REALTIME_ONLY
#include "temporal_filter.h"
#endif

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

#if CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING
extern int vp8_update_coef_context(VP8_COMP *cpi);
#endif

extern unsigned int vp8_get_processor_freq(void);

int vp8_calc_ss_err(YV12_BUFFER_CONFIG *source, YV12_BUFFER_CONFIG *dest);

static void set_default_lf_deltas(VP8_COMP *cpi);

extern const int vp8_gf_interval_table[101];

#if CONFIG_INTERNAL_STATS
#include "math.h"
#include "vpx_dsp/ssim.h"
#endif

#ifdef OUTPUT_YUV_SRC
FILE *yuv_file;
#endif
#ifdef OUTPUT_YUV_DENOISED
FILE *yuv_denoised_file;
#endif
#ifdef OUTPUT_YUV_SKINMAP
static FILE *yuv_skinmap_file = NULL;
#endif

#if 0
FILE *framepsnr;
FILE *kf_list;
FILE *keyfile;
#endif

#if 0
extern int skip_true_count;
extern int skip_false_count;
#endif

#ifdef SPEEDSTATS
unsigned int frames_at_speed[16] = { 0, 0, 0, 0, 0, 0, 0, 0,
                                     0, 0, 0, 0, 0, 0, 0, 0 };
unsigned int tot_pm = 0;
unsigned int cnt_pm = 0;
unsigned int tot_ef = 0;
unsigned int cnt_ef = 0;
#endif

#ifdef MODE_STATS
extern unsigned __int64 Sectionbits[50];
extern int y_modes[5];
extern int uv_modes[4];
extern int b_modes[10];

extern int inter_y_modes[10];
extern int inter_uv_modes[4];
extern unsigned int inter_b_modes[15];
#endif

extern const int vp8_bits_per_mb[2][QINDEX_RANGE];

extern const int qrounding_factors[129];
extern const int qzbin_factors[129];
extern void vp8cx_init_quantizer(VP8_COMP *cpi);
extern const int vp8cx_base_skip_false_prob[128];

/* Tables relating active max Q to active min Q */
static const unsigned char kf_low_motion_minq[QINDEX_RANGE] = {
  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,  1,  1,
  1,  1,  1,  2,  2,  2,  2,  3,  3,  3,  3,  3,  3,  4,  4,  4,  5,  5,  5,
  5,  5,  6,  6,  6,  6,  7,  7,  8,  8,  8,  8,  9,  9,  10, 10, 10, 10, 11,
  11, 11, 11, 12, 12, 13, 13, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16,
  17, 17, 18, 18, 18, 18, 19, 20, 20, 21, 21, 22, 23, 23
};
static const unsigned char kf_high_motion_minq[QINDEX_RANGE] = {
  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,  1,  1,  1,
  1,  1,  2,  2,  2,  2,  3,  3,  3,  3,  3,  3,  3,  3,  4,  4,  4,  4,  5,
  5,  5,  5,  5,  5,  6,  6,  6,  6,  7,  7,  8,  8,  8,  8,  9,  9,  10, 10,
  10, 10, 11, 11, 11, 11, 12, 12, 13, 13, 13, 13, 14, 14, 15, 15, 15, 15, 16,
  16, 16, 16, 17, 17, 18, 18, 18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21,
  22, 22, 23, 23, 24, 25, 25, 26, 26, 27, 28, 28, 29, 30
};
static const unsigned char gf_low_motion_minq[QINDEX_RANGE] = {
  0,  0,  0,  0,  1,  1,  1,  1,  1,  1,  1,  1,  2,  2,  2,  2,  3,  3,  3,
  3,  4,  4,  4,  4,  5,  5,  5,  5,  6,  6,  6,  6,  7,  7,  7,  7,  8,  8,
  8,  8,  9,  9,  9,  9,  10, 10, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15,
  15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24,
  25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30, 30, 31, 31, 32, 32, 33, 33, 34,
  34, 35, 35, 36, 36, 37, 37, 38, 38, 39, 39, 40, 40, 41, 41, 42, 42, 43, 44,
  45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58
};
static const unsigned char gf_mid_motion_minq[QINDEX_RANGE] = {
  0,  0,  0,  0,  1,  1,  1,  1,  1,  1,  2,  2,  3,  3,  3,  4,  4,  4,  5,
  5,  5,  6,  6,  6,  7,  7,  7,  8,  8,  8,  9,  9,  9,  10, 10, 10, 10, 11,
  11, 11, 12, 12, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15, 16, 16, 17, 17, 18,
  18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27,
  28, 28, 29, 29, 30, 30, 31, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 37,
  37, 38, 39, 39, 40, 40, 41, 41, 42, 42, 43, 43, 44, 45, 46, 47, 48, 49, 50,
  51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64
};
static const unsigned char gf_high_motion_minq[QINDEX_RANGE] = {
  0,  0,  0,  0,  1,  1,  1,  1,  1,  2,  2,  2,  3,  3,  3,  4,  4,  4,  5,
  5,  5,  6,  6,  6,  7,  7,  7,  8,  8,  8,  9,  9,  9,  10, 10, 10, 11, 11,
  12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21,
  21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30, 30,
  31, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 37, 37, 38, 38, 39, 39, 40,
  40, 41, 41, 42, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
  57, 58, 59, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80
};
static const unsigned char inter_minq[QINDEX_RANGE] = {
  0,  0,  1,  1,  2,  3,  3,  4,  4,  5,  6,  6,  7,  8,  8,  9,  9,  10, 11,
  11, 12, 13, 13, 14, 15, 15, 16, 17, 17, 18, 19, 20, 20, 21, 22, 22, 23, 24,
  24, 25, 26, 27, 27, 28, 29, 30, 30, 31, 32, 33, 33, 34, 35, 36, 36, 37, 38,
  39, 39, 40, 41, 42, 42, 43, 44, 45, 46, 46, 47, 48, 49, 50, 50, 51, 52, 53,
  54, 55, 55, 56, 57, 58, 59, 60, 60, 61, 62, 63, 64, 65, 66, 67, 67, 68, 69,
  70, 71, 72, 73, 74, 75, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 86,
  87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100
};

#ifdef PACKET_TESTING
extern FILE *vpxlogc;
#endif

void vp8_save_layer_context(VP8_COMP *cpi) {
  LAYER_CONTEXT *lc = &cpi->layer_context[cpi->current_layer];

  /* Save layer dependent coding state */
  lc->target_bandwidth = cpi->target_bandwidth;
  lc->starting_buffer_level = cpi->oxcf.starting_buffer_level;
  lc->optimal_buffer_level = cpi->oxcf.optimal_buffer_level;
  lc->maximum_buffer_size = cpi->oxcf.maximum_buffer_size;
  lc->starting_buffer_level_in_ms = cpi->oxcf.starting_buffer_level_in_ms;
  lc->optimal_buffer_level_in_ms = cpi->oxcf.optimal_buffer_level_in_ms;
  lc->maximum_buffer_size_in_ms = cpi->oxcf.maximum_buffer_size_in_ms;
  lc->buffer_level = cpi->buffer_level;
  lc->bits_off_target = cpi->bits_off_target;
  lc->total_actual_bits = cpi->total_actual_bits;
  lc->worst_quality = cpi->worst_quality;
  lc->active_worst_quality = cpi->active_worst_quality;
  lc->best_quality = cpi->best_quality;
  lc->active_best_quality = cpi->active_best_quality;
  lc->ni_av_qi = cpi->ni_av_qi;
  lc->ni_tot_qi = cpi->ni_tot_qi;
  lc->ni_frames = cpi->ni_frames;
  lc->avg_frame_qindex = cpi->avg_frame_qindex;
  lc->rate_correction_factor = cpi->rate_correction_factor;
  lc->key_frame_rate_correction_factor = cpi->key_frame_rate_correction_factor;
  lc->gf_rate_correction_factor = cpi->gf_rate_correction_factor;
  lc->zbin_over_quant = cpi->mb.zbin_over_quant;
  lc->inter_frame_target = cpi->inter_frame_target;
  lc->total_byte_count = cpi->total_byte_count;
  lc->filter_level = cpi->common.filter_level;
  lc->frames_since_last_drop_overshoot = cpi->frames_since_last_drop_overshoot;
  lc->force_maxqp = cpi->force_maxqp;
  lc->last_frame_percent_intra = cpi->last_frame_percent_intra;
  lc->last_q[0] = cpi->last_q[0];
  lc->last_q[1] = cpi->last_q[1];

  memcpy(lc->count_mb_ref_frame_usage, cpi->mb.count_mb_ref_frame_usage,
         sizeof(cpi->mb.count_mb_ref_frame_usage));
}

void vp8_restore_layer_context(VP8_COMP *cpi, const int layer) {
  LAYER_CONTEXT *lc = &cpi->layer_context[layer];

  /* Restore layer dependent coding state */
  cpi->current_layer = layer;
  cpi->target_bandwidth = lc->target_bandwidth;
  cpi->oxcf.target_bandwidth = lc->target_bandwidth;
  cpi->oxcf.starting_buffer_level = lc->starting_buffer_level;
  cpi->oxcf.optimal_buffer_level = lc->optimal_buffer_level;
  cpi->oxcf.maximum_buffer_size = lc->maximum_buffer_size;
  cpi->oxcf.starting_buffer_level_in_ms = lc->starting_buffer_level_in_ms;
  cpi->oxcf.optimal_buffer_level_in_ms = lc->optimal_buffer_level_in_ms;
  cpi->oxcf.maximum_buffer_size_in_ms = lc->maximum_buffer_size_in_ms;
  cpi->buffer_level = lc->buffer_level;
  cpi->bits_off_target = lc->bits_off_target;
  cpi->total_actual_bits = lc->total_actual_bits;
  cpi->active_worst_quality = lc->active_worst_quality;
  cpi->active_best_quality = lc->active_best_quality;
  cpi->ni_av_qi = lc->ni_av_qi;
  cpi->ni_tot_qi = lc->ni_tot_qi;
  cpi->ni_frames = lc->ni_frames;
  cpi->avg_frame_qindex = lc->avg_frame_qindex;
  cpi->rate_correction_factor = lc->rate_correction_factor;
  cpi->key_frame_rate_correction_factor = lc->key_frame_rate_correction_factor;
  cpi->gf_rate_correction_factor = lc->gf_rate_correction_factor;
  cpi->mb.zbin_over_quant = lc->zbin_over_quant;
  cpi->inter_frame_target = lc->inter_frame_target;
  cpi->total_byte_count = lc->total_byte_count;
  cpi->common.filter_level = lc->filter_level;
  cpi->frames_since_last_drop_overshoot = lc->frames_since_last_drop_overshoot;
  cpi->force_maxqp = lc->force_maxqp;
  cpi->last_frame_percent_intra = lc->last_frame_percent_intra;
  cpi->last_q[0] = lc->last_q[0];
  cpi->last_q[1] = lc->last_q[1];

  memcpy(cpi->mb.count_mb_ref_frame_usage, lc->count_mb_ref_frame_usage,
         sizeof(cpi->mb.count_mb_ref_frame_usage));
}

static int rescale(int val, int num, int denom) {
  int64_t llnum = num;
  int64_t llden = denom;
  int64_t llval = val;

  int64_t result = (llval * llnum / llden);
  if (result <= INT_MAX)
    return (int)result;
  else
    return INT_MAX;
}

void vp8_init_temporal_layer_context(VP8_COMP *cpi, const VP8_CONFIG *oxcf,
                                     const int layer,
                                     double prev_layer_framerate) {
  LAYER_CONTEXT *lc = &cpi->layer_context[layer];

  lc->framerate = cpi->output_framerate / cpi->oxcf.rate_decimator[layer];
  if (cpi->oxcf.target_bitrate[layer] > INT_MAX / 1000)
    lc->target_bandwidth = INT_MAX;
  else
    lc->target_bandwidth = cpi->oxcf.target_bitrate[layer] * 1000;

  lc->starting_buffer_level_in_ms = oxcf->starting_buffer_level;
  lc->optimal_buffer_level_in_ms = oxcf->optimal_buffer_level;
  lc->maximum_buffer_size_in_ms = oxcf->maximum_buffer_size;

  lc->starting_buffer_level =
      rescale((int)(oxcf->starting_buffer_level), lc->target_bandwidth, 1000);

  if (oxcf->optimal_buffer_level == 0) {
    lc->optimal_buffer_level = lc->target_bandwidth / 8;
  } else {
    lc->optimal_buffer_level =
        rescale((int)(oxcf->optimal_buffer_level), lc->target_bandwidth, 1000);
  }

  if (oxcf->maximum_buffer_size == 0) {
    lc->maximum_buffer_size = lc->target_bandwidth / 8;
  } else {
    lc->maximum_buffer_size =
        rescale((int)(oxcf->maximum_buffer_size), lc->target_bandwidth, 1000);
  }

  /* Work out the average size of a frame within this layer */
  if (layer > 0) {
    lc->avg_frame_size_for_layer =
        (int)round((cpi->oxcf.target_bitrate[layer] -
                    cpi->oxcf.target_bitrate[layer - 1]) *
                   1000 / (lc->framerate - prev_layer_framerate));
  }

  lc->active_worst_quality = cpi->oxcf.worst_allowed_q;
  lc->active_best_quality = cpi->oxcf.best_allowed_q;
  lc->avg_frame_qindex = cpi->oxcf.worst_allowed_q;

  lc->buffer_level = lc->starting_buffer_level;
  lc->bits_off_target = lc->starting_buffer_level;

  lc->total_actual_bits = 0;
  lc->ni_av_qi = 0;
  lc->ni_tot_qi = 0;
  lc->ni_frames = 0;
  lc->rate_correction_factor = 1.0;
  lc->key_frame_rate_correction_factor = 1.0;
  lc->gf_rate_correction_factor = 1.0;
  lc->inter_frame_target = 0;
}

// Upon a run-time change in temporal layers, reset the layer context parameters
// for any "new" layers. For "existing" layers, let them inherit the parameters
// from the previous layer state (at the same layer #). In future we may want
// to better map the previous layer state(s) to the "new" ones.
void vp8_reset_temporal_layer_change(VP8_COMP *cpi, const VP8_CONFIG *oxcf,
                                     const int prev_num_layers) {
  int i;
  double prev_layer_framerate = 0;
  const int curr_num_layers = cpi->oxcf.number_of_layers;
  // If the previous state was 1 layer, get current layer context from cpi.
  // We need this to set the layer context for the new layers below.
  if (prev_num_layers == 1) {
    cpi->current_layer = 0;
    vp8_save_layer_context(cpi);
  }
  for (i = 0; i < curr_num_layers; ++i) {
    LAYER_CONTEXT *lc = &cpi->layer_context[i];
    if (i >= prev_num_layers) {
      vp8_init_temporal_layer_context(cpi, oxcf, i, prev_layer_framerate);
    }
    // The initial buffer levels are set based on their starting levels.
    // We could set the buffer levels based on the previous state (normalized
    // properly by the layer bandwidths) but we would need to keep track of
    // the previous set of layer bandwidths (i.e., target_bitrate[i])
    // before the layer change. For now, reset to the starting levels.
    lc->buffer_level =
        cpi->oxcf.starting_buffer_level_in_ms * cpi->oxcf.target_bitrate[i];
    lc->bits_off_target = lc->buffer_level;
    // TDOD(marpan): Should we set the rate_correction_factor and
    // active_worst/best_quality to values derived from the previous layer
    // state (to smooth-out quality dips/rate fluctuation at transition)?

    // We need to treat the 1 layer case separately: oxcf.target_bitrate[i]
    // is not set for 1 layer, and the vp8_restore_layer_context/save_context()
    // are not called in the encoding loop, so we need to call it here to
    // pass the layer context state to |cpi|.
    if (curr_num_layers == 1) {
      lc->target_bandwidth = cpi->oxcf.target_bandwidth;
      lc->buffer_level =
          cpi->oxcf.starting_buffer_level_in_ms * lc->target_bandwidth / 1000;
      lc->bits_off_target = lc->buffer_level;
      vp8_restore_layer_context(cpi, 0);
    }
    prev_layer_framerate = cpi->output_framerate / cpi->oxcf.rate_decimator[i];
  }
}

static void setup_features(VP8_COMP *cpi) {
  // If segmentation enabled set the update flags
  if (cpi->mb.e_mbd.segmentation_enabled) {
    cpi->mb.e_mbd.update_mb_segmentation_map = 1;
    cpi->mb.e_mbd.update_mb_segmentation_data = 1;
  } else {
    cpi->mb.e_mbd.update_mb_segmentation_map = 0;
    cpi->mb.e_mbd.update_mb_segmentation_data = 0;
  }

  cpi->mb.e_mbd.mode_ref_lf_delta_enabled = 0;
  cpi->mb.e_mbd.mode_ref_lf_delta_update = 0;
  memset(cpi->mb.e_mbd.ref_lf_deltas, 0, sizeof(cpi->mb.e_mbd.ref_lf_deltas));
  memset(cpi->mb.e_mbd.mode_lf_deltas, 0, sizeof(cpi->mb.e_mbd.mode_lf_deltas));
  memset(cpi->mb.e_mbd.last_ref_lf_deltas, 0,
         sizeof(cpi->mb.e_mbd.ref_lf_deltas));
  memset(cpi->mb.e_mbd.last_mode_lf_deltas, 0,
         sizeof(cpi->mb.e_mbd.mode_lf_deltas));

  set_default_lf_deltas(cpi);
}

static void dealloc_raw_frame_buffers(VP8_COMP *cpi);

static void initialize_enc(void) {
  vpx_dsp_rtcd();
  vp8_init_intra_predictors();
}

void vp8_initialize_enc(void) { once(initialize_enc); }

static void dealloc_compressor_data(VP8_COMP *cpi) {
  vpx_free(cpi->tplist);
  cpi->tplist = NULL;

  /* Delete last frame MV storage buffers */
  vpx_free(cpi->lfmv);
  cpi->lfmv = 0;

  vpx_free(cpi->lf_ref_frame_sign_bias);
  cpi->lf_ref_frame_sign_bias = 0;

  vpx_free(cpi->lf_ref_frame);
  cpi->lf_ref_frame = 0;

  /* Delete sementation map */
  vpx_free(cpi->segmentation_map);
  cpi->segmentation_map = 0;

  vpx_free(cpi->active_map);
  cpi->active_map = 0;

  vp8_de_alloc_frame_buffers(&cpi->common);

  vp8_yv12_de_alloc_frame_buffer(&cpi->pick_lf_lvl_frame);
  vp8_yv12_de_alloc_frame_buffer(&cpi->scaled_source);
  dealloc_raw_frame_buffers(cpi);

  vpx_free(cpi->tok);
  cpi->tok = 0;

  /* Structure used to monitor GF usage */
  vpx_free(cpi->gf_active_flags);
  cpi->gf_active_flags = 0;

  /* Activity mask based per mb zbin adjustments */
  vpx_free(cpi->mb_activity_map);
  cpi->mb_activity_map = 0;

  vpx_free(cpi->mb.pip);
  cpi->mb.pip = 0;
}

static void enable_segmentation(VP8_COMP *cpi) {
  /* Set the appropriate feature bit */
  cpi->mb.e_mbd.segmentation_enabled = 1;
  cpi->mb.e_mbd.update_mb_segmentation_map = 1;
  cpi->mb.e_mbd.update_mb_segmentation_data = 1;
}
static void disable_segmentation(VP8_COMP *cpi) {
  /* Clear the appropriate feature bit */
  cpi->mb.e_mbd.segmentation_enabled = 0;
}

/* Valid values for a segment are 0 to 3
 * Segmentation map is arrange as [Rows][Columns]
 */

static void set_segmentation_map(VP8_COMP *cpi,
                                 unsigned char *segmentation_map) {
  /* Copy in the new segmentation map */
  memcpy(cpi->segmentation_map, segmentation_map,
         (cpi->common.mb_rows * cpi->common.mb_cols));

  /* Signal that the map should be updated. */
  cpi->mb.e_mbd.update_mb_segmentation_map = 1;
  cpi->mb.e_mbd.update_mb_segmentation_data = 1;
}

/* The values given for each segment can be either deltas (from the default
 * value chosen for the frame) or absolute values.
 *
 * Valid range for abs values is:
 *    (0-127 for MB_LVL_ALT_Q), (0-63 for SEGMENT_ALT_LF)
 * Valid range for delta values are:
 *    (+/-127 for MB_LVL_ALT_Q), (+/-63 for SEGMENT_ALT_LF)
 *
 * abs_delta = SEGMENT_DELTADATA (deltas)
 * abs_delta = SEGMENT_ABSDATA (use the absolute values given).
 *
 */

static void set_segment_data(VP8_COMP *cpi, signed char *feature_data,
                             unsigned char abs_delta) {
  cpi->mb.e_mbd.mb_segment_abs_delta = abs_delta;
  memcpy(cpi->segment_feature_data, feature_data,
         sizeof(cpi->segment_feature_data));
}

/* A simple function to cyclically refresh the background at a lower Q */
static void cyclic_background_refresh(VP8_COMP *cpi, int Q, int lf_adjustment) {
  unsigned char *seg_map = cpi->segmentation_map;
  signed char feature_data[MB_LVL_MAX][MAX_MB_SEGMENTS];
  int i;
  int block_count = cpi->cyclic_refresh_mode_max_mbs_perframe;
  int mbs_in_frame = cpi->common.mb_rows * cpi->common.mb_cols;

  cpi->cyclic_refresh_q = Q / 2;

  if (cpi->oxcf.screen_content_mode) {
    // Modify quality ramp-up based on Q. Above some Q level, increase the
    // number of blocks to be refreshed, and reduce it below the thredhold.
    // Turn-off under certain conditions (i.e., away from key frame, and if
    // we are at good quality (low Q) and most of the blocks were
    // skipped-encoded
    // in previous frame.
    int qp_thresh = (cpi->oxcf.screen_content_mode == 2) ? 80 : 100;
    if (Q >= qp_thresh) {
      cpi->cyclic_refresh_mode_max_mbs_perframe =
          (cpi->common.mb_rows * cpi->common.mb_cols) / 10;
    } else if (cpi->frames_since_key > 250 && Q < 20 &&
               cpi->mb.skip_true_count > (int)(0.95 * mbs_in_frame)) {
      cpi->cyclic_refresh_mode_max_mbs_perframe = 0;
    } else {
      cpi->cyclic_refresh_mode_max_mbs_perframe =
          (cpi->common.mb_rows * cpi->common.mb_cols) / 20;
    }
    block_count = cpi->cyclic_refresh_mode_max_mbs_perframe;
  }

  // Set every macroblock to be eligible for update.
  // For key frame this will reset seg map to 0.
  memset(cpi->segmentation_map, 0, mbs_in_frame);

  if (cpi->common.frame_type != KEY_FRAME && block_count > 0) {
    /* Cycle through the macro_block rows */
    /* MB loop to set local segmentation map */
    i = cpi->cyclic_refresh_mode_index;
    assert(i < mbs_in_frame);
    do {
      /* If the MB is as a candidate for clean up then mark it for
       * possible boost/refresh (segment 1) The segment id may get
       * reset to 0 later if the MB gets coded anything other than
       * last frame 0,0 as only (last frame 0,0) MBs are eligable for
       * refresh : that is to say Mbs likely to be background blocks.
       */

      if (cpi->cyclic_refresh_map[i] == 0) {
        seg_map[i] = 1;
        block_count--;
      } else if (cpi->cyclic_refresh_map[i] < 0) {
        cpi->cyclic_refresh_map[i]++;
      }

      i++;
      if (i == mbs_in_frame) i = 0;

    } while (block_count && i != cpi->cyclic_refresh_mode_index);

    cpi->cyclic_refresh_mode_index = i;

#if CONFIG_TEMPORAL_DENOISING
    if (cpi->oxcf.noise_sensitivity > 0) {
      if (cpi->denoiser.denoiser_mode == kDenoiserOnYUVAggressive &&
          Q < (int)cpi->denoiser.denoise_pars.qp_thresh &&
          (cpi->frames_since_key >
           2 * cpi->denoiser.denoise_pars.consec_zerolast)) {
        // Under aggressive denoising, use segmentation to turn off loop
        // filter below some qp thresh. The filter is reduced for all
        // blocks that have been encoded as ZEROMV LAST x frames in a row,
        // where x is set by cpi->denoiser.denoise_pars.consec_zerolast.
        // This is to avoid "dot" artifacts that can occur from repeated
        // loop filtering on noisy input source.
        cpi->cyclic_refresh_q = Q;
        // lf_adjustment = -MAX_LOOP_FILTER;
        lf_adjustment = -40;
        for (i = 0; i < mbs_in_frame; ++i) {
          seg_map[i] = (cpi->consec_zero_last[i] >
                        cpi->denoiser.denoise_pars.consec_zerolast)
                           ? 1
                           : 0;
        }
      }
    }
#endif
  }

  /* Activate segmentation. */
  cpi->mb.e_mbd.update_mb_segmentation_map = 1;
  cpi->mb.e_mbd.update_mb_segmentation_data = 1;
  enable_segmentation(cpi);

  /* Set up the quant segment data */
  feature_data[MB_LVL_ALT_Q][0] = 0;
  feature_data[MB_LVL_ALT_Q][1] = (cpi->cyclic_refresh_q - Q);
  feature_data[MB_LVL_ALT_Q][2] = 0;
  feature_data[MB_LVL_ALT_Q][3] = 0;

  /* Set up the loop segment data */
  feature_data[MB_LVL_ALT_LF][0] = 0;
  feature_data[MB_LVL_ALT_LF][1] = lf_adjustment;
  feature_data[MB_LVL_ALT_LF][2] = 0;
  feature_data[MB_LVL_ALT_LF][3] = 0;

  /* Initialise the feature data structure */
  set_segment_data(cpi, &feature_data[0][0], SEGMENT_DELTADATA);
}

static void compute_skin_map(VP8_COMP *cpi) {
  int mb_row, mb_col, num_bl;
  VP8_COMMON *cm = &cpi->common;
  const uint8_t *src_y = cpi->Source->y_buffer;
  const uint8_t *src_u = cpi->Source->u_buffer;
  const uint8_t *src_v = cpi->Source->v_buffer;
  const int src_ystride = cpi->Source->y_stride;
  const int src_uvstride = cpi->Source->uv_stride;

  const SKIN_DETECTION_BLOCK_SIZE bsize =
      (cm->Width * cm->Height <= 352 * 288) ? SKIN_8X8 : SKIN_16X16;

  for (mb_row = 0; mb_row < cm->mb_rows; mb_row++) {
    num_bl = 0;
    for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) {
      const int bl_index = mb_row * cm->mb_cols + mb_col;
      cpi->skin_map[bl_index] =
          vp8_compute_skin_block(src_y, src_u, src_v, src_ystride, src_uvstride,
                                 bsize, cpi->consec_zero_last[bl_index], 0);
      num_bl++;
      src_y += 16;
      src_u += 8;
      src_v += 8;
    }
    src_y += (src_ystride << 4) - (num_bl << 4);
    src_u += (src_uvstride << 3) - (num_bl << 3);
    src_v += (src_uvstride << 3) - (num_bl << 3);
  }

  // Remove isolated skin blocks (none of its neighbors are skin) and isolated
  // non-skin blocks (all of its neighbors are skin). Skip the boundary.
  for (mb_row = 1; mb_row < cm->mb_rows - 1; mb_row++) {
    for (mb_col = 1; mb_col < cm->mb_cols - 1; mb_col++) {
      const int bl_index = mb_row * cm->mb_cols + mb_col;
      int num_neighbor = 0;
      int mi, mj;
      int non_skin_threshold = 8;

      for (mi = -1; mi <= 1; mi += 1) {
        for (mj = -1; mj <= 1; mj += 1) {
          int bl_neighbor_index = (mb_row + mi) * cm->mb_cols + mb_col + mj;
          if (cpi->skin_map[bl_neighbor_index]) num_neighbor++;
        }
      }

      if (cpi->skin_map[bl_index] && num_neighbor < 2)
        cpi->skin_map[bl_index] = 0;
      if (!cpi->skin_map[bl_index] && num_neighbor == non_skin_threshold)
        cpi->skin_map[bl_index] = 1;
    }
  }
}

static void set_default_lf_deltas(VP8_COMP *cpi) {
  cpi->mb.e_mbd.mode_ref_lf_delta_enabled = 1;
  cpi->mb.e_mbd.mode_ref_lf_delta_update = 1;

  memset(cpi->mb.e_mbd.ref_lf_deltas, 0, sizeof(cpi->mb.e_mbd.ref_lf_deltas));
  memset(cpi->mb.e_mbd.mode_lf_deltas, 0, sizeof(cpi->mb.e_mbd.mode_lf_deltas));

  /* Test of ref frame deltas */
  cpi->mb.e_mbd.ref_lf_deltas[INTRA_FRAME] = 2;
  cpi->mb.e_mbd.ref_lf_deltas[LAST_FRAME] = 0;
  cpi->mb.e_mbd.ref_lf_deltas[GOLDEN_FRAME] = -2;
  cpi->mb.e_mbd.ref_lf_deltas[ALTREF_FRAME] = -2;

  cpi->mb.e_mbd.mode_lf_deltas[0] = 4; /* BPRED */

  if (cpi->oxcf.Mode == MODE_REALTIME) {
    cpi->mb.e_mbd.mode_lf_deltas[1] = -12; /* Zero */
  } else {
    cpi->mb.e_mbd.mode_lf_deltas[1] = -2; /* Zero */
  }

  cpi->mb.e_mbd.mode_lf_deltas[2] = 2; /* New mv */
  cpi->mb.e_mbd.mode_lf_deltas[3] = 4; /* Split mv */
}

/* Convenience macros for mapping speed and mode into a continuous
 * range
 */

#define GOOD(x) ((x) + 1)
#define RT(x) ((x) + 7)

static int speed_map(int speed, const int *map) {
  int res;

  do {
    res = *map++;
  } while (speed >= *map++);
  return res;
}

static const int thresh_mult_map_znn[] = {
  /* map common to zero, nearest, and near */
  0, GOOD(2), 1500, GOOD(3), 2000, RT(0), 1000, RT(2), 2000, INT_MAX
};

static const int thresh_mult_map_vhpred[] = { 1000, GOOD(2), 1500,    GOOD(3),
                                              2000, RT(0),   1000,    RT(1),
                                              2000, RT(7),   INT_MAX, INT_MAX };

static const int thresh_mult_map_bpred[] = { 2000,    GOOD(0), 2500, GOOD(2),
                                             5000,    GOOD(3), 7500, RT(0),
                                             2500,    RT(1),   5000, RT(6),
                                             INT_MAX, INT_MAX };

static const int thresh_mult_map_tm[] = { 1000,    GOOD(2), 1500, GOOD(3),
                                          2000,    RT(0),   0,    RT(1),
                                          1000,    RT(2),   2000, RT(7),
                                          INT_MAX, INT_MAX };

static const int thresh_mult_map_new1[] = { 1000,  GOOD(2), 2000,
                                            RT(0), 2000,    INT_MAX };

static const int thresh_mult_map_new2[] = { 1000, GOOD(2), 2000, GOOD(3),
                                            2500, GOOD(5), 4000, RT(0),
                                            2000, RT(2),   2500, RT(5),
                                            4000, INT_MAX };

static const int thresh_mult_map_split1[] = {
  2500,  GOOD(0), 1700,  GOOD(2), 10000, GOOD(3), 25000, GOOD(4), INT_MAX,
  RT(0), 5000,    RT(1), 10000,   RT(2), 25000,   RT(3), INT_MAX, INT_MAX
};

static const int thresh_mult_map_split2[] = {
  5000,  GOOD(0), 4500,  GOOD(2), 20000, GOOD(3), 50000, GOOD(4), INT_MAX,
  RT(0), 10000,   RT(1), 20000,   RT(2), 50000,   RT(3), INT_MAX, INT_MAX
};

static const int mode_check_freq_map_zn2[] = {
  /* {zero,nearest}{2,3} */
  0, RT(10), 1 << 1, RT(11), 1 << 2, RT(12), 1 << 3, INT_MAX
};

static const int mode_check_freq_map_vhbpred[] = { 0, GOOD(5), 2, RT(0),
                                                   0, RT(3),   2, RT(5),
                                                   4, INT_MAX };

static const int mode_check_freq_map_near2[] = {
  0,      GOOD(5), 2,      RT(0),  0,      RT(3),  2,
  RT(10), 1 << 2,  RT(11), 1 << 3, RT(12), 1 << 4, INT_MAX
};

static const int mode_check_freq_map_new1[] = {
  0, RT(10), 1 << 1, RT(11), 1 << 2, RT(12), 1 << 3, INT_MAX
};

static const int mode_check_freq_map_new2[] = { 0,      GOOD(5), 4,      RT(0),
                                                0,      RT(3),   4,      RT(10),
                                                1 << 3, RT(11),  1 << 4, RT(12),
                                                1 << 5, INT_MAX };

static const int mode_check_freq_map_split1[] = { 0, GOOD(2), 2, GOOD(3),
                                                  7, RT(1),   2, RT(2),
                                                  7, INT_MAX };

static const int mode_check_freq_map_split2[] = { 0, GOOD(1), 2,  GOOD(2),
                                                  4, GOOD(3), 15, RT(1),
                                                  4, RT(2),   15, INT_MAX };

void vp8_set_speed_features(VP8_COMP *cpi) {
  SPEED_FEATURES *sf = &cpi->sf;
  int Mode = cpi->compressor_speed;
  int Speed = cpi->Speed;
  int Speed2;
  int i;
  VP8_COMMON *cm = &cpi->common;
  int last_improved_quant = sf->improved_quant;
  int ref_frames;

  /* Initialise default mode frequency sampling variables */
  for (i = 0; i < MAX_MODES; ++i) {
    cpi->mode_check_freq[i] = 0;
  }

  cpi->mb.mbs_tested_so_far = 0;
  cpi->mb.mbs_zero_last_dot_suppress = 0;

  /* best quality defaults */
  sf->RD = 1;
  sf->search_method = NSTEP;
  sf->improved_quant = 1;
  sf->improved_dct = 1;
  sf->auto_filter = 1;
  sf->recode_loop = 1;
  sf->quarter_pixel_search = 1;
  sf->half_pixel_search = 1;
  sf->iterative_sub_pixel = 1;
  sf->optimize_coefficients = 1;
  sf->use_fastquant_for_pick = 0;
  sf->no_skip_block4x4_search = 1;

  sf->first_step = 0;
  sf->max_step_search_steps = MAX_MVSEARCH_STEPS;
  sf->improved_mv_pred = 1;

  /* default thresholds to 0 */
  for (i = 0; i < MAX_MODES; ++i) sf->thresh_mult[i] = 0;

  /* Count enabled references */
  ref_frames = 1;
  if (cpi->ref_frame_flags & VP8_LAST_FRAME) ref_frames++;
  if (cpi->ref_frame_flags & VP8_GOLD_FRAME) ref_frames++;
  if (cpi->ref_frame_flags & VP8_ALTR_FRAME) ref_frames++;

  /* Convert speed to continuous range, with clamping */
  if (Mode == 0) {
    Speed = 0;
  } else if (Mode == 2) {
    Speed = RT(Speed);
  } else {
    if (Speed > 5) Speed = 5;
    Speed = GOOD(Speed);
  }

  sf->thresh_mult[THR_ZERO1] = sf->thresh_mult[THR_NEAREST1] =
      sf->thresh_mult[THR_NEAR1] = sf->thresh_mult[THR_DC] = 0; /* always */

  sf->thresh_mult[THR_ZERO2] = sf->thresh_mult[THR_ZERO3] =
      sf->thresh_mult[THR_NEAREST2] = sf->thresh_mult[THR_NEAREST3] =
          sf->thresh_mult[THR_NEAR2] = sf->thresh_mult[THR_NEAR3] =
              speed_map(Speed, thresh_mult_map_znn);

  sf->thresh_mult[THR_V_PRED] = sf->thresh_mult[THR_H_PRED] =
      speed_map(Speed, thresh_mult_map_vhpred);
  sf->thresh_mult[THR_B_PRED] = speed_map(Speed, thresh_mult_map_bpred);
  sf->thresh_mult[THR_TM] = speed_map(Speed, thresh_mult_map_tm);
  sf->thresh_mult[THR_NEW1] = speed_map(Speed, thresh_mult_map_new1);
  sf->thresh_mult[THR_NEW2] = sf->thresh_mult[THR_NEW3] =
      speed_map(Speed, thresh_mult_map_new2);
  sf->thresh_mult[THR_SPLIT1] = speed_map(Speed, thresh_mult_map_split1);
  sf->thresh_mult[THR_SPLIT2] = sf->thresh_mult[THR_SPLIT3] =
      speed_map(Speed, thresh_mult_map_split2);

  // Special case for temporal layers.
  // Reduce the thresholds for zero/nearest/near for GOLDEN, if GOLDEN is
  // used as second reference. We don't modify thresholds for ALTREF case
  // since ALTREF is usually used as long-term reference in temporal layers.
  if ((cpi->Speed <= 6) && (cpi->oxcf.number_of_layers > 1) &&
      (cpi->ref_frame_flags & VP8_LAST_FRAME) &&
      (cpi->ref_frame_flags & VP8_GOLD_FRAME)) {
    if (cpi->closest_reference_frame == GOLDEN_FRAME) {
      sf->thresh_mult[THR_ZERO2] = sf->thresh_mult[THR_ZERO2] >> 3;
      sf->thresh_mult[THR_NEAREST2] = sf->thresh_mult[THR_NEAREST2] >> 3;
      sf->thresh_mult[THR_NEAR2] = sf->thresh_mult[THR_NEAR2] >> 3;
    } else {
      sf->thresh_mult[THR_ZERO2] = sf->thresh_mult[THR_ZERO2] >> 1;
      sf->thresh_mult[THR_NEAREST2] = sf->thresh_mult[THR_NEAREST2] >> 1;
      sf->thresh_mult[THR_NEAR2] = sf->thresh_mult[THR_NEAR2] >> 1;
    }
  }

  cpi->mode_check_freq[THR_ZERO1] = cpi->mode_check_freq[THR_NEAREST1] =
      cpi->mode_check_freq[THR_NEAR1] = cpi->mode_check_freq[THR_TM] =
          cpi->mode_check_freq[THR_DC] = 0; /* always */

  cpi->mode_check_freq[THR_ZERO2] = cpi->mode_check_freq[THR_ZERO3] =
      cpi->mode_check_freq[THR_NEAREST2] = cpi->mode_check_freq[THR_NEAREST3] =
          speed_map(Speed, mode_check_freq_map_zn2);

  cpi->mode_check_freq[THR_NEAR2] = cpi->mode_check_freq[THR_NEAR3] =
      speed_map(Speed, mode_check_freq_map_near2);

  cpi->mode_check_freq[THR_V_PRED] = cpi->mode_check_freq[THR_H_PRED] =
      cpi->mode_check_freq[THR_B_PRED] =
          speed_map(Speed, mode_check_freq_map_vhbpred);

  // For real-time mode at speed 10 keep the mode_check_freq threshold
  // for NEW1 similar to that of speed 9.
  Speed2 = Speed;
  if (cpi->Speed == 10 && Mode == 2) Speed2 = RT(9);
  cpi->mode_check_freq[THR_NEW1] = speed_map(Speed2, mode_check_freq_map_new1);

  cpi->mode_check_freq[THR_NEW2] = cpi->mode_check_freq[THR_NEW3] =
      speed_map(Speed, mode_check_freq_map_new2);

  cpi->mode_check_freq[THR_SPLIT1] =
      speed_map(Speed, mode_check_freq_map_split1);
  cpi->mode_check_freq[THR_SPLIT2] = cpi->mode_check_freq[THR_SPLIT3] =
      speed_map(Speed, mode_check_freq_map_split2);
  Speed = cpi->Speed;
  switch (Mode) {
#if !CONFIG_REALTIME_ONLY
    case 0: /* best quality mode */
      sf->first_step = 0;
      sf->max_step_search_steps = MAX_MVSEARCH_STEPS;
      break;
    case 1:
    case 3:
      if (Speed > 0) {
        /* Disable coefficient optimization above speed 0 */
        sf->optimize_coefficients = 0;
        sf->use_fastquant_for_pick = 1;
        sf->no_skip_block4x4_search = 0;

        sf->first_step = 1;
      }

      if (Speed > 2) {
        sf->improved_quant = 0;
        sf->improved_dct = 0;

        /* Only do recode loop on key frames, golden frames and
         * alt ref frames
         */

        sf->recode_loop = 2;
      }

      if (Speed > 3) {
        sf->auto_filter = 1;
        sf->recode_loop = 0; /* recode loop off */
        sf->RD = 0;          /* Turn rd off */
      }

      if (Speed > 4) {
        sf->auto_filter = 0; /* Faster selection of loop filter */
      }

      break;
#endif
    case 2:
      sf->optimize_coefficients = 0;
      sf->recode_loop = 0;
      sf->auto_filter = 1;
      sf->iterative_sub_pixel = 1;
      sf->search_method = NSTEP;

      if (Speed > 0) {
        sf->improved_quant = 0;
        sf->improved_dct = 0;

        sf->use_fastquant_for_pick = 1;
        sf->no_skip_block4x4_search = 0;
        sf->first_step = 1;
      }

      if (Speed > 2) sf->auto_filter = 0; /* Faster selection of loop filter */

      if (Speed > 3) {
        sf->RD = 0;
        sf->auto_filter = 1;
      }

      if (Speed > 4) {
        sf->auto_filter = 0; /* Faster selection of loop filter */
        sf->search_method = HEX;
        sf->iterative_sub_pixel = 0;
      }

      if (Speed > 6) {
        unsigned int sum = 0;
        unsigned int total_mbs = cm->MBs;
        int thresh;
        unsigned int total_skip;

        int min = 2000;

        if (cpi->oxcf.encode_breakout > 2000) min = cpi->oxcf.encode_breakout;

        min >>= 7;

        for (i = 0; i < min; ++i) {
          sum += cpi->mb.error_bins[i];
        }

        total_skip = sum;
        sum = 0;

        /* i starts from 2 to make sure thresh started from 2048 */
        for (; i < 1024; ++i) {
          sum += cpi->mb.error_bins[i];

          if (10 * sum >=
              (unsigned int)(cpi->Speed - 6) * (total_mbs - total_skip)) {
            break;
          }
        }

        i--;
        thresh = (i << 7);

        if (thresh < 2000) thresh = 2000;

        if (ref_frames > 1) {
          sf->thresh_mult[THR_NEW1] = thresh;
          sf->thresh_mult[THR_NEAREST1] = thresh >> 1;
          sf->thresh_mult[THR_NEAR1] = thresh >> 1;
        }

        if (ref_frames > 2) {
          sf->thresh_mult[THR_NEW2] = thresh << 1;
          sf->thresh_mult[THR_NEAREST2] = thresh;
          sf->thresh_mult[THR_NEAR2] = thresh;
        }

        if (ref_frames > 3) {
          sf->thresh_mult[THR_NEW3] = thresh << 1;
          sf->thresh_mult[THR_NEAREST3] = thresh;
          sf->thresh_mult[THR_NEAR3] = thresh;
        }

        sf->improved_mv_pred = 0;
      }

      if (Speed > 8) sf->quarter_pixel_search = 0;

      if (cm->version == 0) {
        cm->filter_type = NORMAL_LOOPFILTER;

        if (Speed >= 14) cm->filter_type = SIMPLE_LOOPFILTER;
      } else {
        cm->filter_type = SIMPLE_LOOPFILTER;
      }

      /* This has a big hit on quality. Last resort */
      if (Speed >= 15) sf->half_pixel_search = 0;

      memset(cpi->mb.error_bins, 0, sizeof(cpi->mb.error_bins));

  } /* switch */

  /* Slow quant, dct and trellis not worthwhile for first pass
   * so make sure they are always turned off.
   */

  if (cpi->pass == 1) {
    sf->improved_quant = 0;
    sf->optimize_coefficients = 0;
    sf->improved_dct = 0;
  }

  if (cpi->sf.search_method == NSTEP) {
    vp8_init3smotion_compensation(&cpi->mb,
                                  cm->yv12_fb[cm->lst_fb_idx].y_stride);
  } else if (cpi->sf.search_method == DIAMOND) {
    vp8_init_dsmotion_compensation(&cpi->mb,
                                   cm->yv12_fb[cm->lst_fb_idx].y_stride);
  }

  if (cpi->sf.improved_dct) {
    cpi->mb.short_fdct8x4 = vp8_short_fdct8x4;
    cpi->mb.short_fdct4x4 = vp8_short_fdct4x4;
  } else {
    /* No fast FDCT defined for any platform at this time. */
    cpi->mb.short_fdct8x4 = vp8_short_fdct8x4;
    cpi->mb.short_fdct4x4 = vp8_short_fdct4x4;
  }

  cpi->mb.short_walsh4x4 = vp8_short_walsh4x4;

  if (cpi->sf.improved_quant) {
    cpi->mb.quantize_b = vp8_regular_quantize_b;
  } else {
    cpi->mb.quantize_b = vp8_fast_quantize_b;
  }
  if (cpi->sf.improved_quant != last_improved_quant) vp8cx_init_quantizer(cpi);

  if (cpi->sf.iterative_sub_pixel == 1) {
    cpi->find_fractional_mv_step = vp8_find_best_sub_pixel_step_iteratively;
  } else if (cpi->sf.quarter_pixel_search) {
    cpi->find_fractional_mv_step = vp8_find_best_sub_pixel_step;
  } else if (cpi->sf.half_pixel_search) {
    cpi->find_fractional_mv_step = vp8_find_best_half_pixel_step;
  } else {
    cpi->find_fractional_mv_step = vp8_skip_fractional_mv_step;
  }

  if (cpi->sf.optimize_coefficients == 1 && cpi->pass != 1) {
    cpi->mb.optimize = 1;
  } else {
    cpi->mb.optimize = 0;
  }

  if (cpi->common.full_pixel) {
    cpi->find_fractional_mv_step = vp8_skip_fractional_mv_step;
  }

#ifdef SPEEDSTATS
  frames_at_speed[cpi->Speed]++;
#endif
}
#undef GOOD
#undef RT

static void alloc_raw_frame_buffers(VP8_COMP *cpi) {
#if VP8_TEMPORAL_ALT_REF
  int width = (cpi->oxcf.Width + 15) & ~15;
  int height = (cpi->oxcf.Height + 15) & ~15;
#endif

  cpi->lookahead = vp8_lookahead_init(cpi->oxcf.Width, cpi->oxcf.Height,
                                      cpi->oxcf.lag_in_frames);
  if (!cpi->lookahead) {
    vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR,
                       "Failed to allocate lag buffers");
  }

#if VP8_TEMPORAL_ALT_REF

  if (vp8_yv12_alloc_frame_buffer(&cpi->alt_ref_buffer, width, height,
                                  VP8BORDERINPIXELS)) {
    vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR,
                       "Failed to allocate altref buffer");
  }

#endif
}

static void dealloc_raw_frame_buffers(VP8_COMP *cpi) {
#if VP8_TEMPORAL_ALT_REF
  vp8_yv12_de_alloc_frame_buffer(&cpi->alt_ref_buffer);
#endif
  vp8_lookahead_destroy(cpi->lookahead);
}

static int vp8_alloc_partition_data(VP8_COMP *cpi) {
  vpx_free(cpi->mb.pip);

  cpi->mb.pip =
      vpx_calloc((cpi->common.mb_cols + 1) * (cpi->common.mb_rows + 1),
                 sizeof(PARTITION_INFO));
  if (!cpi->mb.pip) return 1;

  cpi->mb.pi = cpi->mb.pip + cpi->common.mode_info_stride + 1;

  return 0;
}

void vp8_alloc_compressor_data(VP8_COMP *cpi) {
  VP8_COMMON *cm = &cpi->common;

  int width = cm->Width;
  int height = cm->Height;

  if (vp8_alloc_frame_buffers(cm, width, height)) {
    vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR,
                       "Failed to allocate frame buffers");
  }

  if (vp8_alloc_partition_data(cpi)) {
    vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR,
                       "Failed to allocate partition data");
  }

  if ((width & 0xf) != 0) width += 16 - (width & 0xf);

  if ((height & 0xf) != 0) height += 16 - (height & 0xf);

  if (vp8_yv12_alloc_frame_buffer(&cpi->pick_lf_lvl_frame, width, height,
                                  VP8BORDERINPIXELS)) {
    vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR,
                       "Failed to allocate last frame buffer");
  }

  if (vp8_yv12_alloc_frame_buffer(&cpi->scaled_source, width, height,
                                  VP8BORDERINPIXELS)) {
    vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR,
                       "Failed to allocate scaled source buffer");
  }

  vpx_free(cpi->tok);

  {
#if CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING
    unsigned int tokens = 8 * 24 * 16; /* one MB for each thread */
#else
    unsigned int tokens = cm->mb_rows * cm->mb_cols * 24 * 16;
#endif
    CHECK_MEM_ERROR(&cpi->common.error, cpi->tok,
                    vpx_calloc(tokens, sizeof(*cpi->tok)));
  }

  /* Data used for real time vc mode to see if gf needs refreshing */
  cpi->zeromv_count = 0;

  /* Structures used to monitor GF usage */
  vpx_free(cpi->gf_active_flags);
  CHECK_MEM_ERROR(
      &cpi->common.error, cpi->gf_active_flags,
      vpx_calloc(sizeof(*cpi->gf_active_flags), cm->mb_rows * cm->mb_cols));
  cpi->gf_active_count = cm->mb_rows * cm->mb_cols;

  vpx_free(cpi->mb_activity_map);
  CHECK_MEM_ERROR(
      &cpi->common.error, cpi->mb_activity_map,
      vpx_calloc(sizeof(*cpi->mb_activity_map), cm->mb_rows * cm->mb_cols));

  /* allocate memory for storing last frame's MVs for MV prediction. */
  vpx_free(cpi->lfmv);
  CHECK_MEM_ERROR(
      &cpi->common.error, cpi->lfmv,
      vpx_calloc((cm->mb_rows + 2) * (cm->mb_cols + 2), sizeof(*cpi->lfmv)));
  vpx_free(cpi->lf_ref_frame_sign_bias);
  CHECK_MEM_ERROR(&cpi->common.error, cpi->lf_ref_frame_sign_bias,
                  vpx_calloc((cm->mb_rows + 2) * (cm->mb_cols + 2),
                             sizeof(*cpi->lf_ref_frame_sign_bias)));
  vpx_free(cpi->lf_ref_frame);
  CHECK_MEM_ERROR(&cpi->common.error, cpi->lf_ref_frame,
                  vpx_calloc((cm->mb_rows + 2) * (cm->mb_cols + 2),
                             sizeof(*cpi->lf_ref_frame)));

  /* Create the encoder segmentation map and set all entries to 0 */
  vpx_free(cpi->segmentation_map);
  CHECK_MEM_ERROR(
      &cpi->common.error, cpi->segmentation_map,
      vpx_calloc(cm->mb_rows * cm->mb_cols, sizeof(*cpi->segmentation_map)));
  cpi->cyclic_refresh_mode_index = 0;
  vpx_free(cpi->active_map);
  CHECK_MEM_ERROR(
      &cpi->common.error, cpi->active_map,
      vpx_calloc(cm->mb_rows * cm->mb_cols, sizeof(*cpi->active_map)));
  memset(cpi->active_map, 1, (cm->mb_rows * cm->mb_cols));

#if CONFIG_MULTITHREAD
  if (width < 640) {
    cpi->mt_sync_range = 1;
  } else if (width <= 1280) {
    cpi->mt_sync_range = 4;
  } else if (width <= 2560) {
    cpi->mt_sync_range = 8;
  } else {
    cpi->mt_sync_range = 16;
  }
#endif

  vpx_free(cpi->tplist);
  CHECK_MEM_ERROR(&cpi->common.error, cpi->tplist,
                  vpx_malloc(sizeof(TOKENLIST) * cm->mb_rows));

#if CONFIG_TEMPORAL_DENOISING
  if (cpi->oxcf.noise_sensitivity > 0) {
    vp8_denoiser_free(&cpi->denoiser);
    if (vp8_denoiser_allocate(&cpi->denoiser, width, height, cm->mb_rows,
                              cm->mb_cols, cpi->oxcf.noise_sensitivity)) {
      vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR,
                         "Failed to allocate denoiser");
    }
  }
#endif
}

/* Quant MOD */
static const int q_trans[] = {
  0,  1,  2,  3,  4,  5,  7,   8,   9,   10,  12,  13,  15,  17,  18,  19,
  20, 21, 23, 24, 25, 26, 27,  28,  29,  30,  31,  33,  35,  37,  39,  41,
  43, 45, 47, 49, 51, 53, 55,  57,  59,  61,  64,  67,  70,  73,  76,  79,
  82, 85, 88, 91, 94, 97, 100, 103, 106, 109, 112, 115, 118, 121, 124, 127,
};

int vp8_reverse_trans(int x) {
  int i;

  for (i = 0; i < 64; ++i) {
    if (q_trans[i] >= x) return i;
  }

  return 63;
}
void vp8_new_framerate(VP8_COMP *cpi, double framerate) {
  if (framerate < .1) framerate = 30;

  cpi->framerate = framerate;
  cpi->output_framerate = framerate;
  const double per_frame_bandwidth =
      round(cpi->oxcf.target_bandwidth / cpi->output_framerate);
  cpi->per_frame_bandwidth = (int)VPXMIN(per_frame_bandwidth, INT_MAX);
  cpi->av_per_frame_bandwidth = cpi->per_frame_bandwidth;
  const int64_t vbr_min_bits = (int64_t)cpi->av_per_frame_bandwidth *
                               cpi->oxcf.two_pass_vbrmin_section / 100;
  cpi->min_frame_bandwidth = (int)VPXMIN(vbr_min_bits, INT_MAX);

  /* Set Maximum gf/arf interval */
  cpi->max_gf_interval = ((int)(cpi->output_framerate / 2.0) + 2);

  if (cpi->max_gf_interval < 12) cpi->max_gf_interval = 12;

  /* Extended interval for genuinely static scenes */
  cpi->twopass.static_scene_max_gf_interval = cpi->key_frame_frequency >> 1;

  /* Special conditions when altr ref frame enabled in lagged compress mode */
  if (cpi->oxcf.play_alternate && cpi->oxcf.lag_in_frames) {
    if (cpi->max_gf_interval > cpi->oxcf.lag_in_frames - 1) {
      cpi->max_gf_interval = cpi->oxcf.lag_in_frames - 1;
    }

    if (cpi->twopass.static_scene_max_gf_interval >
        cpi->oxcf.lag_in_frames - 1) {
      cpi->twopass.static_scene_max_gf_interval = cpi->oxcf.lag_in_frames - 1;
    }
  }

  if (cpi->max_gf_interval > cpi->twopass.static_scene_max_gf_interval) {
    cpi->max_gf_interval = cpi->twopass.static_scene_max_gf_interval;
  }
}

static void init_config(VP8_COMP *cpi, const VP8_CONFIG *oxcf) {
  VP8_COMMON *cm = &cpi->common;

  cpi->oxcf = *oxcf;

  cpi->auto_gold = 1;
  cpi->auto_adjust_gold_quantizer = 1;

  cm->version = oxcf->Version;
  vp8_setup_version(cm);

  /* Frame rate is not available on the first frame, as it's derived from
   * the observed timestamps. The actual value used here doesn't matter
   * too much, as it will adapt quickly.
   */

  if (oxcf->timebase.num > 0) {
    cpi->framerate =
        (double)(oxcf->timebase.den) / (double)(oxcf->timebase.num);
  } else {
    cpi->framerate = 30;
  }

  /* If the reciprocal of the timebase seems like a reasonable framerate,
   * then use that as a guess, otherwise use 30.
   */

  if (cpi->framerate > 180) cpi->framerate = 30;

  cpi->ref_framerate = cpi->framerate;

  cpi->ref_frame_flags = VP8_ALTR_FRAME | VP8_GOLD_FRAME | VP8_LAST_FRAME;

  cm->refresh_golden_frame = 0;
  cm->refresh_last_frame = 1;
  cm->refresh_entropy_probs = 1;

  /* change includes all joint functionality */
  vp8_change_config(cpi, oxcf);

  /* Initialize active best and worst q and average q values. */
  cpi->active_worst_quality = cpi->oxcf.worst_allowed_q;
  cpi->active_best_quality = cpi->oxcf.best_allowed_q;
  cpi->avg_frame_qindex = cpi->oxcf.worst_allowed_q;

  /* Initialise the starting buffer levels */
  cpi->buffer_level = cpi->oxcf.starting_buffer_level;
  cpi->bits_off_target = cpi->oxcf.starting_buffer_level;

  cpi->rolling_target_bits = cpi->av_per_frame_bandwidth;
  cpi->rolling_actual_bits = cpi->av_per_frame_bandwidth;
  cpi->long_rolling_target_bits = cpi->av_per_frame_bandwidth;
  cpi->long_rolling_actual_bits = cpi->av_per_frame_bandwidth;

  cpi->total_actual_bits = 0;
  cpi->total_target_vs_actual = 0;

  /* Temporal scalabilty */
  if (cpi->oxcf.number_of_layers > 1) {
    unsigned int i;
    double prev_layer_framerate = 0;

    for (i = 0; i < cpi->oxcf.number_of_layers; ++i) {
      vp8_init_temporal_layer_context(cpi, oxcf, i, prev_layer_framerate);
      prev_layer_framerate =
          cpi->output_framerate / cpi->oxcf.rate_decimator[i];
    }
  }

#if VP8_TEMPORAL_ALT_REF
  {
    int i;

    cpi->fixed_divide[0] = 0;

    for (i = 1; i < 512; ++i) cpi->fixed_divide[i] = 0x80000 / i;
  }
#endif
}

void vp8_update_layer_contexts(VP8_COMP *cpi) {
  VP8_CONFIG *oxcf = &cpi->oxcf;

  /* Update snapshots of the layer contexts to reflect new parameters */
  if (oxcf->number_of_layers > 1) {
    unsigned int i;
    double prev_layer_framerate = 0;

    assert(oxcf->number_of_layers <= VPX_TS_MAX_LAYERS);
    for (i = 0; i < oxcf->number_of_layers && i < VPX_TS_MAX_LAYERS; ++i) {
      LAYER_CONTEXT *lc = &cpi->layer_context[i];

      lc->framerate = cpi->ref_framerate / oxcf->rate_decimator[i];
      if (oxcf->target_bitrate[i] > INT_MAX / 1000)
        lc->target_bandwidth = INT_MAX;
      else
        lc->target_bandwidth = oxcf->target_bitrate[i] * 1000;

      lc->starting_buffer_level = rescale(
          (int)oxcf->starting_buffer_level_in_ms, lc->target_bandwidth, 1000);

      if (oxcf->optimal_buffer_level == 0) {
        lc->optimal_buffer_level = lc->target_bandwidth / 8;
      } else {
        lc->optimal_buffer_level = rescale(
            (int)oxcf->optimal_buffer_level_in_ms, lc->target_bandwidth, 1000);
      }

      if (oxcf->maximum_buffer_size == 0) {
        lc->maximum_buffer_size = lc->target_bandwidth / 8;
      } else {
        lc->maximum_buffer_size = rescale((int)oxcf->maximum_buffer_size_in_ms,
                                          lc->target_bandwidth, 1000);
      }

      /* Work out the average size of a frame within this layer */
      if (i > 0) {
        lc->avg_frame_size_for_layer =
            (int)round((oxcf->target_bitrate[i] - oxcf->target_bitrate[i - 1]) *
                       1000 / (lc->framerate - prev_layer_framerate));
      }

      prev_layer_framerate = lc->framerate;
    }
  }
}

void vp8_change_config(VP8_COMP *cpi, const VP8_CONFIG *oxcf) {
  VP8_COMMON *cm = &cpi->common;
  int last_w, last_h;
  unsigned int prev_number_of_layers;
  double raw_target_rate;

  if (!cpi) return;

  if (!oxcf) return;

  if (cm->version != oxcf->Version) {
    cm->version = oxcf->Version;
    vp8_setup_version(cm);
  }

  last_w = cpi->oxcf.Width;
  last_h = cpi->oxcf.Height;
  prev_number_of_layers = cpi->oxcf.number_of_layers;

  cpi->oxcf = *oxcf;

  switch (cpi->oxcf.Mode) {
    case MODE_REALTIME:
      cpi->pass = 0;
      cpi->compressor_speed = 2;

      if (cpi->oxcf.cpu_used < -16) {
        cpi->oxcf.cpu_used = -16;
      }

      if (cpi->oxcf.cpu_used > 16) cpi->oxcf.cpu_used = 16;

      break;

    case MODE_GOODQUALITY:
      cpi->pass = 0;
      cpi->compressor_speed = 1;

      if (cpi->oxcf.cpu_used < -5) {
        cpi->oxcf.cpu_used = -5;
      }

      if (cpi->oxcf.cpu_used > 5) cpi->oxcf.cpu_used = 5;

      break;

    case MODE_BESTQUALITY:
      cpi->pass = 0;
      cpi->compressor_speed = 0;
      break;

    case MODE_FIRSTPASS:
      cpi->pass = 1;
      cpi->compressor_speed = 1;
      break;
    case MODE_SECONDPASS:
      cpi->pass = 2;
      cpi->compressor_speed = 1;

      if (cpi->oxcf.cpu_used < -5) {
        cpi->oxcf.cpu_used = -5;
      }

      if (cpi->oxcf.cpu_used > 5) cpi->oxcf.cpu_used = 5;

      break;
    case MODE_SECONDPASS_BEST:
      cpi->pass = 2;
      cpi->compressor_speed = 0;
      break;
  }

  if (cpi->pass == 0) cpi->auto_worst_q = 1;

  cpi->oxcf.worst_allowed_q = q_trans[oxcf->worst_allowed_q];
  cpi->oxcf.best_allowed_q = q_trans[oxcf->best_allowed_q];
  cpi->oxcf.cq_level = q_trans[cpi->oxcf.cq_level];

  if (oxcf->fixed_q >= 0) {
    if (oxcf->worst_allowed_q < 0) {
      cpi->oxcf.fixed_q = q_trans[0];
    } else {
      cpi->oxcf.fixed_q = q_trans[oxcf->worst_allowed_q];
    }

    if (oxcf->alt_q < 0) {
      cpi->oxcf.alt_q = q_trans[0];
    } else {
      cpi->oxcf.alt_q = q_trans[oxcf->alt_q];
    }

    if (oxcf->key_q < 0) {
      cpi->oxcf.key_q = q_trans[0];
    } else {
      cpi->oxcf.key_q = q_trans[oxcf->key_q];
    }

    if (oxcf->gold_q < 0) {
      cpi->oxcf.gold_q = q_trans[0];
    } else {
      cpi->oxcf.gold_q = q_trans[oxcf->gold_q];
    }
  }

  cpi->ext_refresh_frame_flags_pending = 0;

  cpi->baseline_gf_interval =
      cpi->oxcf.alt_freq ? cpi->oxcf.alt_freq : DEFAULT_GF_INTERVAL;

  // GF behavior for 1 pass CBR, used when error_resilience is off.
  if (!cpi->oxcf.error_resilient_mode &&
      cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER &&
      cpi->oxcf.Mode == MODE_REALTIME)
    cpi->baseline_gf_interval = cpi->gf_interval_onepass_cbr;

#if (CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING)
  cpi->oxcf.token_partitions = 3;
#endif

  if (cpi->oxcf.token_partitions >= 0 && cpi->oxcf.token_partitions <= 3) {
    cm->multi_token_partition = (TOKEN_PARTITION)cpi->oxcf.token_partitions;
  }

  setup_features(cpi);

  if (!cpi->use_roi_static_threshold) {
    int i;
    for (i = 0; i < MAX_MB_SEGMENTS; ++i) {
      cpi->segment_encode_breakout[i] = cpi->oxcf.encode_breakout;
    }
  }

  /* At the moment the first order values may not be > MAXQ */
  if (cpi->oxcf.fixed_q > MAXQ) cpi->oxcf.fixed_q = MAXQ;

  /* local file playback mode == really big buffer */
  if (cpi->oxcf.end_usage == USAGE_LOCAL_FILE_PLAYBACK) {
    cpi->oxcf.starting_buffer_level = 60000;
    cpi->oxcf.optimal_buffer_level = 60000;
    cpi->oxcf.maximum_buffer_size = 240000;
    cpi->oxcf.starting_buffer_level_in_ms = 60000;
    cpi->oxcf.optimal_buffer_level_in_ms = 60000;
    cpi->oxcf.maximum_buffer_size_in_ms = 240000;
  }

  raw_target_rate = ((int64_t)cpi->oxcf.Width * cpi->oxcf.Height * 8 * 3 *
                     cpi->framerate / 1000.0);
  if (cpi->oxcf.target_bandwidth > raw_target_rate)
    cpi->oxcf.target_bandwidth = (unsigned int)raw_target_rate;
  /* Convert target bandwidth from Kbit/s to Bit/s */
  cpi->oxcf.target_bandwidth *= 1000;

  cpi->oxcf.starting_buffer_level = rescale(
      (int)cpi->oxcf.starting_buffer_level, cpi->oxcf.target_bandwidth, 1000);

  /* Set or reset optimal and maximum buffer levels. */
  if (cpi->oxcf.optimal_buffer_level == 0) {
    cpi->oxcf.optimal_buffer_level = cpi->oxcf.target_bandwidth / 8;
  } else {
    cpi->oxcf.optimal_buffer_level = rescale(
        (int)cpi->oxcf.optimal_buffer_level, cpi->oxcf.target_bandwidth, 1000);
  }

  if (cpi->oxcf.maximum_buffer_size == 0) {
    cpi->oxcf.maximum_buffer_size = cpi->oxcf.target_bandwidth / 8;
  } else {
    cpi->oxcf.maximum_buffer_size = rescale((int)cpi->oxcf.maximum_buffer_size,
                                            cpi->oxcf.target_bandwidth, 1000);
  }
  // Under a configuration change, where maximum_buffer_size may change,
  // keep buffer level clipped to the maximum allowed buffer size.
  if (cpi->bits_off_target > cpi->oxcf.maximum_buffer_size) {
    cpi->bits_off_target = cpi->oxcf.maximum_buffer_size;
    cpi->buffer_level = cpi->bits_off_target;
  }

  /* Set up frame rate and related parameters rate control values. */
  vp8_new_framerate(cpi, cpi->framerate);

  /* Set absolute upper and lower quality limits */
  cpi->worst_quality = cpi->oxcf.worst_allowed_q;
  cpi->best_quality = cpi->oxcf.best_allowed_q;

  /* active values should only be modified if out of new range */
  if (cpi->active_worst_quality > cpi->oxcf.worst_allowed_q) {
    cpi->active_worst_quality = cpi->oxcf.worst_allowed_q;
  }
  /* less likely */
  else if (cpi->active_worst_quality < cpi->oxcf.best_allowed_q) {
    cpi->active_worst_quality = cpi->oxcf.best_allowed_q;
  }
  if (cpi->active_best_quality < cpi->oxcf.best_allowed_q) {
    cpi->active_best_quality = cpi->oxcf.best_allowed_q;
  }
  /* less likely */
  else if (cpi->active_best_quality > cpi->oxcf.worst_allowed_q) {
    cpi->active_best_quality = cpi->oxcf.worst_allowed_q;
  }

  cpi->buffered_mode = cpi->oxcf.optimal_buffer_level > 0;

  cpi->cq_target_quality = cpi->oxcf.cq_level;

  /* Only allow dropped frames in buffered mode */
  cpi->drop_frames_allowed = cpi->oxcf.allow_df && cpi->buffered_mode;

  cpi->target_bandwidth = cpi->oxcf.target_bandwidth;

  // Check if the number of temporal layers has changed, and if so reset the
  // pattern counter and set/initialize the temporal layer context for the
  // new layer configuration.
  if (cpi->oxcf.number_of_layers != prev_number_of_layers) {
    // If the number of temporal layers are changed we must start at the
    // base of the pattern cycle, so set the layer id to 0 and reset
    // the temporal pattern counter.
    if (cpi->temporal_layer_id > 0) {
      cpi->temporal_layer_id = 0;
    }
    cpi->temporal_pattern_counter = 0;
    vp8_reset_temporal_layer_change(cpi, oxcf, prev_number_of_layers);
  }

  if (!cpi->initial_width) {
    cpi->initial_width = cpi->oxcf.Width;
    cpi->initial_height = cpi->oxcf.Height;
  }

  cm->Width = cpi->oxcf.Width;
  cm->Height = cpi->oxcf.Height;
  assert(cm->Width <= cpi->initial_width);
  assert(cm->Height <= cpi->initial_height);

  /* TODO(jkoleszar): if an internal spatial resampling is active,
   * and we downsize the input image, maybe we should clear the
   * internal scale immediately rather than waiting for it to
   * correct.
   */


  /* VP8 sharpness level mapping 0-7 (vs 0-10 in general VPx dialogs) */
  if (cpi->oxcf.Sharpness > 7) cpi->oxcf.Sharpness = 7;

  cm->sharpness_level = cpi->oxcf.Sharpness;

  if (cm->horiz_scale != VP8E_NORMAL || cm->vert_scale != VP8E_NORMAL) {
    int hr, hs, vr, vs;

    Scale2Ratio(cm->horiz_scale, &hr, &hs);
    Scale2Ratio(cm->vert_scale, &vr, &vs);

    /* always go to the next whole number */
    cm->Width = (hs - 1 + cpi->oxcf.Width * hr) / hs;
    cm->Height = (vs - 1 + cpi->oxcf.Height * vr) / vs;
  }

  if (last_w != cpi->oxcf.Width || last_h != cpi->oxcf.Height) {
    cpi->force_next_frame_intra = 1;
  }

  if (((cm->Width + 15) & ~15) != cm->yv12_fb[cm->lst_fb_idx].y_width ||
      ((cm->Height + 15) & ~15) != cm->yv12_fb[cm->lst_fb_idx].y_height ||
      cm->yv12_fb[cm->lst_fb_idx].y_width == 0) {
    dealloc_raw_frame_buffers(cpi);
    alloc_raw_frame_buffers(cpi);
    vp8_alloc_compressor_data(cpi);
  }

  if (cpi->oxcf.fixed_q >= 0) {
    cpi->last_q[0] = cpi->oxcf.fixed_q;
    cpi->last_q[1] = cpi->oxcf.fixed_q;
  }

  cpi->Speed = cpi->oxcf.cpu_used;

  /* force to allowlag to 0 if lag_in_frames is 0; */
  if (cpi->oxcf.lag_in_frames == 0) {
    cpi->oxcf.allow_lag = 0;
  }
  /* Limit on lag buffers as these are not currently dynamically allocated */
  else if (cpi->oxcf.lag_in_frames > MAX_LAG_BUFFERS) {
    cpi->oxcf.lag_in_frames = MAX_LAG_BUFFERS;
  }

  /* YX Temp */
  cpi->alt_ref_source = NULL;
  cpi->is_src_frame_alt_ref = 0;

#if CONFIG_TEMPORAL_DENOISING
  if (cpi->oxcf.noise_sensitivity) {
    if (!cpi->denoiser.yv12_mc_running_avg.buffer_alloc) {
      int width = (cpi->oxcf.Width + 15) & ~15;
      int height = (cpi->oxcf.Height + 15) & ~15;
      if (vp8_denoiser_allocate(&cpi->denoiser, width, height, cm->mb_rows,
                                cm->mb_cols, cpi->oxcf.noise_sensitivity)) {
        vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR,
                           "Failed to allocate denoiser");
      }
    }
  }
#endif

#if 0
    /* Experimental RD Code */
    cpi->frame_distortion = 0;
    cpi->last_frame_distortion = 0;
#endif
}

#ifndef M_LOG2_E
#define M_LOG2_E 0.693147180559945309417
#endif
#define log2f(x) (log(x) / (float)M_LOG2_E)

static void cal_mvsadcosts(int *mvsadcost[2]) {
  int i = 1;

  mvsadcost[0][0] = 300;
  mvsadcost[1][0] = 300;

  do {
    double z = 256 * (2 * (log2f(8 * i) + .6));
    mvsadcost[0][i] = (int)z;
    mvsadcost[1][i] = (int)z;
    mvsadcost[0][-i] = (int)z;
    mvsadcost[1][-i] = (int)z;
  } while (++i <= mvfp_max);
}

struct VP8_COMP *vp8_create_compressor(const VP8_CONFIG *oxcf) {
  int i;

  VP8_COMP *cpi;
  VP8_COMMON *cm;

  cpi = vpx_memalign(32, sizeof(VP8_COMP));
  /* Check that the CPI instance is valid */
  if (!cpi) return 0;

  cm = &cpi->common;

  memset(cpi, 0, sizeof(VP8_COMP));

  if (setjmp(cm->error.jmp)) {
    cpi->common.error.setjmp = 0;
    vp8_remove_compressor(&cpi);
    return 0;
  }

  cpi->common.error.setjmp = 1;

  CHECK_MEM_ERROR(
      &cpi->common.error, cpi->mb.ss,
      vpx_calloc(sizeof(search_site), (MAX_MVSEARCH_STEPS * 8) + 1));

  vp8_create_common(&cpi->common);

  init_config(cpi, oxcf);

  memcpy(cpi->base_skip_false_prob, vp8cx_base_skip_false_prob,
         sizeof(vp8cx_base_skip_false_prob));
  cpi->common.current_video_frame = 0;
  cpi->temporal_pattern_counter = 0;
  cpi->temporal_layer_id = -1;
  cpi->kf_overspend_bits = 0;
  cpi->kf_bitrate_adjustment = 0;
  cpi->frames_till_gf_update_due = 0;
  cpi->gf_overspend_bits = 0;
  cpi->non_gf_bitrate_adjustment = 0;
  cpi->prob_last_coded = 128;
  cpi->prob_gf_coded = 128;
  cpi->prob_intra_coded = 63;

  /* Prime the recent reference frame usage counters.
   * Hereafter they will be maintained as a sort of moving average
   */

  cpi->recent_ref_frame_usage[INTRA_FRAME] = 1;
  cpi->recent_ref_frame_usage[LAST_FRAME] = 1;
  cpi->recent_ref_frame_usage[GOLDEN_FRAME] = 1;
  cpi->recent_ref_frame_usage[ALTREF_FRAME] = 1;

  /* Set reference frame sign bias for ALTREF frame to 1 (for now) */
  cpi->common.ref_frame_sign_bias[ALTREF_FRAME] = 1;

  cpi->twopass.gf_decay_rate = 0;
  cpi->baseline_gf_interval = DEFAULT_GF_INTERVAL;

  cpi->gold_is_last = 0;
  cpi->alt_is_last = 0;
  cpi->gold_is_alt = 0;

  cpi->active_map_enabled = 0;

  cpi->use_roi_static_threshold = 0;

#if 0
    /* Experimental code for lagged and one pass */
    /* Initialise one_pass GF frames stats */
    /* Update stats used for GF selection */
    if (cpi->pass == 0)
    {
        cpi->one_pass_frame_index = 0;

        for (i = 0; i < MAX_LAG_BUFFERS; ++i)
        {
            cpi->one_pass_frame_stats[i].frames_so_far = 0;
            cpi->one_pass_frame_stats[i].frame_intra_error = 0.0;
            cpi->one_pass_frame_stats[i].frame_coded_error = 0.0;
            cpi->one_pass_frame_stats[i].frame_pcnt_inter = 0.0;
            cpi->one_pass_frame_stats[i].frame_pcnt_motion = 0.0;
            cpi->one_pass_frame_stats[i].frame_mvr = 0.0;
            cpi->one_pass_frame_stats[i].frame_mvr_abs = 0.0;
            cpi->one_pass_frame_stats[i].frame_mvc = 0.0;
            cpi->one_pass_frame_stats[i].frame_mvc_abs = 0.0;
        }
    }
#endif

  cpi->mse_source_denoised = 0;

  /* Should we use the cyclic refresh method.
   * Currently there is no external control for this.
   * Enable it for error_resilient_mode, or for 1 pass CBR mode.
   */

  cpi->cyclic_refresh_mode_enabled =
      (cpi->oxcf.error_resilient_mode ||
       (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER &&
        cpi->oxcf.Mode <= 2));
  cpi->cyclic_refresh_mode_max_mbs_perframe =
      (cpi->common.mb_rows * cpi->common.mb_cols) / 7;
  if (cpi->oxcf.number_of_layers == 1) {
    cpi->cyclic_refresh_mode_max_mbs_perframe =
        (cpi->common.mb_rows * cpi->common.mb_cols) / 20;
  } else if (cpi->oxcf.number_of_layers == 2) {
    cpi->cyclic_refresh_mode_max_mbs_perframe =
        (cpi->common.mb_rows * cpi->common.mb_cols) / 10;
  }
  cpi->cyclic_refresh_mode_index = 0;
  cpi->cyclic_refresh_q = 32;

  // GF behavior for 1 pass CBR, used when error_resilience is off.
  cpi->gf_update_onepass_cbr = 0;
  cpi->gf_noboost_onepass_cbr = 0;
  if (!cpi->oxcf.error_resilient_mode &&
      cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER && cpi->oxcf.Mode <= 2) {
    cpi->gf_update_onepass_cbr = 1;
    cpi->gf_noboost_onepass_cbr = 1;
    cpi->gf_interval_onepass_cbr =
        cpi->cyclic_refresh_mode_max_mbs_perframe > 0
            ? (2 * (cpi->common.mb_rows * cpi->common.mb_cols) /
               cpi->cyclic_refresh_mode_max_mbs_perframe)
            : 10;
    cpi->gf_interval_onepass_cbr =
        VPXMIN(40, VPXMAX(6, cpi->gf_interval_onepass_cbr));
    cpi->baseline_gf_interval = cpi->gf_interval_onepass_cbr;
  }

  if (cpi->cyclic_refresh_mode_enabled) {
    CHECK_MEM_ERROR(&cpi->common.error, cpi->cyclic_refresh_map,
                    vpx_calloc((cpi->common.mb_rows * cpi->common.mb_cols), 1));
  } else {
    cpi->cyclic_refresh_map = (signed char *)NULL;
  }

  CHECK_MEM_ERROR(
      &cpi->common.error, cpi->skin_map,
      vpx_calloc(cm->mb_rows * cm->mb_cols, sizeof(cpi->skin_map[0])));

  CHECK_MEM_ERROR(&cpi->common.error, cpi->consec_zero_last,
                  vpx_calloc(cm->mb_rows * cm->mb_cols, 1));
  CHECK_MEM_ERROR(&cpi->common.error, cpi->consec_zero_last_mvbias,
                  vpx_calloc((cpi->common.mb_rows * cpi->common.mb_cols), 1));

  /*Initialize the feed-forward activity masking.*/
  cpi->activity_avg = 90 << 12;

  /* Give a sensible default for the first frame. */
  cpi->frames_since_key = 8;
  cpi->key_frame_frequency = cpi->oxcf.key_freq;
  cpi->this_key_frame_forced = 0;
  cpi->next_key_frame_forced = 0;

  cpi->source_alt_ref_pending = 0;
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=93 H=92 G=92

¤ Dauer der Verarbeitung: 0.23 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.