/*
* 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 <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "./vp9_rtcd.h"
#include "./vpx_config.h"
#include "./vpx_dsp_rtcd.h"
#include "./vpx_scale_rtcd.h"
#include "vpx/vpx_codec.h"
#include "vpx/vpx_ext_ratectrl.h"
#include "vpx_dsp/psnr.h"
#include "vpx_dsp/vpx_dsp_common.h"
#include "vpx_dsp/vpx_filter.h"
#if CONFIG_INTERNAL_STATS
#include "vpx_dsp/ssim.h"
#endif
#include "vpx_mem/vpx_mem.h"
#include "vpx_ports/mem.h"
#include "vpx_ports/system_state.h"
#include "vpx_ports/vpx_once.h"
#include "vpx_ports/vpx_timer.h"
#include "vpx_util/vpx_pthread.h"
#if CONFIG_BITSTREAM_DEBUG || CONFIG_MISMATCH_DEBUG
#include "vpx_util/vpx_debug_util.h"
#endif // CONFIG_BITSTREAM_DEBUG || CONFIG_MISMATCH_DEBUG
#include "vp9/common/vp9_alloccommon.h"
#include "vp9/common/vp9_blockd.h"
#include "vp9/common/vp9_enums.h"
#include "vp9/common/vp9_filter.h"
#include "vp9/common/vp9_idct.h"
#if CONFIG_VP9_POSTPROC
#include "vp9/common/vp9_postproc.h"
#endif
#include "vp9/common/vp9_reconinter.h"
#include "vp9/common/vp9_reconintra.h"
#include "vp9/common/vp9_scale.h"
#include "vp9/common/vp9_tile_common.h"
#if !CONFIG_REALTIME_ONLY
#include "vp9/encoder/vp9_alt_ref_aq.h"
#include "vp9/encoder/vp9_aq_360.h"
#include "vp9/encoder/vp9_aq_complexity.h"
#endif
#include "vp9/encoder/vp9_aq_cyclicrefresh.h"
#if !CONFIG_REALTIME_ONLY
#include "vp9/encoder/vp9_aq_variance.h"
#endif
#include "vp9/encoder/vp9_bitstream.h"
#if CONFIG_INTERNAL_STATS
#include "vp9/encoder/vp9_blockiness.h"
#endif
#include "vp9/encoder/vp9_context_tree.h"
#include "vp9/encoder/vp9_encodeframe.h"
#include "vp9/encoder/vp9_encodemb.h"
#include "vp9/encoder/vp9_encodemv.h"
#include "vp9/encoder/vp9_encoder.h"
#include "vp9/encoder/vp9_ethread.h"
#include "vp9/encoder/vp9_extend.h"
#include "vp9/encoder/vp9_firstpass.h"
#include "vp9/encoder/vp9_mbgraph.h"
#if CONFIG_NON_GREEDY_MV
#include "vp9/encoder/vp9_mcomp.h"
#endif
#include "vp9/encoder/vp9_multi_thread.h"
#include "vp9/encoder/vp9_noise_estimate.h"
#include "vp9/encoder/vp9_picklpf.h"
#include "vp9/encoder/vp9_quantize.h"
#include "vp9/encoder/vp9_ratectrl.h"
#include "vp9/encoder/vp9_rd.h"
#include "vp9/encoder/vp9_resize.h"
#include "vp9/encoder/vp9_segmentation.h"
#include "vp9/encoder/vp9_skin_detection.h"
#include "vp9/encoder/vp9_speed_features.h"
#include "vp9/encoder/vp9_svc_layercontext.h"
#include "vp9/encoder/vp9_temporal_filter.h"
#include "vp9/encoder/vp9_tpl_model.h"
#include "vp9/vp9_cx_iface.h"
#define AM_SEGMENT_ID_INACTIVE 7
#define AM_SEGMENT_ID_ACTIVE 0
// Whether to use high precision mv for altref computation.
#define ALTREF_HIGH_PRECISION_MV 1
// Q threshold for high precision mv. Choose a very high value for now so that
// HIGH_PRECISION is always chosen.
#define HIGH_PRECISION_MV_QTHRESH 200
#define FRAME_SIZE_FACTOR 128 // empirical params for context model threshold
#define FRAME_RATE_FACTOR 8
#ifdef OUTPUT_YUV_DENOISED
FILE *yuv_denoised_file = NULL;
#endif
#ifdef OUTPUT_YUV_SKINMAP
static FILE *yuv_skinmap_file = NULL;
#endif
#ifdef OUTPUT_YUV_REC
FILE *yuv_rec_file;
#endif
#ifdef OUTPUT_YUV_SVC_SRC
FILE *yuv_svc_src[3] = { NULL, NULL, NULL };
#endif
#if 0
FILE *framepsnr;
FILE *kf_list;
FILE *keyfile;
#endif
#ifdef ENABLE_KF_DENOISE
// Test condition for spatial denoise of source.
static int is_spatial_denoise_enabled(VP9_COMP *cpi) {
VP9_COMMON *const cm = &cpi->common;
const VP9EncoderConfig *const oxcf = &cpi->oxcf;
return (oxcf->pass != 1) && !is_lossless_requested(&cpi->oxcf) &&
frame_is_intra_only(cm);
}
#endif
#if !CONFIG_REALTIME_ONLY
// compute adaptive threshold for skip recoding
static int compute_context_model_thresh(const VP9_COMP *const cpi) {
const VP9_COMMON *const cm = &cpi->common;
const VP9EncoderConfig *const oxcf = &cpi->oxcf;
const int frame_size = (cm->width * cm->height) >> 10;
const int bitrate = (int )(oxcf->target_bandwidth >> 10);
const int qindex_factor = cm->base_qindex + (MAXQ >> 1);
// This equation makes the threshold adaptive to frame size.
// Coding gain obtained by recoding comes from alternate frames of large
// content change. We skip recoding if the difference of previous and current
// frame context probability model is less than a certain threshold.
// The first component is the most critical part to guarantee adaptivity.
// Other parameters are estimated based on normal setting of hd resolution
// parameters. e.g. frame_size = 1920x1080, bitrate = 8000, qindex_factor < 50
const int thresh =
((FRAME_SIZE_FACTOR * frame_size - FRAME_RATE_FACTOR * bitrate) *
qindex_factor) >>
9;
return thresh;
}
// compute the total cost difference between current
// and previous frame context prob model.
static int compute_context_model_diff(const VP9_COMMON *const cm) {
const FRAME_CONTEXT *const pre_fc =
&cm->frame_contexts[cm->frame_context_idx];
const FRAME_CONTEXT *const cur_fc = cm->fc;
const FRAME_COUNTS *counts = &cm->counts;
vpx_prob pre_last_prob, cur_last_prob;
int diff = 0;
int i, j, k, l, m, n;
// y_mode_prob
for (i = 0; i < BLOCK_SIZE_GROUPS; ++i) {
for (j = 0; j < INTRA_MODES - 1; ++j) {
diff += (int )counts->y_mode[i][j] *
(pre_fc->y_mode_prob[i][j] - cur_fc->y_mode_prob[i][j]);
}
pre_last_prob = MAX_PROB - pre_fc->y_mode_prob[i][INTRA_MODES - 2];
cur_last_prob = MAX_PROB - cur_fc->y_mode_prob[i][INTRA_MODES - 2];
diff += (int )counts->y_mode[i][INTRA_MODES - 1] *
(pre_last_prob - cur_last_prob);
}
// uv_mode_prob
for (i = 0; i < INTRA_MODES; ++i) {
for (j = 0; j < INTRA_MODES - 1; ++j) {
diff += (int )counts->uv_mode[i][j] *
(pre_fc->uv_mode_prob[i][j] - cur_fc->uv_mode_prob[i][j]);
}
pre_last_prob = MAX_PROB - pre_fc->uv_mode_prob[i][INTRA_MODES - 2];
cur_last_prob = MAX_PROB - cur_fc->uv_mode_prob[i][INTRA_MODES - 2];
diff += (int )counts->uv_mode[i][INTRA_MODES - 1] *
(pre_last_prob - cur_last_prob);
}
// partition_prob
for (i = 0; i < PARTITION_CONTEXTS; ++i) {
for (j = 0; j < PARTITION_TYPES - 1; ++j) {
diff += (int )counts->partition[i][j] *
(pre_fc->partition_prob[i][j] - cur_fc->partition_prob[i][j]);
}
pre_last_prob = MAX_PROB - pre_fc->partition_prob[i][PARTITION_TYPES - 2];
cur_last_prob = MAX_PROB - cur_fc->partition_prob[i][PARTITION_TYPES - 2];
diff += (int )counts->partition[i][PARTITION_TYPES - 1] *
(pre_last_prob - cur_last_prob);
}
// coef_probs
for (i = 0; i < TX_SIZES; ++i) {
for (j = 0; j < PLANE_TYPES; ++j) {
for (k = 0; k < REF_TYPES; ++k) {
for (l = 0; l < COEF_BANDS; ++l) {
for (m = 0; m < BAND_COEFF_CONTEXTS(l); ++m) {
for (n = 0; n < UNCONSTRAINED_NODES; ++n) {
diff += (int )counts->coef[i][j][k][l][m][n] *
(pre_fc->coef_probs[i][j][k][l][m][n] -
cur_fc->coef_probs[i][j][k][l][m][n]);
}
pre_last_prob =
MAX_PROB -
pre_fc->coef_probs[i][j][k][l][m][UNCONSTRAINED_NODES - 1];
cur_last_prob =
MAX_PROB -
cur_fc->coef_probs[i][j][k][l][m][UNCONSTRAINED_NODES - 1];
diff += (int )counts->coef[i][j][k][l][m][UNCONSTRAINED_NODES] *
(pre_last_prob - cur_last_prob);
}
}
}
}
}
// switchable_interp_prob
for (i = 0; i < SWITCHABLE_FILTER_CONTEXTS; ++i) {
for (j = 0; j < SWITCHABLE_FILTERS - 1; ++j) {
diff += (int )counts->switchable_interp[i][j] *
(pre_fc->switchable_interp_prob[i][j] -
cur_fc->switchable_interp_prob[i][j]);
}
pre_last_prob =
MAX_PROB - pre_fc->switchable_interp_prob[i][SWITCHABLE_FILTERS - 2];
cur_last_prob =
MAX_PROB - cur_fc->switchable_interp_prob[i][SWITCHABLE_FILTERS - 2];
diff += (int )counts->switchable_interp[i][SWITCHABLE_FILTERS - 1] *
(pre_last_prob - cur_last_prob);
}
// inter_mode_probs
for (i = 0; i < INTER_MODE_CONTEXTS; ++i) {
for (j = 0; j < INTER_MODES - 1; ++j) {
diff += (int )counts->inter_mode[i][j] *
(pre_fc->inter_mode_probs[i][j] - cur_fc->inter_mode_probs[i][j]);
}
pre_last_prob = MAX_PROB - pre_fc->inter_mode_probs[i][INTER_MODES - 2];
cur_last_prob = MAX_PROB - cur_fc->inter_mode_probs[i][INTER_MODES - 2];
diff += (int )counts->inter_mode[i][INTER_MODES - 1] *
(pre_last_prob - cur_last_prob);
}
// intra_inter_prob
for (i = 0; i < INTRA_INTER_CONTEXTS; ++i) {
diff += (int )counts->intra_inter[i][0] *
(pre_fc->intra_inter_prob[i] - cur_fc->intra_inter_prob[i]);
pre_last_prob = MAX_PROB - pre_fc->intra_inter_prob[i];
cur_last_prob = MAX_PROB - cur_fc->intra_inter_prob[i];
diff += (int )counts->intra_inter[i][1] * (pre_last_prob - cur_last_prob);
}
// comp_inter_prob
for (i = 0; i < COMP_INTER_CONTEXTS; ++i) {
diff += (int )counts->comp_inter[i][0] *
(pre_fc->comp_inter_prob[i] - cur_fc->comp_inter_prob[i]);
pre_last_prob = MAX_PROB - pre_fc->comp_inter_prob[i];
cur_last_prob = MAX_PROB - cur_fc->comp_inter_prob[i];
diff += (int )counts->comp_inter[i][1] * (pre_last_prob - cur_last_prob);
}
// single_ref_prob
for (i = 0; i < REF_CONTEXTS; ++i) {
for (j = 0; j < 2; ++j) {
diff += (int )counts->single_ref[i][j][0] *
(pre_fc->single_ref_prob[i][j] - cur_fc->single_ref_prob[i][j]);
pre_last_prob = MAX_PROB - pre_fc->single_ref_prob[i][j];
cur_last_prob = MAX_PROB - cur_fc->single_ref_prob[i][j];
diff +=
(int )counts->single_ref[i][j][1] * (pre_last_prob - cur_last_prob);
}
}
// comp_ref_prob
for (i = 0; i < REF_CONTEXTS; ++i) {
diff += (int )counts->comp_ref[i][0] *
(pre_fc->comp_ref_prob[i] - cur_fc->comp_ref_prob[i]);
pre_last_prob = MAX_PROB - pre_fc->comp_ref_prob[i];
cur_last_prob = MAX_PROB - cur_fc->comp_ref_prob[i];
diff += (int )counts->comp_ref[i][1] * (pre_last_prob - cur_last_prob);
}
// tx_probs
for (i = 0; i < TX_SIZE_CONTEXTS; ++i) {
// p32x32
for (j = 0; j < TX_SIZES - 1; ++j) {
diff += (int )counts->tx.p32x32[i][j] *
(pre_fc->tx_probs.p32x32[i][j] - cur_fc->tx_probs.p32x32[i][j]);
}
pre_last_prob = MAX_PROB - pre_fc->tx_probs.p32x32[i][TX_SIZES - 2];
cur_last_prob = MAX_PROB - cur_fc->tx_probs.p32x32[i][TX_SIZES - 2];
diff += (int )counts->tx.p32x32[i][TX_SIZES - 1] *
(pre_last_prob - cur_last_prob);
// p16x16
for (j = 0; j < TX_SIZES - 2; ++j) {
diff += (int )counts->tx.p16x16[i][j] *
(pre_fc->tx_probs.p16x16[i][j] - cur_fc->tx_probs.p16x16[i][j]);
}
pre_last_prob = MAX_PROB - pre_fc->tx_probs.p16x16[i][TX_SIZES - 3];
cur_last_prob = MAX_PROB - cur_fc->tx_probs.p16x16[i][TX_SIZES - 3];
diff += (int )counts->tx.p16x16[i][TX_SIZES - 2] *
(pre_last_prob - cur_last_prob);
// p8x8
for (j = 0; j < TX_SIZES - 3; ++j) {
diff += (int )counts->tx.p8x8[i][j] *
(pre_fc->tx_probs.p8x8[i][j] - cur_fc->tx_probs.p8x8[i][j]);
}
pre_last_prob = MAX_PROB - pre_fc->tx_probs.p8x8[i][TX_SIZES - 4];
cur_last_prob = MAX_PROB - cur_fc->tx_probs.p8x8[i][TX_SIZES - 4];
diff +=
(int )counts->tx.p8x8[i][TX_SIZES - 3] * (pre_last_prob - cur_last_prob);
}
// skip_probs
for (i = 0; i < SKIP_CONTEXTS; ++i) {
diff += (int )counts->skip[i][0] *
(pre_fc->skip_probs[i] - cur_fc->skip_probs[i]);
pre_last_prob = MAX_PROB - pre_fc->skip_probs[i];
cur_last_prob = MAX_PROB - cur_fc->skip_probs[i];
diff += (int )counts->skip[i][1] * (pre_last_prob - cur_last_prob);
}
// mv
for (i = 0; i < MV_JOINTS - 1; ++i) {
diff += (int )counts->mv.joints[i] *
(pre_fc->nmvc.joints[i] - cur_fc->nmvc.joints[i]);
}
pre_last_prob = MAX_PROB - pre_fc->nmvc.joints[MV_JOINTS - 2];
cur_last_prob = MAX_PROB - cur_fc->nmvc.joints[MV_JOINTS - 2];
diff +=
(int )counts->mv.joints[MV_JOINTS - 1] * (pre_last_prob - cur_last_prob);
for (i = 0; i < 2; ++i) {
const nmv_component_counts *nmv_count = &counts->mv.comps[i];
const nmv_component *pre_nmv_prob = &pre_fc->nmvc.comps[i];
const nmv_component *cur_nmv_prob = &cur_fc->nmvc.comps[i];
// sign
diff += (int )nmv_count->sign[0] * (pre_nmv_prob->sign - cur_nmv_prob->sign);
pre_last_prob = MAX_PROB - pre_nmv_prob->sign;
cur_last_prob = MAX_PROB - cur_nmv_prob->sign;
diff += (int )nmv_count->sign[1] * (pre_last_prob - cur_last_prob);
// classes
for (j = 0; j < MV_CLASSES - 1; ++j) {
diff += (int )nmv_count->classes[j] *
(pre_nmv_prob->classes[j] - cur_nmv_prob->classes[j]);
}
pre_last_prob = MAX_PROB - pre_nmv_prob->classes[MV_CLASSES - 2];
cur_last_prob = MAX_PROB - cur_nmv_prob->classes[MV_CLASSES - 2];
diff += (int )nmv_count->classes[MV_CLASSES - 1] *
(pre_last_prob - cur_last_prob);
// class0
for (j = 0; j < CLASS0_SIZE - 1; ++j) {
diff += (int )nmv_count->class0[j] *
(pre_nmv_prob->class0[j] - cur_nmv_prob->class0[j]);
}
pre_last_prob = MAX_PROB - pre_nmv_prob->class0[CLASS0_SIZE - 2];
cur_last_prob = MAX_PROB - cur_nmv_prob->class0[CLASS0_SIZE - 2];
diff += (int )nmv_count->class0[CLASS0_SIZE - 1] *
(pre_last_prob - cur_last_prob);
// bits
for (j = 0; j < MV_OFFSET_BITS; ++j) {
diff += (int )nmv_count->bits[j][0] *
(pre_nmv_prob->bits[j] - cur_nmv_prob->bits[j]);
pre_last_prob = MAX_PROB - pre_nmv_prob->bits[j];
cur_last_prob = MAX_PROB - cur_nmv_prob->bits[j];
diff += (int )nmv_count->bits[j][1] * (pre_last_prob - cur_last_prob);
}
// class0_fp
for (j = 0; j < CLASS0_SIZE; ++j) {
for (k = 0; k < MV_FP_SIZE - 1; ++k) {
diff += (int )nmv_count->class0_fp[j][k] *
(pre_nmv_prob->class0_fp[j][k] - cur_nmv_prob->class0_fp[j][k]);
}
pre_last_prob = MAX_PROB - pre_nmv_prob->class0_fp[j][MV_FP_SIZE - 2];
cur_last_prob = MAX_PROB - cur_nmv_prob->class0_fp[j][MV_FP_SIZE - 2];
diff += (int )nmv_count->class0_fp[j][MV_FP_SIZE - 1] *
(pre_last_prob - cur_last_prob);
}
// fp
for (j = 0; j < MV_FP_SIZE - 1; ++j) {
diff +=
(int )nmv_count->fp[j] * (pre_nmv_prob->fp[j] - cur_nmv_prob->fp[j]);
}
pre_last_prob = MAX_PROB - pre_nmv_prob->fp[MV_FP_SIZE - 2];
cur_last_prob = MAX_PROB - cur_nmv_prob->fp[MV_FP_SIZE - 2];
diff +=
(int )nmv_count->fp[MV_FP_SIZE - 1] * (pre_last_prob - cur_last_prob);
// class0_hp
diff += (int )nmv_count->class0_hp[0] *
(pre_nmv_prob->class0_hp - cur_nmv_prob->class0_hp);
pre_last_prob = MAX_PROB - pre_nmv_prob->class0_hp;
cur_last_prob = MAX_PROB - cur_nmv_prob->class0_hp;
diff += (int )nmv_count->class0_hp[1] * (pre_last_prob - cur_last_prob);
// hp
diff += (int )nmv_count->hp[0] * (pre_nmv_prob->hp - cur_nmv_prob->hp);
pre_last_prob = MAX_PROB - pre_nmv_prob->hp;
cur_last_prob = MAX_PROB - cur_nmv_prob->hp;
diff += (int )nmv_count->hp[1] * (pre_last_prob - cur_last_prob);
}
return -diff;
}
#endif // !CONFIG_REALTIME_ONLY
// Test for whether to calculate metrics for the frame.
static int is_psnr_calc_enabled(const VP9_COMP *cpi) {
const VP9_COMMON *const cm = &cpi->common;
const VP9EncoderConfig *const oxcf = &cpi->oxcf;
return cpi->b_calculate_psnr && (oxcf->pass != 1) && cm->show_frame;
}
/* clang-format off */
const Vp9LevelSpec vp9_level_defs[VP9_LEVELS] = {
// sample rate size breadth bitrate cpb
{ LEVEL_1, 829440, 36864, 512, 200, 400, 2, 1, 4, 8 },
{ LEVEL_1_1, 2764800, 73728, 768, 800, 1000, 2, 1, 4, 8 },
{ LEVEL_2, 4608000, 122880, 960, 1800, 1500, 2, 1, 4, 8 },
{ LEVEL_2_1, 9216000, 245760, 1344, 3600, 2800, 2, 2, 4, 8 },
{ LEVEL_3, 20736000, 552960, 2048, 7200, 6000, 2, 4, 4, 8 },
{ LEVEL_3_1, 36864000, 983040, 2752, 12000, 10000, 2, 4, 4, 8 },
{ LEVEL_4, 83558400, 2228224, 4160, 18000, 16000, 4, 4, 4, 8 },
{ LEVEL_4_1, 160432128, 2228224, 4160, 30000, 18000, 4, 4, 5, 6 },
{ LEVEL_5, 311951360, 8912896, 8384, 60000, 36000, 6, 8, 6, 4 },
{ LEVEL_5_1, 588251136, 8912896, 8384, 120000, 46000, 8, 8, 10, 4 },
// TODO(huisu): update max_cpb_size for level 5_2 ~ 6_2 when
// they are finalized (currently tentative).
{ LEVEL_5_2, 1176502272, 8912896, 8384, 180000, 90000, 8, 8, 10, 4 },
{ LEVEL_6, 1176502272, 35651584, 16832, 180000, 90000, 8, 16, 10, 4 },
{ LEVEL_6_1, 2353004544u, 35651584, 16832, 240000, 180000, 8, 16, 10, 4 },
{ LEVEL_6_2, 4706009088u, 35651584, 16832, 480000, 360000, 8, 16, 10, 4 },
};
/* clang-format on */
static const char *level_fail_messages[TARGET_LEVEL_FAIL_IDS] = {
"The average bit-rate is too high." ,
"The picture size is too large." ,
"The picture width/height is too large." ,
"The luma sample rate is too large." ,
"The CPB size is too large." ,
"The compression ratio is too small" ,
"Too many column tiles are used." ,
"The alt-ref distance is too small." ,
"Too many reference buffers are used."
};
static INLINE void Scale2Ratio(VPX_SCALING_MODE mode, int *hr, int *hs) {
switch (mode) {
case VP8E_NORMAL:
*hr = 1;
*hs = 1;
break ;
case VP8E_FOURFIVE:
*hr = 4;
*hs = 5;
break ;
case VP8E_THREEFIVE:
*hr = 3;
*hs = 5;
break ;
default :
assert(mode == VP8E_ONETWO);
*hr = 1;
*hs = 2;
break ;
}
}
// Mark all inactive blocks as active. Other segmentation features may be set
// so memset cannot be used, instead only inactive blocks should be reset.
static void suppress_active_map(VP9_COMP *cpi) {
unsigned char *const seg_map = cpi->segmentation_map;
if (cpi->active_map.enabled || cpi->active_map.update) {
const int rows = cpi->common.mi_rows;
const int cols = cpi->common.mi_cols;
int i;
for (i = 0; i < rows * cols; ++i)
if (seg_map[i] == AM_SEGMENT_ID_INACTIVE)
seg_map[i] = AM_SEGMENT_ID_ACTIVE;
}
}
static void apply_active_map(VP9_COMP *cpi) {
struct segmentation *const seg = &cpi->common.seg;
unsigned char *const seg_map = cpi->segmentation_map;
const unsigned char *const active_map = cpi->active_map.map;
int i;
assert(AM_SEGMENT_ID_ACTIVE == CR_SEGMENT_ID_BASE);
if (frame_is_intra_only(&cpi->common)) {
cpi->active_map.enabled = 0;
cpi->active_map.update = 1;
}
if (cpi->active_map.update) {
if (cpi->active_map.enabled) {
for (i = 0; i < cpi->common.mi_rows * cpi->common.mi_cols; ++i)
if (seg_map[i] == AM_SEGMENT_ID_ACTIVE) seg_map[i] = active_map[i];
vp9_enable_segmentation(seg);
vp9_enable_segfeature(seg, AM_SEGMENT_ID_INACTIVE, SEG_LVL_SKIP);
vp9_enable_segfeature(seg, AM_SEGMENT_ID_INACTIVE, SEG_LVL_ALT_LF);
// Setting the data to -MAX_LOOP_FILTER will result in the computed loop
// filter level being zero regardless of the value of seg->abs_delta.
vp9_set_segdata(seg, AM_SEGMENT_ID_INACTIVE, SEG_LVL_ALT_LF,
-MAX_LOOP_FILTER);
} else {
vp9_disable_segfeature(seg, AM_SEGMENT_ID_INACTIVE, SEG_LVL_SKIP);
vp9_disable_segfeature(seg, AM_SEGMENT_ID_INACTIVE, SEG_LVL_ALT_LF);
if (seg->enabled) {
seg->update_data = 1;
seg->update_map = 1;
}
}
cpi->active_map.update = 0;
}
}
static void apply_roi_map(VP9_COMP *cpi) {
VP9_COMMON *cm = &cpi->common;
struct segmentation *const seg = &cm->seg;
vpx_roi_map_t *roi = &cpi->roi;
const int *delta_q = roi->delta_q;
const int *delta_lf = roi->delta_lf;
const int *skip = roi->skip;
int ref_frame[8];
int internal_delta_q[MAX_SEGMENTS];
int i;
// TODO(jianj): Investigate why ROI not working in speed < 5 or in non
// realtime mode.
if (cpi->oxcf.mode != REALTIME || cpi->oxcf.speed < 5) return ;
if (!roi->enabled) return ;
memcpy(&ref_frame, roi->ref_frame, sizeof (ref_frame));
vp9_enable_segmentation(seg);
vp9_clearall_segfeatures(seg);
// Select delta coding method;
seg->abs_delta = SEGMENT_DELTADATA;
memcpy(cpi->segmentation_map, roi->roi_map, (cm->mi_rows * cm->mi_cols));
for (i = 0; i < MAX_SEGMENTS; ++i) {
// Translate the external delta q values to internal values.
internal_delta_q[i] = vp9_quantizer_to_qindex(abs(delta_q[i]));
if (delta_q[i] < 0) internal_delta_q[i] = -internal_delta_q[i];
vp9_disable_segfeature(seg, i, SEG_LVL_ALT_Q);
vp9_disable_segfeature(seg, i, SEG_LVL_ALT_LF);
if (internal_delta_q[i] != 0) {
vp9_enable_segfeature(seg, i, SEG_LVL_ALT_Q);
vp9_set_segdata(seg, i, SEG_LVL_ALT_Q, internal_delta_q[i]);
}
if (delta_lf[i] != 0) {
vp9_enable_segfeature(seg, i, SEG_LVL_ALT_LF);
vp9_set_segdata(seg, i, SEG_LVL_ALT_LF, delta_lf[i]);
}
if (skip[i] != 0) {
vp9_enable_segfeature(seg, i, SEG_LVL_SKIP);
vp9_set_segdata(seg, i, SEG_LVL_SKIP, 0);
}
if (ref_frame[i] >= 0) {
int valid_ref = 1;
// ALTREF is not used as reference for nonrd_pickmode with 0 lag.
if (ref_frame[i] == ALTREF_FRAME && cpi->sf.use_nonrd_pick_mode)
valid_ref = 0;
// If GOLDEN is selected, make sure it's set as reference.
if (ref_frame[i] == GOLDEN_FRAME &&
!(cpi->ref_frame_flags & ref_frame_to_flag(ref_frame[i]))) {
valid_ref = 0;
}
// GOLDEN was updated in previous encoded frame, so GOLDEN and LAST are
// same reference.
if (ref_frame[i] == GOLDEN_FRAME && cpi->rc.frames_since_golden == 0)
ref_frame[i] = LAST_FRAME;
if (valid_ref) {
vp9_enable_segfeature(seg, i, SEG_LVL_REF_FRAME);
vp9_set_segdata(seg, i, SEG_LVL_REF_FRAME, ref_frame[i]);
}
}
}
roi->enabled = 1;
}
static void init_level_info(Vp9LevelInfo *level_info) {
Vp9LevelStats *const level_stats = &level_info->level_stats;
Vp9LevelSpec *const level_spec = &level_info->level_spec;
memset(level_stats, 0, sizeof (*level_stats));
memset(level_spec, 0, sizeof (*level_spec));
level_spec->level = LEVEL_UNKNOWN;
level_spec->min_altref_distance = INT_MAX;
}
static int check_seg_range(int seg_data[8], int range) {
int i;
for (i = 0; i < 8; ++i) {
// Note abs() alone can't be used as the behavior of abs(INT_MIN) is
// undefined.
if (seg_data[i] > range || seg_data[i] < -range) {
return 0;
}
}
return 1;
}
VP9_LEVEL vp9_get_level(const Vp9LevelSpec *const level_spec) {
int i;
const Vp9LevelSpec *this_level;
vpx_clear_system_state();
for (i = 0; i < VP9_LEVELS; ++i) {
this_level = &vp9_level_defs[i];
if ((double )level_spec->max_luma_sample_rate >
(double )this_level->max_luma_sample_rate *
(1 + SAMPLE_RATE_GRACE_P) ||
level_spec->max_luma_picture_size > this_level->max_luma_picture_size ||
level_spec->max_luma_picture_breadth >
this_level->max_luma_picture_breadth ||
level_spec->average_bitrate > this_level->average_bitrate ||
level_spec->max_cpb_size > this_level->max_cpb_size ||
level_spec->compression_ratio < this_level->compression_ratio ||
level_spec->max_col_tiles > this_level->max_col_tiles ||
level_spec->min_altref_distance < this_level->min_altref_distance ||
level_spec->max_ref_frame_buffers > this_level->max_ref_frame_buffers)
continue ;
break ;
}
return (i == VP9_LEVELS) ? LEVEL_UNKNOWN : vp9_level_defs[i].level;
}
vpx_codec_err_t vp9_set_roi_map(VP9_COMP *cpi, unsigned char *map,
unsigned int rows, unsigned int cols,
int delta_q[8], int delta_lf[8], int skip[8],
int ref_frame[8]) {
VP9_COMMON *cm = &cpi->common;
vpx_roi_map_t *roi = &cpi->roi;
const int range = 63;
const int ref_frame_range = 3; // Alt-ref
const int skip_range = 1;
const int frame_rows = cpi->common.mi_rows;
const int frame_cols = cpi->common.mi_cols;
// Check number of rows and columns match
if (frame_rows != (int )rows || frame_cols != (int )cols) {
return VPX_CODEC_INVALID_PARAM;
}
if (!check_seg_range(delta_q, range) || !check_seg_range(delta_lf, range) ||
!check_seg_range(ref_frame, ref_frame_range) ||
!check_seg_range(skip, skip_range))
return VPX_CODEC_INVALID_PARAM;
// Also disable segmentation if no deltas are specified.
if (!map ||
(!(delta_q[0] | delta_q[1] | delta_q[2] | delta_q[3] | delta_q[4] |
delta_q[5] | delta_q[6] | delta_q[7] | delta_lf[0] | delta_lf[1] |
delta_lf[2] | delta_lf[3] | delta_lf[4] | delta_lf[5] | delta_lf[6] |
delta_lf[7] | skip[0] | skip[1] | skip[2] | skip[3] | skip[4] |
skip[5] | skip[6] | skip[7]) &&
(ref_frame[0] == -1 && ref_frame[1] == -1 && ref_frame[2] == -1 &&
ref_frame[3] == -1 && ref_frame[4] == -1 && ref_frame[5] == -1 &&
ref_frame[6] == -1 && ref_frame[7] == -1))) {
vp9_disable_segmentation(&cm->seg);
cpi->roi.enabled = 0;
return VPX_CODEC_OK;
}
if (roi->roi_map) {
vpx_free(roi->roi_map);
roi->roi_map = NULL;
}
roi->roi_map = vpx_malloc(rows * cols);
if (!roi->roi_map) return VPX_CODEC_MEM_ERROR;
// Copy to ROI structure in the compressor.
memcpy(roi->roi_map, map, rows * cols);
memcpy(&roi->delta_q, delta_q, MAX_SEGMENTS * sizeof (delta_q[0]));
memcpy(&roi->delta_lf, delta_lf, MAX_SEGMENTS * sizeof (delta_lf[0]));
memcpy(&roi->skip, skip, MAX_SEGMENTS * sizeof (skip[0]));
memcpy(&roi->ref_frame, ref_frame, MAX_SEGMENTS * sizeof (ref_frame[0]));
roi->enabled = 1;
roi->rows = rows;
roi->cols = cols;
return VPX_CODEC_OK;
}
int vp9_set_active_map(VP9_COMP *cpi, unsigned char *new_map_16x16, int rows,
int cols) {
if (rows == cpi->common.mb_rows && cols == cpi->common.mb_cols) {
unsigned char *const active_map_8x8 = cpi->active_map.map;
const int mi_rows = cpi->common.mi_rows;
const int mi_cols = cpi->common.mi_cols;
cpi->active_map.update = 1;
if (new_map_16x16) {
int r, c;
for (r = 0; r < mi_rows; ++r) {
for (c = 0; c < mi_cols; ++c) {
active_map_8x8[r * mi_cols + c] =
new_map_16x16[(r >> 1) * cols + (c >> 1)]
? AM_SEGMENT_ID_ACTIVE
: AM_SEGMENT_ID_INACTIVE;
}
}
cpi->active_map.enabled = 1;
} else {
cpi->active_map.enabled = 0;
}
return 0;
} else {
return -1;
}
}
int vp9_get_active_map(VP9_COMP *cpi, unsigned char *new_map_16x16, int rows,
int cols) {
if (rows == cpi->common.mb_rows && cols == cpi->common.mb_cols &&
new_map_16x16) {
unsigned char *const seg_map_8x8 = cpi->segmentation_map;
const int mi_rows = cpi->common.mi_rows;
const int mi_cols = cpi->common.mi_cols;
memset(new_map_16x16, !cpi->active_map.enabled, rows * cols);
if (cpi->active_map.enabled) {
int r, c;
for (r = 0; r < mi_rows; ++r) {
for (c = 0; c < mi_cols; ++c) {
// Cyclic refresh segments are considered active despite not having
// AM_SEGMENT_ID_ACTIVE
new_map_16x16[(r >> 1) * cols + (c >> 1)] |=
seg_map_8x8[r * mi_cols + c] != AM_SEGMENT_ID_INACTIVE;
}
}
}
return 0;
} else {
return -1;
}
}
void vp9_set_high_precision_mv(VP9_COMP *cpi, int allow_high_precision_mv) {
MACROBLOCK *const mb = &cpi->td.mb;
cpi->common.allow_high_precision_mv = allow_high_precision_mv;
if (cpi->common.allow_high_precision_mv) {
mb->mvcost = mb->nmvcost_hp;
mb->mvsadcost = mb->nmvsadcost_hp;
} else {
mb->mvcost = mb->nmvcost;
mb->mvsadcost = mb->nmvsadcost;
}
}
static void setup_frame(VP9_COMP *cpi) {
VP9_COMMON *const cm = &cpi->common;
// Set up entropy context depending on frame type. The decoder mandates
// the use of the default context, index 0, for keyframes and inter
// frames where the error_resilient_mode or intra_only flag is set. For
// other inter-frames the encoder currently uses only two contexts;
// context 1 for ALTREF frames and context 0 for the others.
if (frame_is_intra_only(cm) || cm->error_resilient_mode) {
vp9_setup_past_independence(cm);
} else {
if (!cpi->use_svc) cm->frame_context_idx = cpi->refresh_alt_ref_frame;
}
// TODO(jingning): Overwrite the frame_context_idx index in multi-layer ARF
// case. Need some further investigation on if we could apply this to single
// layer ARF case as well.
if (cpi->multi_layer_arf && !cpi->use_svc) {
GF_GROUP *const gf_group = &cpi->twopass.gf_group;
const int gf_group_index = gf_group->index;
const int boost_frame =
!cpi->rc.is_src_frame_alt_ref &&
(cpi->refresh_golden_frame || cpi->refresh_alt_ref_frame);
// frame_context_idx Frame Type
// 0 Intra only frame, base layer ARF
// 1 ARFs with layer depth = 2,3
// 2 ARFs with layer depth > 3
// 3 Non-boosted frames
if (frame_is_intra_only(cm)) {
cm->frame_context_idx = 0;
} else if (boost_frame) {
if (gf_group->rf_level[gf_group_index] == GF_ARF_STD)
cm->frame_context_idx = 0;
else if (gf_group->layer_depth[gf_group_index] <= 3)
cm->frame_context_idx = 1;
else
cm->frame_context_idx = 2;
} else {
cm->frame_context_idx = 3;
}
}
if (cm->frame_type == KEY_FRAME) {
cpi->refresh_golden_frame = 1;
cpi->refresh_alt_ref_frame = 1;
vp9_zero(cpi->interp_filter_selected);
} else {
*cm->fc = cm->frame_contexts[cm->frame_context_idx];
vp9_zero(cpi->interp_filter_selected[0]);
}
}
static void vp9_enc_setup_mi(VP9_COMMON *cm) {
int i;
cm->mi = cm->mip + cm->mi_stride + 1;
memset(cm->mip, 0, cm->mi_stride * (cm->mi_rows + 1) * sizeof (*cm->mip));
cm->prev_mi = cm->prev_mip + cm->mi_stride + 1;
// Clear top border row
memset(cm->prev_mip, 0, sizeof (*cm->prev_mip) * cm->mi_stride);
// Clear left border column
for (i = 1; i < cm->mi_rows + 1; ++i)
memset(&cm->prev_mip[i * cm->mi_stride], 0, sizeof (*cm->prev_mip));
cm->mi_grid_visible = cm->mi_grid_base + cm->mi_stride + 1;
cm->prev_mi_grid_visible = cm->prev_mi_grid_base + cm->mi_stride + 1;
memset(cm->mi_grid_base, 0,
cm->mi_stride * (cm->mi_rows + 1) * sizeof (*cm->mi_grid_base));
}
static int vp9_enc_alloc_mi(VP9_COMMON *cm, int mi_size) {
cm->mip = vpx_calloc(mi_size, sizeof (*cm->mip));
if (!cm->mip) return 1;
cm->prev_mip = vpx_calloc(mi_size, sizeof (*cm->prev_mip));
if (!cm->prev_mip) return 1;
cm->mi_alloc_size = mi_size;
cm->mi_grid_base =
(MODE_INFO **)vpx_calloc(mi_size, sizeof (*cm->mi_grid_base));
if (!cm->mi_grid_base) return 1;
cm->prev_mi_grid_base =
(MODE_INFO **)vpx_calloc(mi_size, sizeof (*cm->prev_mi_grid_base));
if (!cm->prev_mi_grid_base) return 1;
return 0;
}
static void vp9_enc_free_mi(VP9_COMMON *cm) {
vpx_free(cm->mip);
cm->mip = NULL;
vpx_free(cm->prev_mip);
cm->prev_mip = NULL;
vpx_free(cm->mi_grid_base);
cm->mi_grid_base = NULL;
vpx_free(cm->prev_mi_grid_base);
cm->prev_mi_grid_base = NULL;
cm->mi_alloc_size = 0;
}
static void vp9_swap_mi_and_prev_mi(VP9_COMMON *cm) {
// Current mip will be the prev_mip for the next frame.
MODE_INFO **temp_base = cm->prev_mi_grid_base;
MODE_INFO *temp = cm->prev_mip;
// Skip update prev_mi frame in show_existing_frame mode.
if (cm->show_existing_frame) return ;
cm->prev_mip = cm->mip;
cm->mip = temp;
// Update the upper left visible macroblock ptrs.
cm->mi = cm->mip + cm->mi_stride + 1;
cm->prev_mi = cm->prev_mip + cm->mi_stride + 1;
cm->prev_mi_grid_base = cm->mi_grid_base;
cm->mi_grid_base = temp_base;
cm->mi_grid_visible = cm->mi_grid_base + cm->mi_stride + 1;
cm->prev_mi_grid_visible = cm->prev_mi_grid_base + cm->mi_stride + 1;
}
static void initialize_enc(void ) {
vp9_rtcd();
vpx_dsp_rtcd();
vpx_scale_rtcd();
vp9_init_intra_predictors();
vp9_init_me_luts();
vp9_rc_init_minq_luts();
vp9_entropy_mv_init();
#if !CONFIG_REALTIME_ONLY
vp9_temporal_filter_init();
#endif
}
void vp9_initialize_enc(void ) { once(initialize_enc); }
static void dealloc_compressor_data(VP9_COMP *cpi) {
VP9_COMMON *const cm = &cpi->common;
int i;
vpx_free(cpi->mbmi_ext_base);
cpi->mbmi_ext_base = NULL;
vpx_free(cpi->tile_data);
cpi->tile_data = NULL;
vpx_free(cpi->segmentation_map);
cpi->segmentation_map = NULL;
vpx_free(cpi->coding_context.last_frame_seg_map_copy);
cpi->coding_context.last_frame_seg_map_copy = NULL;
vpx_free(cpi->nmvcosts[0]);
vpx_free(cpi->nmvcosts[1]);
cpi->nmvcosts[0] = NULL;
cpi->nmvcosts[1] = NULL;
vpx_free(cpi->nmvcosts_hp[0]);
vpx_free(cpi->nmvcosts_hp[1]);
cpi->nmvcosts_hp[0] = NULL;
cpi->nmvcosts_hp[1] = NULL;
vpx_free(cpi->nmvsadcosts[0]);
vpx_free(cpi->nmvsadcosts[1]);
cpi->nmvsadcosts[0] = NULL;
cpi->nmvsadcosts[1] = NULL;
vpx_free(cpi->nmvsadcosts_hp[0]);
vpx_free(cpi->nmvsadcosts_hp[1]);
cpi->nmvsadcosts_hp[0] = NULL;
cpi->nmvsadcosts_hp[1] = NULL;
vpx_free(cpi->skin_map);
cpi->skin_map = NULL;
vpx_free(cpi->prev_partition);
cpi->prev_partition = NULL;
vpx_free(cpi->svc.prev_partition_svc);
cpi->svc.prev_partition_svc = NULL;
vpx_free(cpi->prev_segment_id);
cpi->prev_segment_id = NULL;
vpx_free(cpi->prev_variance_low);
cpi->prev_variance_low = NULL;
vpx_free(cpi->copied_frame_cnt);
cpi->copied_frame_cnt = NULL;
vpx_free(cpi->content_state_sb_fd);
cpi->content_state_sb_fd = NULL;
vpx_free(cpi->count_arf_frame_usage);
cpi->count_arf_frame_usage = NULL;
vpx_free(cpi->count_lastgolden_frame_usage);
cpi->count_lastgolden_frame_usage = NULL;
vp9_cyclic_refresh_free(cpi->cyclic_refresh);
cpi->cyclic_refresh = NULL;
vpx_free(cpi->active_map.map);
cpi->active_map.map = NULL;
vpx_free(cpi->roi.roi_map);
cpi->roi.roi_map = NULL;
vpx_free(cpi->consec_zero_mv);
cpi->consec_zero_mv = NULL;
vpx_free(cpi->mb_wiener_variance);
cpi->mb_wiener_variance = NULL;
vpx_free(cpi->sb_mul_scale);
cpi->sb_mul_scale = NULL;
vpx_free(cpi->mi_ssim_rdmult_scaling_factors);
cpi->mi_ssim_rdmult_scaling_factors = NULL;
#if CONFIG_RATE_CTRL
if (cpi->oxcf.use_simple_encode_api) {
free_partition_info(cpi);
free_motion_vector_info(cpi);
free_fp_motion_vector_info(cpi);
free_tpl_stats_info(cpi);
}
#endif
vp9_free_ref_frame_buffers(cm->buffer_pool);
#if CONFIG_VP9_POSTPROC
vp9_free_postproc_buffers(cm);
#endif
vp9_free_context_buffers(cm);
vpx_free_frame_buffer(&cpi->last_frame_uf);
vpx_free_frame_buffer(&cpi->scaled_source);
vpx_free_frame_buffer(&cpi->scaled_last_source);
vpx_free_frame_buffer(&cpi->tf_buffer);
#ifdef ENABLE_KF_DENOISE
vpx_free_frame_buffer(&cpi->raw_unscaled_source);
vpx_free_frame_buffer(&cpi->raw_scaled_source);
#endif
vp9_lookahead_destroy(cpi->lookahead);
vpx_free(cpi->tile_tok[0][0]);
cpi->tile_tok[0][0] = 0;
vpx_free(cpi->tplist[0][0]);
cpi->tplist[0][0] = NULL;
vp9_free_pc_tree(&cpi->td);
for (i = 0; i < cpi->svc.number_spatial_layers; ++i) {
LAYER_CONTEXT *const lc = &cpi->svc.layer_context[i];
vpx_free(lc->rc_twopass_stats_in.buf);
lc->rc_twopass_stats_in.buf = NULL;
lc->rc_twopass_stats_in.sz = 0;
}
if (cpi->source_diff_var != NULL) {
vpx_free(cpi->source_diff_var);
cpi->source_diff_var = NULL;
}
for (i = 0; i < MAX_LAG_BUFFERS; ++i) {
vpx_free_frame_buffer(&cpi->svc.scaled_frames[i]);
}
memset(&cpi->svc.scaled_frames[0], 0,
MAX_LAG_BUFFERS * sizeof (cpi->svc.scaled_frames[0]));
vpx_free_frame_buffer(&cpi->svc.scaled_temp);
memset(&cpi->svc.scaled_temp, 0, sizeof (cpi->svc.scaled_temp));
vpx_free_frame_buffer(&cpi->svc.empty_frame.img);
memset(&cpi->svc.empty_frame, 0, sizeof (cpi->svc.empty_frame));
vp9_free_svc_cyclic_refresh(cpi);
}
static void save_coding_context(VP9_COMP *cpi) {
CODING_CONTEXT *const cc = &cpi->coding_context;
VP9_COMMON *cm = &cpi->common;
// Stores a snapshot of key state variables which can subsequently be
// restored with a call to vp9_restore_coding_context. These functions are
// intended for use in a re-code loop in vp9_compress_frame where the
// quantizer value is adjusted between loop iterations.
vp9_copy(cc->nmvjointcost, cpi->td.mb.nmvjointcost);
memcpy(cc->nmvcosts[0], cpi->nmvcosts[0],
MV_VALS * sizeof (*cpi->nmvcosts[0]));
memcpy(cc->nmvcosts[1], cpi->nmvcosts[1],
MV_VALS * sizeof (*cpi->nmvcosts[1]));
memcpy(cc->nmvcosts_hp[0], cpi->nmvcosts_hp[0],
MV_VALS * sizeof (*cpi->nmvcosts_hp[0]));
memcpy(cc->nmvcosts_hp[1], cpi->nmvcosts_hp[1],
MV_VALS * sizeof (*cpi->nmvcosts_hp[1]));
vp9_copy(cc->segment_pred_probs, cm->seg.pred_probs);
memcpy(cpi->coding_context.last_frame_seg_map_copy, cm->last_frame_seg_map,
(cm->mi_rows * cm->mi_cols));
vp9_copy(cc->last_ref_lf_deltas, cm->lf.last_ref_deltas);
vp9_copy(cc->last_mode_lf_deltas, cm->lf.last_mode_deltas);
cc->fc = *cm->fc;
}
static void restore_coding_context(VP9_COMP *cpi) {
CODING_CONTEXT *const cc = &cpi->coding_context;
VP9_COMMON *cm = &cpi->common;
// Restore key state variables to the snapshot state stored in the
// previous call to vp9_save_coding_context.
vp9_copy(cpi->td.mb.nmvjointcost, cc->nmvjointcost);
memcpy(cpi->nmvcosts[0], cc->nmvcosts[0], MV_VALS * sizeof (*cc->nmvcosts[0]));
memcpy(cpi->nmvcosts[1], cc->nmvcosts[1], MV_VALS * sizeof (*cc->nmvcosts[1]));
memcpy(cpi->nmvcosts_hp[0], cc->nmvcosts_hp[0],
MV_VALS * sizeof (*cc->nmvcosts_hp[0]));
memcpy(cpi->nmvcosts_hp[1], cc->nmvcosts_hp[1],
MV_VALS * sizeof (*cc->nmvcosts_hp[1]));
vp9_copy(cm->seg.pred_probs, cc->segment_pred_probs);
memcpy(cm->last_frame_seg_map, cpi->coding_context.last_frame_seg_map_copy,
(cm->mi_rows * cm->mi_cols));
vp9_copy(cm->lf.last_ref_deltas, cc->last_ref_lf_deltas);
vp9_copy(cm->lf.last_mode_deltas, cc->last_mode_lf_deltas);
*cm->fc = cc->fc;
}
#if !CONFIG_REALTIME_ONLY
static void configure_static_seg_features(VP9_COMP *cpi) {
VP9_COMMON *const cm = &cpi->common;
const RATE_CONTROL *const rc = &cpi->rc;
struct segmentation *const seg = &cm->seg;
int high_q = (int )(rc->avg_q > 48.0);
int qi_delta;
// Disable and clear down for KF
if (cm->frame_type == KEY_FRAME) {
// Clear down the global segmentation map
memset(cpi->segmentation_map, 0, cm->mi_rows * cm->mi_cols);
seg->update_map = 0;
seg->update_data = 0;
cpi->static_mb_pct = 0;
// Disable segmentation
vp9_disable_segmentation(seg);
// Clear down the segment features.
vp9_clearall_segfeatures(seg);
} else if (cpi->refresh_alt_ref_frame) {
// If this is an alt ref frame
// Clear down the global segmentation map
memset(cpi->segmentation_map, 0, cm->mi_rows * cm->mi_cols);
seg->update_map = 0;
seg->update_data = 0;
cpi->static_mb_pct = 0;
// Disable segmentation and individual segment features by default
vp9_disable_segmentation(seg);
vp9_clearall_segfeatures(seg);
// Scan frames from current to arf frame.
// This function re-enables segmentation if appropriate.
vp9_update_mbgraph_stats(cpi);
// If segmentation was enabled set those features needed for the
// arf itself.
if (seg->enabled) {
seg->update_map = 1;
seg->update_data = 1;
qi_delta =
vp9_compute_qdelta(rc, rc->avg_q, rc->avg_q * 0.875, cm->bit_depth);
vp9_set_segdata(seg, 1, SEG_LVL_ALT_Q, qi_delta - 2);
vp9_set_segdata(seg, 1, SEG_LVL_ALT_LF, -2);
vp9_enable_segfeature(seg, 1, SEG_LVL_ALT_Q);
vp9_enable_segfeature(seg, 1, SEG_LVL_ALT_LF);
// Where relevant assume segment data is delta data
seg->abs_delta = SEGMENT_DELTADATA;
}
} else if (seg->enabled) {
// All other frames if segmentation has been enabled
// First normal frame in a valid gf or alt ref group
if (rc->frames_since_golden == 0) {
// Set up segment features for normal frames in an arf group
if (rc->source_alt_ref_active) {
seg->update_map = 0;
seg->update_data = 1;
seg->abs_delta = SEGMENT_DELTADATA;
qi_delta =
vp9_compute_qdelta(rc, rc->avg_q, rc->avg_q * 1.125, cm->bit_depth);
vp9_set_segdata(seg, 1, SEG_LVL_ALT_Q, qi_delta + 2);
vp9_enable_segfeature(seg, 1, SEG_LVL_ALT_Q);
vp9_set_segdata(seg, 1, SEG_LVL_ALT_LF, -2);
vp9_enable_segfeature(seg, 1, SEG_LVL_ALT_LF);
// Segment coding disabled for compred testing
if (high_q || (cpi->static_mb_pct == 100)) {
vp9_set_segdata(seg, 1, SEG_LVL_REF_FRAME, ALTREF_FRAME);
vp9_enable_segfeature(seg, 1, SEG_LVL_REF_FRAME);
vp9_enable_segfeature(seg, 1, SEG_LVL_SKIP);
}
} else {
// Disable segmentation and clear down features if alt ref
// is not active for this group
vp9_disable_segmentation(seg);
memset(cpi->segmentation_map, 0, cm->mi_rows * cm->mi_cols);
seg->update_map = 0;
seg->update_data = 0;
vp9_clearall_segfeatures(seg);
}
} else if (rc->is_src_frame_alt_ref) {
// Special case where we are coding over the top of a previous
// alt ref frame.
// Segment coding disabled for compred testing
// Enable ref frame features for segment 0 as well
vp9_enable_segfeature(seg, 0, SEG_LVL_REF_FRAME);
vp9_enable_segfeature(seg, 1, SEG_LVL_REF_FRAME);
// All mbs should use ALTREF_FRAME
vp9_clear_segdata(seg, 0, SEG_LVL_REF_FRAME);
vp9_set_segdata(seg, 0, SEG_LVL_REF_FRAME, ALTREF_FRAME);
vp9_clear_segdata(seg, 1, SEG_LVL_REF_FRAME);
vp9_set_segdata(seg, 1, SEG_LVL_REF_FRAME, ALTREF_FRAME);
// Skip all MBs if high Q (0,0 mv and skip coeffs)
if (high_q) {
vp9_enable_segfeature(seg, 0, SEG_LVL_SKIP);
vp9_enable_segfeature(seg, 1, SEG_LVL_SKIP);
}
// Enable data update
seg->update_data = 1;
} else {
// All other frames.
// No updates.. leave things as they are.
seg->update_map = 0;
seg->update_data = 0;
}
}
}
#endif // !CONFIG_REALTIME_ONLY
static void update_reference_segmentation_map(VP9_COMP *cpi) {
VP9_COMMON *const cm = &cpi->common;
MODE_INFO **mi_8x8_ptr = cm->mi_grid_visible;
uint8_t *cache_ptr = cm->last_frame_seg_map;
int row, col;
for (row = 0; row < cm->mi_rows; row++) {
MODE_INFO **mi_8x8 = mi_8x8_ptr;
uint8_t *cache = cache_ptr;
for (col = 0; col < cm->mi_cols; col++, mi_8x8++, cache++)
cache[0] = mi_8x8[0]->segment_id;
mi_8x8_ptr += cm->mi_stride;
cache_ptr += cm->mi_cols;
}
}
static void alloc_raw_frame_buffers(VP9_COMP *cpi) {
VP9_COMMON *cm = &cpi->common;
const VP9EncoderConfig *oxcf = &cpi->oxcf;
if (!cpi->lookahead)
cpi->lookahead = vp9_lookahead_init(oxcf->width, oxcf->height,
cm->subsampling_x, cm->subsampling_y,
#if CONFIG_VP9_HIGHBITDEPTH
cm->use_highbitdepth,
#endif
oxcf->lag_in_frames);
if (!cpi->lookahead)
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
"Failed to allocate lag buffers" );
// TODO(agrange) Check if ARF is enabled and skip allocation if not.
if (vpx_realloc_frame_buffer(&cpi->tf_buffer, oxcf->width, oxcf->height,
cm->subsampling_x, cm->subsampling_y,
#if CONFIG_VP9_HIGHBITDEPTH
cm->use_highbitdepth,
#endif
VP9_ENC_BORDER_IN_PIXELS, cm->byte_alignment,
NULL, NULL, NULL))
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
"Failed to allocate temporal filter buffer" );
}
static void alloc_util_frame_buffers(VP9_COMP *cpi) {
VP9_COMMON *const cm = &cpi->common;
if (vpx_realloc_frame_buffer(&cpi->last_frame_uf, cm->width, cm->height,
cm->subsampling_x, cm->subsampling_y,
#if CONFIG_VP9_HIGHBITDEPTH
cm->use_highbitdepth,
#endif
VP9_ENC_BORDER_IN_PIXELS, cm->byte_alignment,
NULL, NULL, NULL))
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
"Failed to allocate last frame buffer" );
if (vpx_realloc_frame_buffer(&cpi->scaled_source, cm->width, cm->height,
cm->subsampling_x, cm->subsampling_y,
#if CONFIG_VP9_HIGHBITDEPTH
cm->use_highbitdepth,
#endif
VP9_ENC_BORDER_IN_PIXELS, cm->byte_alignment,
NULL, NULL, NULL))
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
"Failed to allocate scaled source buffer" );
// For 1 pass cbr: allocate scaled_frame that may be used as an intermediate
// buffer for a 2 stage down-sampling: two stages of 1:2 down-sampling for a
// target of 1/4x1/4. number_spatial_layers must be greater than 2.
if (is_one_pass_svc(cpi) && !cpi->svc.scaled_temp_is_alloc &&
cpi->svc.number_spatial_layers > 2) {
cpi->svc.scaled_temp_is_alloc = 1;
if (vpx_realloc_frame_buffer(
&cpi->svc.scaled_temp, cm->width >> 1, cm->height >> 1,
cm->subsampling_x, cm->subsampling_y,
#if CONFIG_VP9_HIGHBITDEPTH
cm->use_highbitdepth,
#endif
VP9_ENC_BORDER_IN_PIXELS, cm->byte_alignment, NULL, NULL, NULL))
vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR,
"Failed to allocate scaled_frame for svc " );
}
if (vpx_realloc_frame_buffer(&cpi->scaled_last_source, cm->width, cm->height,
cm->subsampling_x, cm->subsampling_y,
#if CONFIG_VP9_HIGHBITDEPTH
cm->use_highbitdepth,
#endif
VP9_ENC_BORDER_IN_PIXELS, cm->byte_alignment,
NULL, NULL, NULL))
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
"Failed to allocate scaled last source buffer" );
#ifdef ENABLE_KF_DENOISE
if (vpx_realloc_frame_buffer(&cpi->raw_unscaled_source, cm->width, cm->height,
cm->subsampling_x, cm->subsampling_y,
#if CONFIG_VP9_HIGHBITDEPTH
cm->use_highbitdepth,
#endif
VP9_ENC_BORDER_IN_PIXELS, cm->byte_alignment,
NULL, NULL, NULL))
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
"Failed to allocate unscaled raw source frame buffer" );
if (vpx_realloc_frame_buffer(&cpi->raw_scaled_source, cm->width, cm->height,
cm->subsampling_x, cm->subsampling_y,
#if CONFIG_VP9_HIGHBITDEPTH
cm->use_highbitdepth,
#endif
VP9_ENC_BORDER_IN_PIXELS, cm->byte_alignment,
NULL, NULL, NULL))
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
"Failed to allocate scaled raw source frame buffer" );
#endif
}
static void alloc_context_buffers_ext(VP9_COMP *cpi) {
VP9_COMMON *cm = &cpi->common;
int mi_size = cm->mi_cols * cm->mi_rows;
CHECK_MEM_ERROR(&cm->error, cpi->mbmi_ext_base,
vpx_calloc(mi_size, sizeof (*cpi->mbmi_ext_base)));
}
static void alloc_compressor_data(VP9_COMP *cpi) {
VP9_COMMON *cm = &cpi->common;
int sb_rows;
if (vp9_alloc_context_buffers(cm, cm->width, cm->height)) {
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
"Failed to allocate context buffers" );
}
alloc_context_buffers_ext(cpi);
vpx_free(cpi->tile_tok[0][0]);
{
unsigned int tokens = get_token_alloc(cm->mb_rows, cm->mb_cols);
CHECK_MEM_ERROR(&cm->error, cpi->tile_tok[0][0],
vpx_calloc(tokens, sizeof (*cpi->tile_tok[0][0])));
}
sb_rows = mi_cols_aligned_to_sb(cm->mi_rows) >> MI_BLOCK_SIZE_LOG2;
vpx_free(cpi->tplist[0][0]);
CHECK_MEM_ERROR(
&cm->error, cpi->tplist[0][0],
vpx_calloc(sb_rows * 4 * (1 << 6), sizeof (*cpi->tplist[0][0])));
vp9_setup_pc_tree(&cpi->common, &cpi->td);
}
void vp9_new_framerate(VP9_COMP *cpi, double framerate) {
cpi->framerate = framerate < 0.1 ? 30 : framerate;
vp9_rc_update_framerate(cpi);
}
static void set_tile_limits(VP9_COMP *cpi) {
VP9_COMMON *const cm = &cpi->common;
int min_log2_tile_cols, max_log2_tile_cols;
vp9_get_tile_n_bits(cm->mi_cols, &min_log2_tile_cols, &max_log2_tile_cols);
cm->log2_tile_cols =
clamp(cpi->oxcf.tile_columns, min_log2_tile_cols, max_log2_tile_cols);
cm->log2_tile_rows = cpi->oxcf.tile_rows;
if (cpi->oxcf.target_level == LEVEL_AUTO) {
const int level_tile_cols =
log_tile_cols_from_picsize_level(cpi->common.width, cpi->common.height);
if (cm->log2_tile_cols > level_tile_cols) {
cm->log2_tile_cols = VPXMAX(level_tile_cols, min_log2_tile_cols);
}
}
}
static void update_frame_size(VP9_COMP *cpi) {
VP9_COMMON *const cm = &cpi->common;
MACROBLOCKD *const xd = &cpi->td.mb.e_mbd;
vp9_set_mb_mi(cm, cm->width, cm->height);
vp9_init_context_buffers(cm);
vp9_init_macroblockd(cm, xd, NULL);
cpi->td.mb.mbmi_ext_base = cpi->mbmi_ext_base;
memset(cpi->mbmi_ext_base, 0,
cm->mi_rows * cm->mi_cols * sizeof (*cpi->mbmi_ext_base));
set_tile_limits(cpi);
}
static void init_buffer_indices(VP9_COMP *cpi) {
int ref_frame;
for (ref_frame = 0; ref_frame < REF_FRAMES; ++ref_frame)
cpi->ref_fb_idx[ref_frame] = ref_frame;
cpi->lst_fb_idx = cpi->ref_fb_idx[LAST_FRAME - 1];
cpi->gld_fb_idx = cpi->ref_fb_idx[GOLDEN_FRAME - 1];
cpi->alt_fb_idx = cpi->ref_fb_idx[ALTREF_FRAME - 1];
}
static void init_level_constraint(LevelConstraint *lc) {
lc->level_index = -1;
lc->max_cpb_size = INT_MAX;
lc->max_frame_size = INT_MAX;
lc->fail_flag = 0;
}
static void set_level_constraint(LevelConstraint *ls, int8_t level_index) {
vpx_clear_system_state();
ls->level_index = level_index;
if (level_index >= 0) {
ls->max_cpb_size = vp9_level_defs[level_index].max_cpb_size * (double )1000;
}
}
static void init_config(struct VP9_COMP *cpi, const VP9EncoderConfig *oxcf) {
VP9_COMMON *const cm = &cpi->common;
cpi->oxcf = *oxcf;
cpi->framerate = oxcf->init_framerate;
cm->profile = oxcf->profile;
cm->bit_depth = oxcf->bit_depth;
#if CONFIG_VP9_HIGHBITDEPTH
cm->use_highbitdepth = oxcf->use_highbitdepth;
#endif
cm->color_space = oxcf->color_space;
cm->color_range = oxcf->color_range;
cpi->target_level = oxcf->target_level;
cpi->keep_level_stats = oxcf->target_level != LEVEL_MAX;
set_level_constraint(&cpi->level_constraint,
get_level_index(cpi->target_level));
cm->width = oxcf->width;
cm->height = oxcf->height;
alloc_compressor_data(cpi);
cpi->svc.temporal_layering_mode = oxcf->temporal_layering_mode;
// Single thread case: use counts in common.
cpi->td.counts = &cm->counts;
// Spatial scalability.
cpi->svc.number_spatial_layers = oxcf->ss_number_layers;
// Temporal scalability.
cpi->svc.number_temporal_layers = oxcf->ts_number_layers;
if ((cpi->svc.number_temporal_layers > 1) ||
((cpi->svc.number_temporal_layers > 1 ||
cpi->svc.number_spatial_layers > 1) &&
cpi->oxcf.pass != 1)) {
vp9_init_layer_context(cpi);
}
// change includes all joint functionality
vp9_change_config(cpi, oxcf);
cpi->static_mb_pct = 0;
cpi->ref_frame_flags = 0;
init_buffer_indices(cpi);
vp9_noise_estimate_init(&cpi->noise_estimate, cm->width, cm->height);
cpi->fixed_qp_onepass = 0;
}
void vp9_check_reset_rc_flag(VP9_COMP *cpi) {
RATE_CONTROL *rc = &cpi->rc;
if (cpi->common.current_video_frame >
(unsigned int )cpi->svc.number_spatial_layers) {
if (cpi->use_svc) {
vp9_svc_check_reset_layer_rc_flag(cpi);
} else {
if (rc->avg_frame_bandwidth / 3 > (rc->last_avg_frame_bandwidth >> 1) ||
rc->avg_frame_bandwidth < (rc->last_avg_frame_bandwidth >> 1)) {
rc->rc_1_frame = 0;
rc->rc_2_frame = 0;
rc->bits_off_target = rc->optimal_buffer_level;
rc->buffer_level = rc->optimal_buffer_level;
}
}
}
}
void vp9_set_rc_buffer_sizes(VP9_COMP *cpi) {
RATE_CONTROL *rc = &cpi->rc;
const VP9EncoderConfig *oxcf = &cpi->oxcf;
const int64_t bandwidth = oxcf->target_bandwidth;
const int64_t starting = oxcf->starting_buffer_level_ms;
const int64_t optimal = oxcf->optimal_buffer_level_ms;
const int64_t maximum = oxcf->maximum_buffer_size_ms;
rc->starting_buffer_level = starting * bandwidth / 1000;
rc->optimal_buffer_level =
(optimal == 0) ? bandwidth / 8 : optimal * bandwidth / 1000;
rc->maximum_buffer_size =
(maximum == 0) ? bandwidth / 8 : maximum * bandwidth / 1000;
// Under a configuration change, where maximum_buffer_size may change,
// keep buffer level clipped to the maximum allowed buffer size.
rc->bits_off_target = VPXMIN(rc->bits_off_target, rc->maximum_buffer_size);
rc->buffer_level = VPXMIN(rc->buffer_level, rc->maximum_buffer_size);
}
#if CONFIG_VP9_HIGHBITDEPTH
#define HIGHBD_BFP(BT, SDF, SDSF, SDAF, VF, SVF, SVAF, SDX4DF, SDSX4DF) \
cpi->fn_ptr[BT].sdf = SDF; \
cpi->fn_ptr[BT].sdsf = SDSF; \
cpi->fn_ptr[BT].sdaf = SDAF; \
cpi->fn_ptr[BT].vf = VF; \
cpi->fn_ptr[BT].svf = SVF; \
cpi->fn_ptr[BT].svaf = SVAF; \
cpi->fn_ptr[BT].sdx4df = SDX4DF; \
cpi->fn_ptr[BT].sdsx4df = SDSX4DF;
#define MAKE_BFP_SAD_WRAPPER(fnname) \
static unsigned int fnname## _bits8(const uint8_t *src_ptr, \
int source_stride, \
const uint8_t *ref_ptr, int ref_stride) { \
return fnname(src_ptr, source_stride, ref_ptr, ref_stride); \
} \
static unsigned int fnname## _bits10( \
const uint8_t *src_ptr, int source_stride, const uint8_t *ref_ptr, \
int ref_stride) { \
return fnname(src_ptr, source_stride, ref_ptr, ref_stride) >> 2; \
} \
static unsigned int fnname## _bits12( \
const uint8_t *src_ptr, int source_stride, const uint8_t *ref_ptr, \
int ref_stride) { \
return fnname(src_ptr, source_stride, ref_ptr, ref_stride) >> 4; \
}
#define MAKE_BFP_SADAVG_WRAPPER(fnname) \
static unsigned int fnname## _bits8( \
const uint8_t *src_ptr, int source_stride, const uint8_t *ref_ptr, \
int ref_stride, const uint8_t *second_pred) { \
return fnname(src_ptr, source_stride, ref_ptr, ref_stride, second_pred); \
} \
static unsigned int fnname## _bits10( \
const uint8_t *src_ptr, int source_stride, const uint8_t *ref_ptr, \
int ref_stride, const uint8_t *second_pred) { \
return fnname(src_ptr, source_stride, ref_ptr, ref_stride, second_pred) >> \
2; \
} \
static unsigned int fnname## _bits12( \
const uint8_t *src_ptr, int source_stride, const uint8_t *ref_ptr, \
int ref_stride, const uint8_t *second_pred) { \
return fnname(src_ptr, source_stride, ref_ptr, ref_stride, second_pred) >> \
4; \
}
#define MAKE_BFP_SAD4D_WRAPPER(fnname) \
static void fnname## _bits8(const uint8_t *src_ptr, int source_stride, \
const uint8_t *const ref_ptr[], int ref_stride, \
unsigned int *sad_array) { \
fnname(src_ptr, source_stride, ref_ptr, ref_stride, sad_array); \
} \
static void fnname## _bits10(const uint8_t *src_ptr, int source_stride, \
const uint8_t *const ref_ptr[], int ref_stride, \
unsigned int *sad_array) { \
int i; \
fnname(src_ptr, source_stride, ref_ptr, ref_stride, sad_array); \
for (i = 0; i < 4; i++) sad_array[i] >>= 2; \
} \
static void fnname## _bits12(const uint8_t *src_ptr, int source_stride, \
const uint8_t *const ref_ptr[], int ref_stride, \
unsigned int *sad_array) { \
int i; \
fnname(src_ptr, source_stride, ref_ptr, ref_stride, sad_array); \
for (i = 0; i < 4; i++) sad_array[i] >>= 4; \
}
MAKE_BFP_SAD_WRAPPER(vpx_highbd_sad32x16)
MAKE_BFP_SAD_WRAPPER(vpx_highbd_sad_skip_32x16)
MAKE_BFP_SADAVG_WRAPPER(vpx_highbd_sad32x16_avg)
MAKE_BFP_SAD4D_WRAPPER(vpx_highbd_sad32x16x4d)
MAKE_BFP_SAD4D_WRAPPER(vpx_highbd_sad_skip_32x16x4d)
MAKE_BFP_SAD_WRAPPER(vpx_highbd_sad16x32)
MAKE_BFP_SAD_WRAPPER(vpx_highbd_sad_skip_16x32)
MAKE_BFP_SADAVG_WRAPPER(vpx_highbd_sad16x32_avg)
MAKE_BFP_SAD4D_WRAPPER(vpx_highbd_sad16x32x4d)
MAKE_BFP_SAD4D_WRAPPER(vpx_highbd_sad_skip_16x32x4d)
MAKE_BFP_SAD_WRAPPER(vpx_highbd_sad64x32)
MAKE_BFP_SAD_WRAPPER(vpx_highbd_sad_skip_64x32)
MAKE_BFP_SADAVG_WRAPPER(vpx_highbd_sad64x32_avg)
MAKE_BFP_SAD4D_WRAPPER(vpx_highbd_sad64x32x4d)
MAKE_BFP_SAD4D_WRAPPER(vpx_highbd_sad_skip_64x32x4d)
MAKE_BFP_SAD_WRAPPER(vpx_highbd_sad32x64)
MAKE_BFP_SAD_WRAPPER(vpx_highbd_sad_skip_32x64)
MAKE_BFP_SADAVG_WRAPPER(vpx_highbd_sad32x64_avg)
MAKE_BFP_SAD4D_WRAPPER(vpx_highbd_sad32x64x4d)
MAKE_BFP_SAD4D_WRAPPER(vpx_highbd_sad_skip_32x64x4d)
MAKE_BFP_SAD_WRAPPER(vpx_highbd_sad32x32)
MAKE_BFP_SAD_WRAPPER(vpx_highbd_sad_skip_32x32)
MAKE_BFP_SADAVG_WRAPPER(vpx_highbd_sad32x32_avg)
MAKE_BFP_SAD4D_WRAPPER(vpx_highbd_sad32x32x4d)
MAKE_BFP_SAD4D_WRAPPER(vpx_highbd_sad_skip_32x32x4d)
MAKE_BFP_SAD_WRAPPER(vpx_highbd_sad64x64)
MAKE_BFP_SAD_WRAPPER(vpx_highbd_sad_skip_64x64)
MAKE_BFP_SADAVG_WRAPPER(vpx_highbd_sad64x64_avg)
MAKE_BFP_SAD4D_WRAPPER(vpx_highbd_sad64x64x4d)
MAKE_BFP_SAD4D_WRAPPER(vpx_highbd_sad_skip_64x64x4d)
MAKE_BFP_SAD_WRAPPER(vpx_highbd_sad16x16)
MAKE_BFP_SAD_WRAPPER(vpx_highbd_sad_skip_16x16)
MAKE_BFP_SADAVG_WRAPPER(vpx_highbd_sad16x16_avg)
MAKE_BFP_SAD4D_WRAPPER(vpx_highbd_sad16x16x4d)
MAKE_BFP_SAD4D_WRAPPER(vpx_highbd_sad_skip_16x16x4d)
MAKE_BFP_SAD_WRAPPER(vpx_highbd_sad16x8)
MAKE_BFP_SAD_WRAPPER(vpx_highbd_sad_skip_16x8)
MAKE_BFP_SADAVG_WRAPPER(vpx_highbd_sad16x8_avg)
MAKE_BFP_SAD4D_WRAPPER(vpx_highbd_sad16x8x4d)
MAKE_BFP_SAD4D_WRAPPER(vpx_highbd_sad_skip_16x8x4d)
MAKE_BFP_SAD_WRAPPER(vpx_highbd_sad8x16)
MAKE_BFP_SAD_WRAPPER(vpx_highbd_sad_skip_8x16)
MAKE_BFP_SADAVG_WRAPPER(vpx_highbd_sad8x16_avg)
MAKE_BFP_SAD4D_WRAPPER(vpx_highbd_sad8x16x4d)
MAKE_BFP_SAD4D_WRAPPER(vpx_highbd_sad_skip_8x16x4d)
MAKE_BFP_SAD_WRAPPER(vpx_highbd_sad8x8)
MAKE_BFP_SAD_WRAPPER(vpx_highbd_sad_skip_8x8)
MAKE_BFP_SADAVG_WRAPPER(vpx_highbd_sad8x8_avg)
MAKE_BFP_SAD4D_WRAPPER(vpx_highbd_sad8x8x4d)
MAKE_BFP_SAD4D_WRAPPER(vpx_highbd_sad_skip_8x8x4d)
MAKE_BFP_SAD_WRAPPER(vpx_highbd_sad8x4)
MAKE_BFP_SAD_WRAPPER(vpx_highbd_sad_skip_8x4)
MAKE_BFP_SADAVG_WRAPPER(vpx_highbd_sad8x4_avg)
MAKE_BFP_SAD4D_WRAPPER(vpx_highbd_sad8x4x4d)
MAKE_BFP_SAD4D_WRAPPER(vpx_highbd_sad_skip_8x4x4d)
MAKE_BFP_SAD_WRAPPER(vpx_highbd_sad4x8)
MAKE_BFP_SAD_WRAPPER(vpx_highbd_sad_skip_4x8)
MAKE_BFP_SADAVG_WRAPPER(vpx_highbd_sad4x8_avg)
MAKE_BFP_SAD4D_WRAPPER(vpx_highbd_sad4x8x4d)
MAKE_BFP_SAD4D_WRAPPER(vpx_highbd_sad_skip_4x8x4d)
MAKE_BFP_SAD_WRAPPER(vpx_highbd_sad4x4)
MAKE_BFP_SAD_WRAPPER(vpx_highbd_sad_skip_4x4)
MAKE_BFP_SADAVG_WRAPPER(vpx_highbd_sad4x4_avg)
MAKE_BFP_SAD4D_WRAPPER(vpx_highbd_sad4x4x4d)
MAKE_BFP_SAD4D_WRAPPER(vpx_highbd_sad_skip_4x4x4d)
static void highbd_set_var_fns(VP9_COMP *const cpi) {
VP9_COMMON *const cm = &cpi->common;
if (cm->use_highbitdepth) {
switch (cm->bit_depth) {
case VPX_BITS_8:
HIGHBD_BFP(
BLOCK_32X16, vpx_highbd_sad32x16_bits8,
vpx_highbd_sad_skip_32x16_bits8, vpx_highbd_sad32x16_avg_bits8,
vpx_highbd_8_variance32x16, vpx_highbd_8_sub_pixel_variance32x16,
vpx_highbd_8_sub_pixel_avg_variance32x16,
vpx_highbd_sad32x16x4d_bits8, vpx_highbd_sad_skip_32x16x4d_bits8)
HIGHBD_BFP(
BLOCK_16X32, vpx_highbd_sad16x32_bits8,
vpx_highbd_sad_skip_16x32_bits8, vpx_highbd_sad16x32_avg_bits8,
vpx_highbd_8_variance16x32, vpx_highbd_8_sub_pixel_variance16x32,
vpx_highbd_8_sub_pixel_avg_variance16x32,
vpx_highbd_sad16x32x4d_bits8, vpx_highbd_sad_skip_16x32x4d_bits8)
HIGHBD_BFP(
BLOCK_64X32, vpx_highbd_sad64x32_bits8,
vpx_highbd_sad_skip_64x32_bits8, vpx_highbd_sad64x32_avg_bits8,
vpx_highbd_8_variance64x32, vpx_highbd_8_sub_pixel_variance64x32,
vpx_highbd_8_sub_pixel_avg_variance64x32,
vpx_highbd_sad64x32x4d_bits8, vpx_highbd_sad_skip_64x32x4d_bits8)
HIGHBD_BFP(
BLOCK_32X64, vpx_highbd_sad32x64_bits8,
vpx_highbd_sad_skip_32x64_bits8, vpx_highbd_sad32x64_avg_bits8,
vpx_highbd_8_variance32x64, vpx_highbd_8_sub_pixel_variance32x64,
vpx_highbd_8_sub_pixel_avg_variance32x64,
vpx_highbd_sad32x64x4d_bits8, vpx_highbd_sad_skip_32x64x4d_bits8)
HIGHBD_BFP(
BLOCK_32X32, vpx_highbd_sad32x32_bits8,
vpx_highbd_sad_skip_32x32_bits8, vpx_highbd_sad32x32_avg_bits8,
vpx_highbd_8_variance32x32, vpx_highbd_8_sub_pixel_variance32x32,
vpx_highbd_8_sub_pixel_avg_variance32x32,
vpx_highbd_sad32x32x4d_bits8, vpx_highbd_sad_skip_32x32x4d_bits8)
HIGHBD_BFP(
BLOCK_64X64, vpx_highbd_sad64x64_bits8,
vpx_highbd_sad_skip_64x64_bits8, vpx_highbd_sad64x64_avg_bits8,
vpx_highbd_8_variance64x64, vpx_highbd_8_sub_pixel_variance64x64,
vpx_highbd_8_sub_pixel_avg_variance64x64,
vpx_highbd_sad64x64x4d_bits8, vpx_highbd_sad_skip_64x64x4d_bits8)
HIGHBD_BFP(
BLOCK_16X16, vpx_highbd_sad16x16_bits8,
vpx_highbd_sad_skip_16x16_bits8, vpx_highbd_sad16x16_avg_bits8,
vpx_highbd_8_variance16x16, vpx_highbd_8_sub_pixel_variance16x16,
vpx_highbd_8_sub_pixel_avg_variance16x16,
vpx_highbd_sad16x16x4d_bits8, vpx_highbd_sad_skip_16x16x4d_bits8)
HIGHBD_BFP(
BLOCK_16X8, vpx_highbd_sad16x8_bits8,
vpx_highbd_sad_skip_16x8_bits8, vpx_highbd_sad16x8_avg_bits8,
vpx_highbd_8_variance16x8, vpx_highbd_8_sub_pixel_variance16x8,
vpx_highbd_8_sub_pixel_avg_variance16x8,
vpx_highbd_sad16x8x4d_bits8, vpx_highbd_sad_skip_16x8x4d_bits8)
HIGHBD_BFP(
BLOCK_8X16, vpx_highbd_sad8x16_bits8,
vpx_highbd_sad_skip_8x16_bits8, vpx_highbd_sad8x16_avg_bits8,
vpx_highbd_8_variance8x16, vpx_highbd_8_sub_pixel_variance8x16,
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5 C=91 H=83 G=86
¤ Dauer der Verarbeitung: 0.19 Sekunden
(vorverarbeitet)
¤
*© Formatika GbR, Deutschland