mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-12 10:17:31 +09:00
aom: update libaom to 0ec86ac7ae1e32a7e70410fa4972a655ec3670a4
This commit is contained in:
parent
bc3f20e378
commit
eb361970c5
438 changed files with 52661 additions and 21905 deletions
4
third_party/aom/av1/encoder/aq_complexity.c
vendored
4
third_party/aom/av1/encoder/aq_complexity.c
vendored
|
|
@ -93,7 +93,7 @@ void av1_setup_in_frame_q_adj(AV1_COMP *cpi) {
|
|||
if (segment == DEFAULT_AQ2_SEG) continue;
|
||||
|
||||
qindex_delta = av1_compute_qdelta_by_rate(
|
||||
&cpi->rc, cm->frame_type, cm->base_qindex,
|
||||
&cpi->rc, cm->current_frame.frame_type, cm->base_qindex,
|
||||
aq_c_q_adj_factor[aq_strength][segment], cm->seq_params.bit_depth);
|
||||
|
||||
// For AQ complexity mode, we dont allow Q0 in a segment if the base
|
||||
|
|
@ -148,7 +148,7 @@ void av1_caq_select_segment(const AV1_COMP *cpi, MACROBLOCK *mb, BLOCK_SIZE bs,
|
|||
? AOMMAX(exp(cpi->twopass.mb_av_energy), MIN_DEFAULT_LV_THRESH)
|
||||
: DEFAULT_LV_THRESH;
|
||||
|
||||
av1_setup_src_planes(mb, cpi->source, mi_row, mi_col, num_planes);
|
||||
av1_setup_src_planes(mb, cpi->source, mi_row, mi_col, num_planes, bs);
|
||||
logvar = av1_log_block_var(cpi, mb, bs);
|
||||
|
||||
segment = AQ_C_SEGMENTS - 1; // Just in case no break out below.
|
||||
|
|
|
|||
25
third_party/aom/av1/encoder/aq_cyclicrefresh.c
vendored
25
third_party/aom/av1/encoder/aq_cyclicrefresh.c
vendored
|
|
@ -140,8 +140,8 @@ static int compute_deltaq(const AV1_COMP *cpi, int q, double rate_factor) {
|
|||
const CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
|
||||
const RATE_CONTROL *const rc = &cpi->rc;
|
||||
int deltaq =
|
||||
av1_compute_qdelta_by_rate(rc, cpi->common.frame_type, q, rate_factor,
|
||||
cpi->common.seq_params.bit_depth);
|
||||
av1_compute_qdelta_by_rate(rc, cpi->common.current_frame.frame_type, q,
|
||||
rate_factor, cpi->common.seq_params.bit_depth);
|
||||
if ((-deltaq) > cr->max_qdelta_perc * q / 100) {
|
||||
deltaq = -cr->max_qdelta_perc * q / 100;
|
||||
}
|
||||
|
|
@ -166,15 +166,15 @@ int av1_cyclic_refresh_estimate_bits_at_q(const AV1_COMP *cpi,
|
|||
// Take segment weighted average for estimated bits.
|
||||
estimated_bits =
|
||||
(int)((1.0 - weight_segment1 - weight_segment2) *
|
||||
av1_estimate_bits_at_q(cm->frame_type, cm->base_qindex, mbs,
|
||||
correction_factor,
|
||||
av1_estimate_bits_at_q(cm->current_frame.frame_type,
|
||||
cm->base_qindex, mbs, correction_factor,
|
||||
cm->seq_params.bit_depth) +
|
||||
weight_segment1 * av1_estimate_bits_at_q(
|
||||
cm->frame_type,
|
||||
cm->current_frame.frame_type,
|
||||
cm->base_qindex + cr->qindex_delta[1], mbs,
|
||||
correction_factor, cm->seq_params.bit_depth) +
|
||||
weight_segment2 * av1_estimate_bits_at_q(
|
||||
cm->frame_type,
|
||||
cm->current_frame.frame_type,
|
||||
cm->base_qindex + cr->qindex_delta[2], mbs,
|
||||
correction_factor, cm->seq_params.bit_depth));
|
||||
return estimated_bits;
|
||||
|
|
@ -203,10 +203,11 @@ int av1_cyclic_refresh_rc_bits_per_mb(const AV1_COMP *cpi, int i,
|
|||
// Take segment weighted average for bits per mb.
|
||||
bits_per_mb =
|
||||
(int)((1.0 - weight_segment) *
|
||||
av1_rc_bits_per_mb(cm->frame_type, i, correction_factor,
|
||||
av1_rc_bits_per_mb(cm->current_frame.frame_type, i,
|
||||
correction_factor,
|
||||
cm->seq_params.bit_depth) +
|
||||
weight_segment * av1_rc_bits_per_mb(cm->frame_type, i + deltaq,
|
||||
correction_factor,
|
||||
weight_segment * av1_rc_bits_per_mb(cm->current_frame.frame_type,
|
||||
i + deltaq, correction_factor,
|
||||
cm->seq_params.bit_depth));
|
||||
return bits_per_mb;
|
||||
}
|
||||
|
|
@ -496,14 +497,14 @@ void av1_cyclic_refresh_setup(AV1_COMP *const cpi) {
|
|||
av1_disable_segmentation(seg);
|
||||
return;
|
||||
}
|
||||
if (cm->current_video_frame == 0) cr->low_content_avg = 0.0;
|
||||
if (cm->current_frame.frame_number == 0) cr->low_content_avg = 0.0;
|
||||
// Don't apply refresh on key frame or enhancement layer frames.
|
||||
if (!apply_cyclic_refresh || cm->frame_type == KEY_FRAME) {
|
||||
if (!apply_cyclic_refresh || cm->current_frame.frame_type == KEY_FRAME) {
|
||||
// Set segmentation map to 0 and disable.
|
||||
unsigned char *const seg_map = cpi->segmentation_map;
|
||||
memset(seg_map, 0, cm->mi_rows * cm->mi_cols);
|
||||
av1_disable_segmentation(&cm->seg);
|
||||
if (cm->frame_type == KEY_FRAME) {
|
||||
if (cm->current_frame.frame_type == KEY_FRAME) {
|
||||
memset(cr->last_coded_q_map, MAXQ,
|
||||
cm->mi_rows * cm->mi_cols * sizeof(*cr->last_coded_q_map));
|
||||
cr->sb_index = 0;
|
||||
|
|
|
|||
14
third_party/aom/av1/encoder/aq_variance.c
vendored
14
third_party/aom/av1/encoder/aq_variance.c
vendored
|
|
@ -77,8 +77,8 @@ void av1_vaq_frame_setup(AV1_COMP *cpi) {
|
|||
// Set up avg segment id to be 1.0 and adjust the other segments around
|
||||
// it.
|
||||
int qindex_delta = av1_compute_qdelta_by_rate(
|
||||
&cpi->rc, cm->frame_type, cm->base_qindex, rate_ratio[i] / avg_ratio,
|
||||
cm->seq_params.bit_depth);
|
||||
&cpi->rc, cm->current_frame.frame_type, cm->base_qindex,
|
||||
rate_ratio[i] / avg_ratio, cm->seq_params.bit_depth);
|
||||
|
||||
// We don't allow qindex 0 in a segment if the base value is not 0.
|
||||
// Q index 0 (lossless) implies 4x4 encoding only and in AQ mode a segment
|
||||
|
|
@ -121,7 +121,7 @@ int av1_log_block_var(const AV1_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bs) {
|
|||
|
||||
for (i = 0; i < bh; i += 4) {
|
||||
for (j = 0; j < bw; j += 4) {
|
||||
if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) {
|
||||
if (is_cur_buf_hbd(xd)) {
|
||||
var +=
|
||||
log(1.0 + cpi->fn_ptr[BLOCK_4X4].vf(
|
||||
x->plane[0].src.buf + i * x->plane[0].src.stride + j,
|
||||
|
|
@ -147,13 +147,13 @@ int av1_log_block_var(const AV1_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bs) {
|
|||
|
||||
#define DEFAULT_E_MIDPOINT 10.0
|
||||
|
||||
unsigned int haar_ac_energy(MACROBLOCK *x, BLOCK_SIZE bs) {
|
||||
static unsigned int haar_ac_energy(MACROBLOCK *x, BLOCK_SIZE bs) {
|
||||
MACROBLOCKD *xd = &x->e_mbd;
|
||||
int stride = x->plane[0].src.stride;
|
||||
uint8_t *buf = x->plane[0].src.buf;
|
||||
const int bw = MI_SIZE * mi_size_wide[bs];
|
||||
const int bh = MI_SIZE * mi_size_high[bs];
|
||||
int hbd = xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH;
|
||||
const int hbd = is_cur_buf_hbd(xd);
|
||||
|
||||
int var = 0;
|
||||
for (int r = 0; r < bh; r += 8)
|
||||
|
|
@ -192,8 +192,8 @@ int av1_compute_deltaq_from_energy_level(const AV1_COMP *const cpi,
|
|||
rate_level = block_var_level;
|
||||
}
|
||||
int qindex_delta = av1_compute_qdelta_by_rate(
|
||||
&cpi->rc, cm->frame_type, cm->base_qindex, deltaq_rate_ratio[rate_level],
|
||||
cm->seq_params.bit_depth);
|
||||
&cpi->rc, cm->current_frame.frame_type, cm->base_qindex,
|
||||
deltaq_rate_ratio[rate_level], cm->seq_params.bit_depth);
|
||||
|
||||
if ((cm->base_qindex != 0) && ((cm->base_qindex + qindex_delta) == 0)) {
|
||||
qindex_delta = -cm->base_qindex + 1;
|
||||
|
|
|
|||
12
third_party/aom/av1/encoder/av1_fwd_txfm2d.c
vendored
12
third_party/aom/av1/encoder/av1_fwd_txfm2d.c
vendored
|
|
@ -364,8 +364,6 @@ static const int8_t fadst4_range_mult2[7] = { 0, 2, 4, 3, 3, 3, 3 };
|
|||
static const int8_t fadst8_range_mult2[8] = { 0, 0, 1, 3, 3, 5, 5, 5 };
|
||||
static const int8_t fadst16_range_mult2[10] = { 0, 0, 1, 3, 3, 5, 5, 7, 7, 7 };
|
||||
|
||||
static const int8_t max_fwd_range_mult2_col[5] = { 3, 5, 7, 9, 11 };
|
||||
|
||||
static const int8_t fidtx4_range_mult2[1] = { 1 };
|
||||
static const int8_t fidtx8_range_mult2[1] = { 2 };
|
||||
static const int8_t fidtx16_range_mult2[1] = { 3 };
|
||||
|
|
@ -389,14 +387,12 @@ const int8_t *fwd_txfm_range_mult2_list[TXFM_TYPES] = {
|
|||
};
|
||||
|
||||
static INLINE void set_fwd_txfm_non_scale_range(TXFM_2D_FLIP_CFG *cfg) {
|
||||
const int txh_idx = get_txh_idx(cfg->tx_size);
|
||||
av1_zero(cfg->stage_range_col);
|
||||
av1_zero(cfg->stage_range_row);
|
||||
|
||||
const int8_t *range_mult2_col = fwd_txfm_range_mult2_list[cfg->txfm_type_col];
|
||||
if (cfg->txfm_type_col != TXFM_TYPE_INVALID) {
|
||||
int stage_num_col = cfg->stage_num_col;
|
||||
const int8_t *range_mult2_col =
|
||||
fwd_txfm_range_mult2_list[cfg->txfm_type_col];
|
||||
for (int i = 0; i < stage_num_col; ++i)
|
||||
cfg->stage_range_col[i] = (range_mult2_col[i] + 1) >> 1;
|
||||
}
|
||||
|
|
@ -405,9 +401,11 @@ static INLINE void set_fwd_txfm_non_scale_range(TXFM_2D_FLIP_CFG *cfg) {
|
|||
int stage_num_row = cfg->stage_num_row;
|
||||
const int8_t *range_mult2_row =
|
||||
fwd_txfm_range_mult2_list[cfg->txfm_type_row];
|
||||
for (int i = 0; i < stage_num_row; ++i)
|
||||
for (int i = 0; i < stage_num_row; ++i) {
|
||||
cfg->stage_range_row[i] =
|
||||
(max_fwd_range_mult2_col[txh_idx] + range_mult2_row[i] + 1) >> 1;
|
||||
(range_mult2_col[cfg->stage_num_col - 1] + range_mult2_row[i] + 1) >>
|
||||
1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
70
third_party/aom/av1/encoder/av1_multi_thread.c
vendored
Normal file
70
third_party/aom/av1/encoder/av1_multi_thread.c
vendored
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "av1/encoder/encoder.h"
|
||||
#include "av1/encoder/ethread.h"
|
||||
#include "av1/encoder/av1_multi_thread.h"
|
||||
|
||||
void av1_row_mt_mem_alloc(AV1_COMP *cpi, int max_sb_rows) {
|
||||
struct AV1Common *cm = &cpi->common;
|
||||
MultiThreadHandle *multi_thread_ctxt = &cpi->multi_thread_ctxt;
|
||||
int tile_row, tile_col;
|
||||
const int tile_cols = cm->tile_cols;
|
||||
const int tile_rows = cm->tile_rows;
|
||||
|
||||
multi_thread_ctxt->allocated_tile_cols = tile_cols;
|
||||
multi_thread_ctxt->allocated_tile_rows = tile_rows;
|
||||
multi_thread_ctxt->allocated_sb_rows = max_sb_rows;
|
||||
|
||||
// Allocate memory for row based multi-threading
|
||||
for (tile_row = 0; tile_row < multi_thread_ctxt->allocated_tile_rows;
|
||||
tile_row++) {
|
||||
for (tile_col = 0; tile_col < multi_thread_ctxt->allocated_tile_cols;
|
||||
tile_col++) {
|
||||
TileDataEnc *this_tile =
|
||||
&cpi->tile_data[tile_row * multi_thread_ctxt->allocated_tile_cols +
|
||||
tile_col];
|
||||
av1_row_mt_sync_mem_alloc(&this_tile->row_mt_sync, cm, max_sb_rows);
|
||||
if (cpi->oxcf.cdf_update_mode)
|
||||
CHECK_MEM_ERROR(
|
||||
cm, this_tile->row_ctx,
|
||||
(FRAME_CONTEXT *)aom_memalign(
|
||||
16,
|
||||
AOMMAX(1, (av1_get_sb_cols_in_tile(cm, this_tile->tile_info) -
|
||||
1)) *
|
||||
sizeof(*this_tile->row_ctx)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void av1_row_mt_mem_dealloc(AV1_COMP *cpi) {
|
||||
MultiThreadHandle *multi_thread_ctxt = &cpi->multi_thread_ctxt;
|
||||
int tile_col;
|
||||
int tile_row;
|
||||
|
||||
// Free row based multi-threading sync memory
|
||||
for (tile_row = 0; tile_row < multi_thread_ctxt->allocated_tile_rows;
|
||||
tile_row++) {
|
||||
for (tile_col = 0; tile_col < multi_thread_ctxt->allocated_tile_cols;
|
||||
tile_col++) {
|
||||
TileDataEnc *this_tile =
|
||||
&cpi->tile_data[tile_row * multi_thread_ctxt->allocated_tile_cols +
|
||||
tile_col];
|
||||
av1_row_mt_sync_mem_dealloc(&this_tile->row_mt_sync);
|
||||
if (cpi->oxcf.cdf_update_mode) aom_free(this_tile->row_ctx);
|
||||
}
|
||||
}
|
||||
multi_thread_ctxt->allocated_sb_rows = 0;
|
||||
multi_thread_ctxt->allocated_tile_cols = 0;
|
||||
multi_thread_ctxt->allocated_tile_rows = 0;
|
||||
}
|
||||
21
third_party/aom/av1/encoder/av1_multi_thread.h
vendored
Normal file
21
third_party/aom/av1/encoder/av1_multi_thread.h
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#ifndef AV1_ENCODER_AV1_MULTI_THREAD_H
|
||||
#define AV1_ENCODER_AV1_MULTI_THREAD_H
|
||||
|
||||
#include "av1/encoder/encoder.h"
|
||||
|
||||
void av1_row_mt_mem_alloc(AV1_COMP *cpi, int max_sb_rows);
|
||||
|
||||
void av1_row_mt_mem_dealloc(AV1_COMP *cpi);
|
||||
|
||||
#endif // AV1_ENCODER_AV1_MULTI_THREAD_H
|
||||
233
third_party/aom/av1/encoder/av1_quantize.c
vendored
233
third_party/aom/av1/encoder/av1_quantize.c
vendored
|
|
@ -41,47 +41,37 @@ static void quantize_fp_helper_c(
|
|||
const int16_t *scan, const int16_t *iscan, const qm_val_t *qm_ptr,
|
||||
const qm_val_t *iqm_ptr, int log_scale) {
|
||||
int i, eob = -1;
|
||||
const int rounding[2] = { ROUND_POWER_OF_TWO(round_ptr[0], log_scale),
|
||||
ROUND_POWER_OF_TWO(round_ptr[1], log_scale) };
|
||||
// TODO(jingning) Decide the need of these arguments after the
|
||||
// quantization process is completed.
|
||||
(void)zbin_ptr;
|
||||
(void)quant_shift_ptr;
|
||||
(void)iscan;
|
||||
|
||||
memset(qcoeff_ptr, 0, n_coeffs * sizeof(*qcoeff_ptr));
|
||||
memset(dqcoeff_ptr, 0, n_coeffs * sizeof(*dqcoeff_ptr));
|
||||
|
||||
if (qm_ptr == NULL && iqm_ptr == NULL) {
|
||||
const int rounding0 = ROUND_POWER_OF_TWO(round_ptr[0], log_scale);
|
||||
{ // rc == 0
|
||||
const int coeff = coeff_ptr[0];
|
||||
for (i = 0; i < n_coeffs; i++) {
|
||||
const int rc = scan[i];
|
||||
const int32_t thresh = (int32_t)(dequant_ptr[rc != 0]);
|
||||
const int coeff = coeff_ptr[rc];
|
||||
const int coeff_sign = (coeff >> 31);
|
||||
int64_t abs_coeff = (coeff ^ coeff_sign) - coeff_sign;
|
||||
if ((abs_coeff << (1 + log_scale)) >= (int32_t)(dequant_ptr[0])) {
|
||||
abs_coeff = clamp64(abs_coeff + rounding0, INT16_MIN, INT16_MAX);
|
||||
const int tmp32 = (int)((abs_coeff * quant_ptr[0]) >> (16 - log_scale));
|
||||
int tmp32 = 0;
|
||||
if ((abs_coeff << (1 + log_scale)) >= thresh) {
|
||||
abs_coeff =
|
||||
clamp64(abs_coeff + rounding[rc != 0], INT16_MIN, INT16_MAX);
|
||||
tmp32 = (int)((abs_coeff * quant_ptr[rc != 0]) >> (16 - log_scale));
|
||||
if (tmp32) {
|
||||
qcoeff_ptr[0] = (tmp32 ^ coeff_sign) - coeff_sign;
|
||||
const tran_low_t abs_dqcoeff = (tmp32 * dequant_ptr[0]) >> log_scale;
|
||||
dqcoeff_ptr[0] = (abs_dqcoeff ^ coeff_sign) - coeff_sign;
|
||||
eob = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
const int rounding1 = ROUND_POWER_OF_TWO(round_ptr[1], log_scale);
|
||||
const int32_t thresh1 = (int32_t)(dequant_ptr[1]);
|
||||
for (i = 1; i < n_coeffs; i++) {
|
||||
const int coeff = coeff_ptr[i];
|
||||
const int coeff_sign = (coeff >> 31);
|
||||
int64_t abs_coeff = (coeff ^ coeff_sign) - coeff_sign;
|
||||
if ((abs_coeff << (1 + log_scale)) >= thresh1) {
|
||||
abs_coeff = clamp64(abs_coeff + rounding1, INT16_MIN, INT16_MAX);
|
||||
const int tmp32 = (int)((abs_coeff * quant_ptr[1]) >> (16 - log_scale));
|
||||
if (tmp32) {
|
||||
qcoeff_ptr[i] = (tmp32 ^ coeff_sign) - coeff_sign;
|
||||
const tran_low_t abs_dqcoeff = (tmp32 * dequant_ptr[1]) >> log_scale;
|
||||
dqcoeff_ptr[i] = (abs_dqcoeff ^ coeff_sign) - coeff_sign;
|
||||
eob = AOMMAX(iscan[i], eob);
|
||||
qcoeff_ptr[rc] = (tmp32 ^ coeff_sign) - coeff_sign;
|
||||
const tran_low_t abs_dqcoeff =
|
||||
(tmp32 * dequant_ptr[rc != 0]) >> log_scale;
|
||||
dqcoeff_ptr[rc] = (abs_dqcoeff ^ coeff_sign) - coeff_sign;
|
||||
}
|
||||
}
|
||||
if (tmp32) eob = i;
|
||||
}
|
||||
} else {
|
||||
// Quantization pass: All coefficients with index >= zero_flag are
|
||||
|
|
@ -99,7 +89,7 @@ static void quantize_fp_helper_c(
|
|||
int tmp32 = 0;
|
||||
if (abs_coeff * wt >=
|
||||
(dequant_ptr[rc != 0] << (AOM_QM_BITS - (1 + log_scale)))) {
|
||||
abs_coeff += ROUND_POWER_OF_TWO(round_ptr[rc != 0], log_scale);
|
||||
abs_coeff += rounding[rc != 0];
|
||||
abs_coeff = clamp64(abs_coeff, INT16_MIN, INT16_MAX);
|
||||
tmp32 = (int)((abs_coeff * wt * quant_ptr[rc != 0]) >>
|
||||
(16 - log_scale + AOM_QM_BITS));
|
||||
|
|
@ -275,32 +265,65 @@ void av1_quantize_b_facade(const tran_low_t *coeff_ptr, intptr_t n_coeffs,
|
|||
const SCAN_ORDER *sc, const QUANT_PARAM *qparam) {
|
||||
const qm_val_t *qm_ptr = qparam->qmatrix;
|
||||
const qm_val_t *iqm_ptr = qparam->iqmatrix;
|
||||
if (qm_ptr != NULL && iqm_ptr != NULL) {
|
||||
quantize_b_helper_c(coeff_ptr, n_coeffs, p->zbin_QTX, p->round_QTX,
|
||||
p->quant_QTX, p->quant_shift_QTX, qcoeff_ptr,
|
||||
dqcoeff_ptr, p->dequant_QTX, eob_ptr, sc->scan,
|
||||
sc->iscan, qm_ptr, iqm_ptr, qparam->log_scale);
|
||||
if (qparam->use_quant_b_adapt) {
|
||||
// TODO(sarahparker) These quantize_b optimizations need SIMD
|
||||
// implementations
|
||||
if (qm_ptr != NULL && iqm_ptr != NULL) {
|
||||
quantize_b_adaptive_helper_c(
|
||||
coeff_ptr, n_coeffs, p->zbin_QTX, p->round_QTX, p->quant_QTX,
|
||||
p->quant_shift_QTX, qcoeff_ptr, dqcoeff_ptr, p->dequant_QTX, eob_ptr,
|
||||
sc->scan, sc->iscan, qm_ptr, iqm_ptr, qparam->log_scale);
|
||||
} else {
|
||||
switch (qparam->log_scale) {
|
||||
case 0:
|
||||
aom_quantize_b_adaptive_c(
|
||||
coeff_ptr, n_coeffs, p->zbin_QTX, p->round_QTX, p->quant_QTX,
|
||||
p->quant_shift_QTX, qcoeff_ptr, dqcoeff_ptr, p->dequant_QTX,
|
||||
eob_ptr, sc->scan, sc->iscan);
|
||||
break;
|
||||
case 1:
|
||||
aom_quantize_b_32x32_adaptive_c(
|
||||
coeff_ptr, n_coeffs, p->zbin_QTX, p->round_QTX, p->quant_QTX,
|
||||
p->quant_shift_QTX, qcoeff_ptr, dqcoeff_ptr, p->dequant_QTX,
|
||||
eob_ptr, sc->scan, sc->iscan);
|
||||
break;
|
||||
case 2:
|
||||
aom_quantize_b_64x64_adaptive_c(
|
||||
coeff_ptr, n_coeffs, p->zbin_QTX, p->round_QTX, p->quant_QTX,
|
||||
p->quant_shift_QTX, qcoeff_ptr, dqcoeff_ptr, p->dequant_QTX,
|
||||
eob_ptr, sc->scan, sc->iscan);
|
||||
break;
|
||||
default: assert(0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
switch (qparam->log_scale) {
|
||||
case 0:
|
||||
aom_quantize_b(coeff_ptr, n_coeffs, p->zbin_QTX, p->round_QTX,
|
||||
p->quant_QTX, p->quant_shift_QTX, qcoeff_ptr,
|
||||
dqcoeff_ptr, p->dequant_QTX, eob_ptr, sc->scan,
|
||||
sc->iscan);
|
||||
break;
|
||||
case 1:
|
||||
aom_quantize_b_32x32(coeff_ptr, n_coeffs, p->zbin_QTX, p->round_QTX,
|
||||
p->quant_QTX, p->quant_shift_QTX, qcoeff_ptr,
|
||||
dqcoeff_ptr, p->dequant_QTX, eob_ptr, sc->scan,
|
||||
sc->iscan);
|
||||
break;
|
||||
case 2:
|
||||
aom_quantize_b_64x64(coeff_ptr, n_coeffs, p->zbin_QTX, p->round_QTX,
|
||||
p->quant_QTX, p->quant_shift_QTX, qcoeff_ptr,
|
||||
dqcoeff_ptr, p->dequant_QTX, eob_ptr, sc->scan,
|
||||
sc->iscan);
|
||||
break;
|
||||
default: assert(0);
|
||||
if (qm_ptr != NULL && iqm_ptr != NULL) {
|
||||
quantize_b_helper_c(coeff_ptr, n_coeffs, p->zbin_QTX, p->round_QTX,
|
||||
p->quant_QTX, p->quant_shift_QTX, qcoeff_ptr,
|
||||
dqcoeff_ptr, p->dequant_QTX, eob_ptr, sc->scan,
|
||||
sc->iscan, qm_ptr, iqm_ptr, qparam->log_scale);
|
||||
} else {
|
||||
switch (qparam->log_scale) {
|
||||
case 0:
|
||||
aom_quantize_b(coeff_ptr, n_coeffs, p->zbin_QTX, p->round_QTX,
|
||||
p->quant_QTX, p->quant_shift_QTX, qcoeff_ptr,
|
||||
dqcoeff_ptr, p->dequant_QTX, eob_ptr, sc->scan,
|
||||
sc->iscan);
|
||||
break;
|
||||
case 1:
|
||||
aom_quantize_b_32x32(coeff_ptr, n_coeffs, p->zbin_QTX, p->round_QTX,
|
||||
p->quant_QTX, p->quant_shift_QTX, qcoeff_ptr,
|
||||
dqcoeff_ptr, p->dequant_QTX, eob_ptr, sc->scan,
|
||||
sc->iscan);
|
||||
break;
|
||||
case 2:
|
||||
aom_quantize_b_64x64(coeff_ptr, n_coeffs, p->zbin_QTX, p->round_QTX,
|
||||
p->quant_QTX, p->quant_shift_QTX, qcoeff_ptr,
|
||||
dqcoeff_ptr, p->dequant_QTX, eob_ptr, sc->scan,
|
||||
sc->iscan);
|
||||
break;
|
||||
default: assert(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -391,41 +414,81 @@ void av1_highbd_quantize_b_facade(const tran_low_t *coeff_ptr,
|
|||
const QUANT_PARAM *qparam) {
|
||||
const qm_val_t *qm_ptr = qparam->qmatrix;
|
||||
const qm_val_t *iqm_ptr = qparam->iqmatrix;
|
||||
if (qm_ptr != NULL && iqm_ptr != NULL) {
|
||||
highbd_quantize_b_helper_c(coeff_ptr, n_coeffs, p->zbin_QTX, p->round_QTX,
|
||||
p->quant_QTX, p->quant_shift_QTX, qcoeff_ptr,
|
||||
dqcoeff_ptr, p->dequant_QTX, eob_ptr, sc->scan,
|
||||
sc->iscan, qm_ptr, iqm_ptr, qparam->log_scale);
|
||||
if (qparam->use_quant_b_adapt) {
|
||||
if (qm_ptr != NULL && iqm_ptr != NULL) {
|
||||
highbd_quantize_b_adaptive_helper_c(
|
||||
coeff_ptr, n_coeffs, p->zbin_QTX, p->round_QTX, p->quant_QTX,
|
||||
p->quant_shift_QTX, qcoeff_ptr, dqcoeff_ptr, p->dequant_QTX, eob_ptr,
|
||||
sc->scan, sc->iscan, qm_ptr, iqm_ptr, qparam->log_scale);
|
||||
} else {
|
||||
switch (qparam->log_scale) {
|
||||
case 0:
|
||||
if (LIKELY(n_coeffs >= 8)) {
|
||||
aom_highbd_quantize_b_adaptive_c(
|
||||
coeff_ptr, n_coeffs, p->zbin_QTX, p->round_QTX, p->quant_QTX,
|
||||
p->quant_shift_QTX, qcoeff_ptr, dqcoeff_ptr, p->dequant_QTX,
|
||||
eob_ptr, sc->scan, sc->iscan);
|
||||
} else {
|
||||
// TODO(luoyi): Need SIMD (e.g. sse2) for smaller block size
|
||||
// quantization
|
||||
aom_highbd_quantize_b_adaptive_c(
|
||||
coeff_ptr, n_coeffs, p->zbin_QTX, p->round_QTX, p->quant_QTX,
|
||||
p->quant_shift_QTX, qcoeff_ptr, dqcoeff_ptr, p->dequant_QTX,
|
||||
eob_ptr, sc->scan, sc->iscan);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
aom_highbd_quantize_b_32x32_adaptive_c(
|
||||
coeff_ptr, n_coeffs, p->zbin_QTX, p->round_QTX, p->quant_QTX,
|
||||
p->quant_shift_QTX, qcoeff_ptr, dqcoeff_ptr, p->dequant_QTX,
|
||||
eob_ptr, sc->scan, sc->iscan);
|
||||
break;
|
||||
case 2:
|
||||
aom_highbd_quantize_b_64x64_adaptive_c(
|
||||
coeff_ptr, n_coeffs, p->zbin_QTX, p->round_QTX, p->quant_QTX,
|
||||
p->quant_shift_QTX, qcoeff_ptr, dqcoeff_ptr, p->dequant_QTX,
|
||||
eob_ptr, sc->scan, sc->iscan);
|
||||
break;
|
||||
default: assert(0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
switch (qparam->log_scale) {
|
||||
case 0:
|
||||
if (LIKELY(n_coeffs >= 8)) {
|
||||
aom_highbd_quantize_b(coeff_ptr, n_coeffs, p->zbin_QTX, p->round_QTX,
|
||||
p->quant_QTX, p->quant_shift_QTX, qcoeff_ptr,
|
||||
dqcoeff_ptr, p->dequant_QTX, eob_ptr, sc->scan,
|
||||
sc->iscan);
|
||||
} else {
|
||||
// TODO(luoyi): Need SIMD (e.g. sse2) for smaller block size
|
||||
// quantization
|
||||
aom_highbd_quantize_b_c(coeff_ptr, n_coeffs, p->zbin_QTX,
|
||||
if (qm_ptr != NULL && iqm_ptr != NULL) {
|
||||
highbd_quantize_b_helper_c(coeff_ptr, n_coeffs, p->zbin_QTX, p->round_QTX,
|
||||
p->quant_QTX, p->quant_shift_QTX, qcoeff_ptr,
|
||||
dqcoeff_ptr, p->dequant_QTX, eob_ptr, sc->scan,
|
||||
sc->iscan, qm_ptr, iqm_ptr, qparam->log_scale);
|
||||
} else {
|
||||
switch (qparam->log_scale) {
|
||||
case 0:
|
||||
if (LIKELY(n_coeffs >= 8)) {
|
||||
aom_highbd_quantize_b(coeff_ptr, n_coeffs, p->zbin_QTX,
|
||||
p->round_QTX, p->quant_QTX,
|
||||
p->quant_shift_QTX, qcoeff_ptr, dqcoeff_ptr,
|
||||
p->dequant_QTX, eob_ptr, sc->scan, sc->iscan);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
aom_highbd_quantize_b_32x32(
|
||||
coeff_ptr, n_coeffs, p->zbin_QTX, p->round_QTX, p->quant_QTX,
|
||||
p->quant_shift_QTX, qcoeff_ptr, dqcoeff_ptr, p->dequant_QTX,
|
||||
eob_ptr, sc->scan, sc->iscan);
|
||||
break;
|
||||
case 2:
|
||||
aom_highbd_quantize_b_64x64(
|
||||
coeff_ptr, n_coeffs, p->zbin_QTX, p->round_QTX, p->quant_QTX,
|
||||
p->quant_shift_QTX, qcoeff_ptr, dqcoeff_ptr, p->dequant_QTX,
|
||||
eob_ptr, sc->scan, sc->iscan);
|
||||
break;
|
||||
default: assert(0);
|
||||
} else {
|
||||
// TODO(luoyi): Need SIMD (e.g. sse2) for smaller block size
|
||||
// quantization
|
||||
aom_highbd_quantize_b_c(
|
||||
coeff_ptr, n_coeffs, p->zbin_QTX, p->round_QTX, p->quant_QTX,
|
||||
p->quant_shift_QTX, qcoeff_ptr, dqcoeff_ptr, p->dequant_QTX,
|
||||
eob_ptr, sc->scan, sc->iscan);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
aom_highbd_quantize_b_32x32(
|
||||
coeff_ptr, n_coeffs, p->zbin_QTX, p->round_QTX, p->quant_QTX,
|
||||
p->quant_shift_QTX, qcoeff_ptr, dqcoeff_ptr, p->dequant_QTX,
|
||||
eob_ptr, sc->scan, sc->iscan);
|
||||
break;
|
||||
case 2:
|
||||
aom_highbd_quantize_b_64x64(
|
||||
coeff_ptr, n_coeffs, p->zbin_QTX, p->round_QTX, p->quant_QTX,
|
||||
p->quant_shift_QTX, qcoeff_ptr, dqcoeff_ptr, p->dequant_QTX,
|
||||
eob_ptr, sc->scan, sc->iscan);
|
||||
break;
|
||||
default: assert(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -697,7 +760,7 @@ void av1_frame_init_quantizer(AV1_COMP *cpi) {
|
|||
void av1_set_quantizer(AV1_COMMON *cm, int q) {
|
||||
// quantizer has to be reinitialized with av1_init_quantizer() if any
|
||||
// delta_q changes.
|
||||
cm->base_qindex = AOMMAX(cm->delta_q_present_flag, q);
|
||||
cm->base_qindex = AOMMAX(cm->delta_q_info.delta_q_present_flag, q);
|
||||
cm->y_dc_delta_q = 0;
|
||||
cm->u_dc_delta_q = 0;
|
||||
cm->u_ac_delta_q = 0;
|
||||
|
|
|
|||
3
third_party/aom/av1/encoder/av1_quantize.h
vendored
3
third_party/aom/av1/encoder/av1_quantize.h
vendored
|
|
@ -27,6 +27,7 @@ typedef struct QUANT_PARAM {
|
|||
TX_SIZE tx_size;
|
||||
const qm_val_t *qmatrix;
|
||||
const qm_val_t *iqmatrix;
|
||||
int use_quant_b_adapt;
|
||||
} QUANT_PARAM;
|
||||
|
||||
typedef void (*AV1_QUANT_FACADE)(const tran_low_t *coeff_ptr, intptr_t n_coeffs,
|
||||
|
|
@ -67,7 +68,7 @@ typedef struct {
|
|||
|
||||
// The Dequants structure is used only for internal quantizer setup in
|
||||
// av1_quantize.c.
|
||||
// Fields are sufffixed according to whether or not they're expressed in
|
||||
// Fields are suffixed according to whether or not they're expressed in
|
||||
// the same coefficient shift/precision as TX or a fixed Q3 format.
|
||||
typedef struct {
|
||||
DECLARE_ALIGNED(16, int16_t,
|
||||
|
|
|
|||
675
third_party/aom/av1/encoder/bitstream.c
vendored
675
third_party/aom/av1/encoder/bitstream.c
vendored
File diff suppressed because it is too large
Load diff
5
third_party/aom/av1/encoder/bitstream.h
vendored
5
third_party/aom/av1/encoder/bitstream.h
vendored
|
|
@ -33,9 +33,10 @@ uint32_t write_obu_header(OBU_TYPE obu_type, int obu_extension,
|
|||
int write_uleb_obu_size(uint32_t obu_header_size, uint32_t obu_payload_size,
|
||||
uint8_t *dest);
|
||||
|
||||
int av1_pack_bitstream(AV1_COMP *const cpi, uint8_t *dest, size_t *size);
|
||||
int av1_pack_bitstream(AV1_COMP *const cpi, uint8_t *dst, size_t *size,
|
||||
int *const largest_tile_id);
|
||||
|
||||
static INLINE int av1_preserve_existing_gf(AV1_COMP *cpi) {
|
||||
static INLINE int av1_preserve_existing_gf(const AV1_COMP *const cpi) {
|
||||
// Do not swap gf and arf indices for internal overlay frames
|
||||
return cpi->rc.is_src_frame_alt_ref && !cpi->rc.is_src_frame_ext_arf;
|
||||
}
|
||||
|
|
|
|||
65
third_party/aom/av1/encoder/block.h
vendored
65
third_party/aom/av1/encoder/block.h
vendored
|
|
@ -54,10 +54,10 @@ typedef struct macroblock_plane {
|
|||
typedef struct {
|
||||
int txb_skip_cost[TXB_SKIP_CONTEXTS][2];
|
||||
int base_eob_cost[SIG_COEF_CONTEXTS_EOB][3];
|
||||
int base_cost[SIG_COEF_CONTEXTS][4];
|
||||
int base_cost[SIG_COEF_CONTEXTS][8];
|
||||
int eob_extra_cost[EOB_COEF_CONTEXTS][2];
|
||||
int dc_sign_cost[DC_SIGN_CONTEXTS][2];
|
||||
int lps_cost[LEVEL_CONTEXTS][COEFF_BASE_RANGE + 1];
|
||||
int lps_cost[LEVEL_CONTEXTS][COEFF_BASE_RANGE + 1 + COEFF_BASE_RANGE + 1];
|
||||
} LV_MAP_COEFF_COST;
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -74,16 +74,16 @@ typedef struct {
|
|||
} CB_COEFF_BUFFER;
|
||||
|
||||
typedef struct {
|
||||
int16_t mode_context[MODE_CTX_REF_FRAMES];
|
||||
// TODO(angiebird): Reduce the buffer size according to sb_type
|
||||
tran_low_t *tcoeff[MAX_MB_PLANE];
|
||||
uint16_t *eobs[MAX_MB_PLANE];
|
||||
uint8_t *txb_skip_ctx[MAX_MB_PLANE];
|
||||
int *dc_sign_ctx[MAX_MB_PLANE];
|
||||
uint8_t ref_mv_count[MODE_CTX_REF_FRAMES];
|
||||
CANDIDATE_MV ref_mv_stack[MODE_CTX_REF_FRAMES][MAX_REF_MV_STACK_SIZE];
|
||||
int_mv global_mvs[REF_FRAMES];
|
||||
int16_t compound_mode_context[MODE_CTX_REF_FRAMES];
|
||||
int16_t mode_context[MODE_CTX_REF_FRAMES];
|
||||
uint8_t ref_mv_count[MODE_CTX_REF_FRAMES];
|
||||
} MB_MODE_INFO_EXT;
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -140,6 +140,20 @@ typedef struct tx_size_rd_info_node {
|
|||
struct tx_size_rd_info_node *children[4];
|
||||
} TXB_RD_INFO_NODE;
|
||||
|
||||
// Simple translation rd state for prune_comp_search_by_single_result
|
||||
typedef struct {
|
||||
RD_STATS rd_stats;
|
||||
RD_STATS rd_stats_y;
|
||||
RD_STATS rd_stats_uv;
|
||||
uint8_t blk_skip[MAX_MIB_SIZE * MAX_MIB_SIZE];
|
||||
uint8_t skip;
|
||||
uint8_t disable_skip;
|
||||
uint8_t early_skipped;
|
||||
} SimpleRDState;
|
||||
|
||||
// 4: NEAREST, NEW, NEAR, GLOBAL
|
||||
#define SINGLE_REF_MODES ((REF_FRAMES - 1) * 4)
|
||||
|
||||
// Region size for mode decision sampling in the first pass of partition
|
||||
// search(two_pass_partition_search speed feature), in units of mi size(4).
|
||||
// Used by the mode_pruning_based_on_two_pass_partition_search speed feature.
|
||||
|
|
@ -173,6 +187,19 @@ typedef struct {
|
|||
COMPOUND_TYPE comp_type;
|
||||
} INTERPOLATION_FILTER_STATS;
|
||||
|
||||
#define MAX_COMP_RD_STATS 64
|
||||
typedef struct {
|
||||
int32_t rate[COMPOUND_TYPES];
|
||||
int64_t dist[COMPOUND_TYPES];
|
||||
int_mv mv[2];
|
||||
MV_REFERENCE_FRAME ref_frames[2];
|
||||
PREDICTION_MODE mode;
|
||||
InterpFilters filter;
|
||||
int ref_mv_idx;
|
||||
int is_global[2];
|
||||
} COMP_RD_STATS;
|
||||
|
||||
struct inter_modes_info;
|
||||
typedef struct macroblock MACROBLOCK;
|
||||
struct macroblock {
|
||||
struct macroblock_plane plane[MAX_MB_PLANE];
|
||||
|
|
@ -194,6 +221,9 @@ struct macroblock {
|
|||
INTERPOLATION_FILTER_STATS interp_filter_stats[2][MAX_INTERP_FILTER_STATS];
|
||||
int interp_filter_stats_idx[2];
|
||||
|
||||
// prune_comp_search_by_single_result (3:MAX_REF_MV_SERCH)
|
||||
SimpleRDState simple_rd_state[SINGLE_REF_MODES][3];
|
||||
|
||||
// Activate constrained coding block partition search range.
|
||||
int use_cb_search_range;
|
||||
|
||||
|
|
@ -224,12 +254,16 @@ struct macroblock {
|
|||
// for sub-8x8 blocks.
|
||||
int sadperbit4;
|
||||
int rdmult;
|
||||
int cb_rdmult;
|
||||
int mb_energy;
|
||||
int sb_energy_level;
|
||||
int *m_search_count_ptr;
|
||||
int *ex_search_count_ptr;
|
||||
|
||||
unsigned int txb_split_count;
|
||||
#if CONFIG_SPEED_STATS
|
||||
unsigned int tx_search_count;
|
||||
#endif // CONFIG_SPEED_STATS
|
||||
|
||||
// These are set to their default values at the beginning, and then adjusted
|
||||
// further in the encoding process.
|
||||
|
|
@ -241,12 +275,10 @@ struct macroblock {
|
|||
unsigned int pred_sse[REF_FRAMES];
|
||||
int pred_mv_sad[REF_FRAMES];
|
||||
|
||||
int *nmvjointcost;
|
||||
int nmv_vec_cost[MV_JOINTS];
|
||||
int *nmvcost[2];
|
||||
int *nmvcost_hp[2];
|
||||
int **mv_cost_stack;
|
||||
int **mvcost;
|
||||
|
||||
int32_t *wsrc_buf;
|
||||
int32_t *mask_buf;
|
||||
|
|
@ -258,6 +290,16 @@ struct macroblock {
|
|||
CONV_BUF_TYPE *tmp_conv_dst;
|
||||
uint8_t *tmp_obmc_bufs[2];
|
||||
|
||||
FRAME_CONTEXT *row_ctx;
|
||||
// This context will be used to update color_map_cdf pointer which would be
|
||||
// used during pack bitstream. For single thread and tile-multithreading case
|
||||
// this ponter will be same as xd->tile_ctx, but for the case of row-mt:
|
||||
// xd->tile_ctx will point to a temporary context while tile_pb_ctx will point
|
||||
// to the accurate tile context.
|
||||
FRAME_CONTEXT *tile_pb_ctx;
|
||||
|
||||
struct inter_modes_info *inter_modes_info;
|
||||
|
||||
// buffer for hash value calculation of a block
|
||||
// used only in av1_get_block_hash_value()
|
||||
// [first hash/second hash]
|
||||
|
|
@ -351,6 +393,9 @@ struct macroblock {
|
|||
// Store the second best motion vector during full-pixel motion search
|
||||
int_mv second_best_mv;
|
||||
|
||||
// Store the fractional best motion vector during sub/Qpel-pixel motion search
|
||||
int_mv fractional_best_mv[3];
|
||||
|
||||
// use default transform and skip transform type search for intra modes
|
||||
int use_default_intra_tx_type;
|
||||
// use default transform and skip transform type search for inter modes
|
||||
|
|
@ -367,6 +412,14 @@ struct macroblock {
|
|||
int tx_split_prune_flag; // Flag to skip tx split RD search.
|
||||
int recalc_luma_mc_data; // Flag to indicate recalculation of MC data during
|
||||
// interpolation filter search
|
||||
// The likelihood of an edge existing in the block (using partial Canny edge
|
||||
// detection). For reference, 556 is the value returned for a solid
|
||||
// vertical black/white edge.
|
||||
uint16_t edge_strength;
|
||||
|
||||
// [Saved stat index]
|
||||
COMP_RD_STATS comp_rd_stats[MAX_COMP_RD_STATS];
|
||||
int comp_rd_stats_idx;
|
||||
};
|
||||
|
||||
static INLINE int is_rect_tx_allowed_bsize(BLOCK_SIZE bsize) {
|
||||
|
|
|
|||
88
third_party/aom/av1/encoder/context_tree.c
vendored
88
third_party/aom/av1/encoder/context_tree.c
vendored
|
|
@ -16,8 +16,15 @@ static const BLOCK_SIZE square[MAX_SB_SIZE_LOG2 - 1] = {
|
|||
BLOCK_4X4, BLOCK_8X8, BLOCK_16X16, BLOCK_32X32, BLOCK_64X64, BLOCK_128X128,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
tran_low_t *coeff_buf[MAX_MB_PLANE];
|
||||
tran_low_t *qcoeff_buf[MAX_MB_PLANE];
|
||||
tran_low_t *dqcoeff_buf[MAX_MB_PLANE];
|
||||
} PC_TREE_SHARED_BUFFERS;
|
||||
|
||||
static void alloc_mode_context(AV1_COMMON *cm, int num_pix,
|
||||
PICK_MODE_CONTEXT *ctx) {
|
||||
PICK_MODE_CONTEXT *ctx,
|
||||
PC_TREE_SHARED_BUFFERS *shared_bufs) {
|
||||
const int num_planes = av1_num_planes(cm);
|
||||
int i;
|
||||
const int num_blk = num_pix / 16;
|
||||
|
|
@ -25,12 +32,9 @@ static void alloc_mode_context(AV1_COMMON *cm, int num_pix,
|
|||
|
||||
CHECK_MEM_ERROR(cm, ctx->blk_skip, aom_calloc(num_blk, sizeof(uint8_t)));
|
||||
for (i = 0; i < num_planes; ++i) {
|
||||
CHECK_MEM_ERROR(cm, ctx->coeff[i],
|
||||
aom_memalign(32, num_pix * sizeof(*ctx->coeff[i])));
|
||||
CHECK_MEM_ERROR(cm, ctx->qcoeff[i],
|
||||
aom_memalign(32, num_pix * sizeof(*ctx->qcoeff[i])));
|
||||
CHECK_MEM_ERROR(cm, ctx->dqcoeff[i],
|
||||
aom_memalign(32, num_pix * sizeof(*ctx->dqcoeff[i])));
|
||||
ctx->coeff[i] = shared_bufs->coeff_buf[i];
|
||||
ctx->qcoeff[i] = shared_bufs->qcoeff_buf[i];
|
||||
ctx->dqcoeff[i] = shared_bufs->dqcoeff_buf[i];
|
||||
CHECK_MEM_ERROR(cm, ctx->eobs[i],
|
||||
aom_memalign(32, num_blk * sizeof(*ctx->eobs[i])));
|
||||
CHECK_MEM_ERROR(
|
||||
|
|
@ -52,11 +56,8 @@ static void free_mode_context(PICK_MODE_CONTEXT *ctx, const int num_planes) {
|
|||
aom_free(ctx->blk_skip);
|
||||
ctx->blk_skip = 0;
|
||||
for (i = 0; i < num_planes; ++i) {
|
||||
aom_free(ctx->coeff[i]);
|
||||
ctx->coeff[i] = 0;
|
||||
aom_free(ctx->qcoeff[i]);
|
||||
ctx->qcoeff[i] = 0;
|
||||
aom_free(ctx->dqcoeff[i]);
|
||||
ctx->dqcoeff[i] = 0;
|
||||
aom_free(ctx->eobs[i]);
|
||||
ctx->eobs[i] = 0;
|
||||
|
|
@ -71,36 +72,37 @@ static void free_mode_context(PICK_MODE_CONTEXT *ctx, const int num_planes) {
|
|||
}
|
||||
|
||||
static void alloc_tree_contexts(AV1_COMMON *cm, PC_TREE *tree, int num_pix,
|
||||
int is_leaf) {
|
||||
alloc_mode_context(cm, num_pix, &tree->none);
|
||||
int is_leaf,
|
||||
PC_TREE_SHARED_BUFFERS *shared_bufs) {
|
||||
alloc_mode_context(cm, num_pix, &tree->none, shared_bufs);
|
||||
|
||||
if (is_leaf) return;
|
||||
|
||||
alloc_mode_context(cm, num_pix / 2, &tree->horizontal[0]);
|
||||
alloc_mode_context(cm, num_pix / 2, &tree->vertical[0]);
|
||||
alloc_mode_context(cm, num_pix / 2, &tree->horizontal[0], shared_bufs);
|
||||
alloc_mode_context(cm, num_pix / 2, &tree->vertical[0], shared_bufs);
|
||||
|
||||
alloc_mode_context(cm, num_pix / 2, &tree->horizontal[1]);
|
||||
alloc_mode_context(cm, num_pix / 2, &tree->vertical[1]);
|
||||
alloc_mode_context(cm, num_pix / 2, &tree->horizontal[1], shared_bufs);
|
||||
alloc_mode_context(cm, num_pix / 2, &tree->vertical[1], shared_bufs);
|
||||
|
||||
alloc_mode_context(cm, num_pix / 4, &tree->horizontala[0]);
|
||||
alloc_mode_context(cm, num_pix / 4, &tree->horizontala[1]);
|
||||
alloc_mode_context(cm, num_pix / 2, &tree->horizontala[2]);
|
||||
alloc_mode_context(cm, num_pix / 4, &tree->horizontala[0], shared_bufs);
|
||||
alloc_mode_context(cm, num_pix / 4, &tree->horizontala[1], shared_bufs);
|
||||
alloc_mode_context(cm, num_pix / 2, &tree->horizontala[2], shared_bufs);
|
||||
|
||||
alloc_mode_context(cm, num_pix / 2, &tree->horizontalb[0]);
|
||||
alloc_mode_context(cm, num_pix / 4, &tree->horizontalb[1]);
|
||||
alloc_mode_context(cm, num_pix / 4, &tree->horizontalb[2]);
|
||||
alloc_mode_context(cm, num_pix / 2, &tree->horizontalb[0], shared_bufs);
|
||||
alloc_mode_context(cm, num_pix / 4, &tree->horizontalb[1], shared_bufs);
|
||||
alloc_mode_context(cm, num_pix / 4, &tree->horizontalb[2], shared_bufs);
|
||||
|
||||
alloc_mode_context(cm, num_pix / 4, &tree->verticala[0]);
|
||||
alloc_mode_context(cm, num_pix / 4, &tree->verticala[1]);
|
||||
alloc_mode_context(cm, num_pix / 2, &tree->verticala[2]);
|
||||
alloc_mode_context(cm, num_pix / 4, &tree->verticala[0], shared_bufs);
|
||||
alloc_mode_context(cm, num_pix / 4, &tree->verticala[1], shared_bufs);
|
||||
alloc_mode_context(cm, num_pix / 2, &tree->verticala[2], shared_bufs);
|
||||
|
||||
alloc_mode_context(cm, num_pix / 2, &tree->verticalb[0]);
|
||||
alloc_mode_context(cm, num_pix / 4, &tree->verticalb[1]);
|
||||
alloc_mode_context(cm, num_pix / 4, &tree->verticalb[2]);
|
||||
alloc_mode_context(cm, num_pix / 2, &tree->verticalb[0], shared_bufs);
|
||||
alloc_mode_context(cm, num_pix / 4, &tree->verticalb[1], shared_bufs);
|
||||
alloc_mode_context(cm, num_pix / 4, &tree->verticalb[2], shared_bufs);
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
alloc_mode_context(cm, num_pix / 4, &tree->horizontal4[i]);
|
||||
alloc_mode_context(cm, num_pix / 4, &tree->vertical4[i]);
|
||||
alloc_mode_context(cm, num_pix / 4, &tree->horizontal4[i], shared_bufs);
|
||||
alloc_mode_context(cm, num_pix / 4, &tree->vertical4[i], shared_bufs);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -135,6 +137,7 @@ void av1_setup_pc_tree(AV1_COMMON *cm, ThreadData *td) {
|
|||
const int tree_nodes = tree_nodes_inc + 256 + 64 + 16 + 4 + 1;
|
||||
int pc_tree_index = 0;
|
||||
PC_TREE *this_pc;
|
||||
PC_TREE_SHARED_BUFFERS shared_bufs;
|
||||
int square_index = 1;
|
||||
int nodes;
|
||||
|
||||
|
|
@ -143,11 +146,24 @@ void av1_setup_pc_tree(AV1_COMMON *cm, ThreadData *td) {
|
|||
aom_calloc(tree_nodes, sizeof(*td->pc_tree)));
|
||||
this_pc = &td->pc_tree[0];
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
const int max_num_pix = MAX_SB_SIZE * MAX_SB_SIZE;
|
||||
CHECK_MEM_ERROR(cm, td->tree_coeff_buf[i],
|
||||
aom_memalign(32, max_num_pix * sizeof(tran_low_t)));
|
||||
CHECK_MEM_ERROR(cm, td->tree_qcoeff_buf[i],
|
||||
aom_memalign(32, max_num_pix * sizeof(tran_low_t)));
|
||||
CHECK_MEM_ERROR(cm, td->tree_dqcoeff_buf[i],
|
||||
aom_memalign(32, max_num_pix * sizeof(tran_low_t)));
|
||||
shared_bufs.coeff_buf[i] = td->tree_coeff_buf[i];
|
||||
shared_bufs.qcoeff_buf[i] = td->tree_qcoeff_buf[i];
|
||||
shared_bufs.dqcoeff_buf[i] = td->tree_dqcoeff_buf[i];
|
||||
}
|
||||
|
||||
// Sets up all the leaf nodes in the tree.
|
||||
for (pc_tree_index = 0; pc_tree_index < leaf_nodes; ++pc_tree_index) {
|
||||
PC_TREE *const tree = &td->pc_tree[pc_tree_index];
|
||||
tree->block_size = square[0];
|
||||
alloc_tree_contexts(cm, tree, 16, 1);
|
||||
alloc_tree_contexts(cm, tree, 16, 1, &shared_bufs);
|
||||
}
|
||||
|
||||
// Each node has 4 leaf nodes, fill each block_size level of the tree
|
||||
|
|
@ -155,7 +171,7 @@ void av1_setup_pc_tree(AV1_COMMON *cm, ThreadData *td) {
|
|||
for (nodes = leaf_nodes >> 2; nodes > 0; nodes >>= 2) {
|
||||
for (i = 0; i < nodes; ++i) {
|
||||
PC_TREE *const tree = &td->pc_tree[pc_tree_index];
|
||||
alloc_tree_contexts(cm, tree, 16 << (2 * square_index), 0);
|
||||
alloc_tree_contexts(cm, tree, 16 << (2 * square_index), 0, &shared_bufs);
|
||||
tree->block_size = square[square_index];
|
||||
for (j = 0; j < 4; j++) tree->split[j] = this_pc++;
|
||||
++pc_tree_index;
|
||||
|
|
@ -181,6 +197,14 @@ void av1_free_pc_tree(ThreadData *td, const int num_planes) {
|
|||
for (int i = 0; i < tree_nodes; ++i) {
|
||||
free_tree_contexts(&td->pc_tree[i], num_planes);
|
||||
}
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
aom_free(td->tree_coeff_buf[i]);
|
||||
aom_free(td->tree_qcoeff_buf[i]);
|
||||
aom_free(td->tree_dqcoeff_buf[i]);
|
||||
td->tree_coeff_buf[i] = NULL;
|
||||
td->tree_qcoeff_buf[i] = NULL;
|
||||
td->tree_dqcoeff_buf[i] = NULL;
|
||||
}
|
||||
aom_free(td->pc_tree);
|
||||
td->pc_tree = NULL;
|
||||
}
|
||||
|
|
|
|||
34
third_party/aom/av1/encoder/context_tree.h
vendored
34
third_party/aom/av1/encoder/context_tree.h
vendored
|
|
@ -23,7 +23,7 @@ struct AV1_COMP;
|
|||
struct AV1Common;
|
||||
struct ThreadData;
|
||||
|
||||
typedef enum {
|
||||
enum {
|
||||
// Search all the partition types in this plane.
|
||||
SEARCH_FULL_PLANE = 0,
|
||||
// Only search none_partition coding block.
|
||||
|
|
@ -32,12 +32,14 @@ typedef enum {
|
|||
SEARCH_SAME_PLANE = 2,
|
||||
// Skip search partition on this plane. Go split directly.
|
||||
SPLIT_PLANE = 3,
|
||||
} CB_TREE_SEARCH;
|
||||
} UENUM1BYTE(CB_TREE_SEARCH);
|
||||
|
||||
// Structure to hold snapshot of coding context during the mode picking process
|
||||
typedef struct {
|
||||
MB_MODE_INFO mic;
|
||||
MB_MODE_INFO_EXT mbmi_ext;
|
||||
int64_t dist;
|
||||
int64_t rdcost;
|
||||
uint8_t *color_index_map[2];
|
||||
uint8_t *blk_skip;
|
||||
|
||||
|
|
@ -62,30 +64,42 @@ typedef struct {
|
|||
// TODO(jingning) Use RD_COST struct here instead. This involves a boarder
|
||||
// scope of refactoring.
|
||||
int rate;
|
||||
int64_t dist;
|
||||
int64_t rdcost;
|
||||
|
||||
int rd_mode_is_ready; // Flag to indicate whether rd pick mode decision has
|
||||
// been made.
|
||||
int mode_selected;
|
||||
#if CONFIG_ONE_PASS_SVM
|
||||
// Features for one pass svm early term
|
||||
int seg_feat;
|
||||
#endif
|
||||
|
||||
// motion vector cache for adaptive motion search control in partition
|
||||
// search loop
|
||||
MV pred_mv[REF_FRAMES];
|
||||
InterpFilter pred_interp_filter;
|
||||
PARTITION_TYPE partition;
|
||||
|
||||
// Reference and prediction mode cache for ref/mode speedup
|
||||
// TODO(zoeliu@gmail.com): The values of ref_selected and mode_selected will
|
||||
// be explored for further encoder speedup, to differentiate this approach for
|
||||
// setting skip_ref_frame_mask from others. For instance, it is possible that
|
||||
// the underlying square block(s) share the same SIMPLE_TRANSLATION motion
|
||||
// mode as well as the mode of GLOBALMV, more ref/mode combos could be
|
||||
// skipped.
|
||||
MV_REFERENCE_FRAME ref_selected[2];
|
||||
} PICK_MODE_CONTEXT;
|
||||
|
||||
typedef struct {
|
||||
int64_t rdcost;
|
||||
int64_t sub_block_rdcost[4];
|
||||
int valid;
|
||||
int split;
|
||||
int skip;
|
||||
int64_t rdcost;
|
||||
int sub_block_split[4];
|
||||
int sub_block_skip[4];
|
||||
int64_t sub_block_rdcost[4];
|
||||
int skip;
|
||||
} PC_TREE_STATS;
|
||||
|
||||
typedef struct PC_TREE {
|
||||
int index;
|
||||
PARTITION_TYPE partitioning;
|
||||
BLOCK_SIZE block_size;
|
||||
PICK_MODE_CONTEXT none;
|
||||
|
|
@ -97,9 +111,11 @@ typedef struct PC_TREE {
|
|||
PICK_MODE_CONTEXT verticalb[3];
|
||||
PICK_MODE_CONTEXT horizontal4[4];
|
||||
PICK_MODE_CONTEXT vertical4[4];
|
||||
CB_TREE_SEARCH cb_search_range;
|
||||
struct PC_TREE *split[4];
|
||||
PC_TREE_STATS pc_tree_stats;
|
||||
CB_TREE_SEARCH cb_search_range;
|
||||
int index;
|
||||
MV mv_ref_fulls[REF_FRAMES];
|
||||
} PC_TREE;
|
||||
|
||||
void av1_setup_pc_tree(struct AV1Common *cm, struct ThreadData *td);
|
||||
|
|
|
|||
4
third_party/aom/av1/encoder/cost.h
vendored
4
third_party/aom/av1/encoder/cost.h
vendored
|
|
@ -30,6 +30,10 @@ extern const uint16_t av1_prob_cost[128];
|
|||
|
||||
// Calculate the cost of a symbol with probability p15 / 2^15
|
||||
static INLINE int av1_cost_symbol(aom_cdf_prob p15) {
|
||||
// p15 can be out of range [1, CDF_PROB_TOP - 1]. Clamping it, so that the
|
||||
// following cost calculation works correctly. Otherwise, if p15 =
|
||||
// CDF_PROB_TOP, shift would be -1, and "p15 << shift" would be wrong.
|
||||
p15 = (aom_cdf_prob)clamp(p15, 1, CDF_PROB_TOP - 1);
|
||||
assert(0 < p15 && p15 < CDF_PROB_TOP);
|
||||
const int shift = CDF_PROB_BITS - 1 - get_msb(p15);
|
||||
const int prob = get_prob(p15 << shift, CDF_PROB_TOP);
|
||||
|
|
|
|||
918
third_party/aom/av1/encoder/encode_strategy.c
vendored
Normal file
918
third_party/aom/av1/encoder/encode_strategy.c
vendored
Normal file
|
|
@ -0,0 +1,918 @@
|
|||
/*
|
||||
* Copyright (c) 2019, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "config/aom_config.h"
|
||||
#include "config/aom_scale_rtcd.h"
|
||||
|
||||
#include "aom/aom_codec.h"
|
||||
#include "aom/aom_encoder.h"
|
||||
|
||||
#include "aom_ports/system_state.h"
|
||||
|
||||
#if CONFIG_MISMATCH_DEBUG
|
||||
#include "aom_util/debug_util.h"
|
||||
#endif // CONFIG_MISMATCH_DEBUG
|
||||
|
||||
#include "av1/common/onyxc_int.h"
|
||||
|
||||
#include "av1/encoder/encoder.h"
|
||||
#include "av1/encoder/encode_strategy.h"
|
||||
#include "av1/encoder/firstpass.h"
|
||||
#include "av1/encoder/temporal_filter.h"
|
||||
#include "av1/encoder/tpl_model.h"
|
||||
|
||||
// Define the reference buffers that will be updated post encode.
|
||||
void av1_configure_buffer_updates(AV1_COMP *cpi, const FRAME_UPDATE_TYPE type) {
|
||||
// NOTE(weitinglin): Should we define another function to take care of
|
||||
// cpi->rc.is_$Source_Type to make this function as it is in the comment?
|
||||
|
||||
// show_existing_frame is a flag left set from the end of encoding the
|
||||
// previous frame. Alongside it, is_src_frame_alt_ref may also be left
|
||||
// set so shouldn't be cleared in this case.
|
||||
if (!cpi->common.show_existing_frame) cpi->rc.is_src_frame_alt_ref = 0;
|
||||
|
||||
cpi->rc.is_bwd_ref_frame = 0;
|
||||
cpi->rc.is_last_bipred_frame = 0;
|
||||
cpi->rc.is_bipred_frame = 0;
|
||||
cpi->rc.is_src_frame_ext_arf = 0;
|
||||
|
||||
switch (type) {
|
||||
case KF_UPDATE:
|
||||
cpi->refresh_last_frame = 1;
|
||||
cpi->refresh_golden_frame = 1;
|
||||
cpi->refresh_bwd_ref_frame = 1;
|
||||
cpi->refresh_alt2_ref_frame = 1;
|
||||
cpi->refresh_alt_ref_frame = 1;
|
||||
break;
|
||||
|
||||
case LF_UPDATE:
|
||||
cpi->refresh_last_frame = 1;
|
||||
cpi->refresh_golden_frame = 0;
|
||||
cpi->refresh_bwd_ref_frame = 0;
|
||||
cpi->refresh_alt2_ref_frame = 0;
|
||||
cpi->refresh_alt_ref_frame = 0;
|
||||
break;
|
||||
|
||||
case GF_UPDATE:
|
||||
// TODO(zoeliu): To further investigate whether 'refresh_last_frame' is
|
||||
// needed.
|
||||
cpi->refresh_last_frame = 1;
|
||||
cpi->refresh_golden_frame = 1;
|
||||
cpi->refresh_bwd_ref_frame = 0;
|
||||
cpi->refresh_alt2_ref_frame = 0;
|
||||
cpi->refresh_alt_ref_frame = 0;
|
||||
break;
|
||||
|
||||
case OVERLAY_UPDATE:
|
||||
cpi->refresh_last_frame = 0;
|
||||
cpi->refresh_golden_frame = 1;
|
||||
cpi->refresh_bwd_ref_frame = 0;
|
||||
cpi->refresh_alt2_ref_frame = 0;
|
||||
cpi->refresh_alt_ref_frame = 0;
|
||||
|
||||
cpi->rc.is_src_frame_alt_ref = 1;
|
||||
break;
|
||||
|
||||
case ARF_UPDATE:
|
||||
cpi->refresh_last_frame = 0;
|
||||
cpi->refresh_golden_frame = 0;
|
||||
// NOTE: BWDREF does not get updated along with ALTREF_FRAME.
|
||||
cpi->refresh_bwd_ref_frame = 0;
|
||||
cpi->refresh_alt2_ref_frame = 0;
|
||||
cpi->refresh_alt_ref_frame = 1;
|
||||
break;
|
||||
|
||||
case BRF_UPDATE:
|
||||
cpi->refresh_last_frame = 0;
|
||||
cpi->refresh_golden_frame = 0;
|
||||
cpi->refresh_bwd_ref_frame = 1;
|
||||
cpi->refresh_alt2_ref_frame = 0;
|
||||
cpi->refresh_alt_ref_frame = 0;
|
||||
|
||||
cpi->rc.is_bwd_ref_frame = 1;
|
||||
break;
|
||||
|
||||
case LAST_BIPRED_UPDATE:
|
||||
cpi->refresh_last_frame = 1;
|
||||
cpi->refresh_golden_frame = 0;
|
||||
cpi->refresh_bwd_ref_frame = 0;
|
||||
cpi->refresh_alt2_ref_frame = 0;
|
||||
cpi->refresh_alt_ref_frame = 0;
|
||||
|
||||
cpi->rc.is_last_bipred_frame = 1;
|
||||
break;
|
||||
|
||||
case BIPRED_UPDATE:
|
||||
cpi->refresh_last_frame = 1;
|
||||
cpi->refresh_golden_frame = 0;
|
||||
cpi->refresh_bwd_ref_frame = 0;
|
||||
cpi->refresh_alt2_ref_frame = 0;
|
||||
cpi->refresh_alt_ref_frame = 0;
|
||||
|
||||
cpi->rc.is_bipred_frame = 1;
|
||||
break;
|
||||
|
||||
case INTNL_OVERLAY_UPDATE:
|
||||
cpi->refresh_last_frame = 1;
|
||||
cpi->refresh_golden_frame = 0;
|
||||
cpi->refresh_bwd_ref_frame = 0;
|
||||
cpi->refresh_alt2_ref_frame = 0;
|
||||
cpi->refresh_alt_ref_frame = 0;
|
||||
|
||||
cpi->rc.is_src_frame_alt_ref = 1;
|
||||
cpi->rc.is_src_frame_ext_arf = 1;
|
||||
break;
|
||||
|
||||
case INTNL_ARF_UPDATE:
|
||||
cpi->refresh_last_frame = 0;
|
||||
cpi->refresh_golden_frame = 0;
|
||||
if (cpi->new_bwdref_update_rule == 1 && cpi->oxcf.pass == 2) {
|
||||
cpi->refresh_bwd_ref_frame = 1;
|
||||
cpi->refresh_alt2_ref_frame = 0;
|
||||
} else {
|
||||
cpi->refresh_bwd_ref_frame = 0;
|
||||
cpi->refresh_alt2_ref_frame = 1;
|
||||
}
|
||||
cpi->refresh_alt_ref_frame = 0;
|
||||
break;
|
||||
|
||||
default: assert(0); break;
|
||||
}
|
||||
}
|
||||
|
||||
static void set_additional_frame_flags(const AV1_COMMON *const cm,
|
||||
unsigned int *const frame_flags) {
|
||||
if (frame_is_intra_only(cm)) *frame_flags |= FRAMEFLAGS_INTRAONLY;
|
||||
if (frame_is_sframe(cm)) *frame_flags |= FRAMEFLAGS_SWITCH;
|
||||
if (cm->error_resilient_mode) *frame_flags |= FRAMEFLAGS_ERROR_RESILIENT;
|
||||
}
|
||||
|
||||
static INLINE void update_keyframe_counters(AV1_COMP *cpi) {
|
||||
// TODO(zoeliu): To investigate whether we should treat BWDREF_FRAME
|
||||
// differently here for rc->avg_frame_bandwidth.
|
||||
if (cpi->common.show_frame || cpi->rc.is_bwd_ref_frame) {
|
||||
if (!cpi->common.show_existing_frame || cpi->rc.is_src_frame_alt_ref ||
|
||||
cpi->common.current_frame.frame_type == KEY_FRAME) {
|
||||
// If this is a show_existing_frame with a source other than altref,
|
||||
// or if it is not a displayed forward keyframe, the keyframe update
|
||||
// counters were incremented when it was originally encoded.
|
||||
cpi->rc.frames_since_key++;
|
||||
cpi->rc.frames_to_key--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static INLINE int is_frame_droppable(const AV1_COMP *const cpi) {
|
||||
return !(cpi->refresh_alt_ref_frame || cpi->refresh_alt2_ref_frame ||
|
||||
cpi->refresh_bwd_ref_frame || cpi->refresh_golden_frame ||
|
||||
cpi->refresh_last_frame);
|
||||
}
|
||||
|
||||
static INLINE void update_frames_till_gf_update(AV1_COMP *cpi) {
|
||||
// TODO(weitinglin): Updating this counter for is_frame_droppable
|
||||
// is a work-around to handle the condition when a frame is drop.
|
||||
// We should fix the cpi->common.show_frame flag
|
||||
// instead of checking the other condition to update the counter properly.
|
||||
if (cpi->common.show_frame || is_frame_droppable(cpi)) {
|
||||
// Decrement count down till next gf
|
||||
if (cpi->rc.frames_till_gf_update_due > 0)
|
||||
cpi->rc.frames_till_gf_update_due--;
|
||||
}
|
||||
}
|
||||
|
||||
static INLINE void update_twopass_gf_group_index(AV1_COMP *cpi) {
|
||||
// Increment the gf group index ready for the next frame. If this is
|
||||
// a show_existing_frame with a source other than altref, or if it is not
|
||||
// a displayed forward keyframe, the index was incremented when it was
|
||||
// originally encoded.
|
||||
if (!cpi->common.show_existing_frame || cpi->rc.is_src_frame_alt_ref ||
|
||||
cpi->common.current_frame.frame_type == KEY_FRAME) {
|
||||
++cpi->twopass.gf_group.index;
|
||||
}
|
||||
}
|
||||
|
||||
static void update_rc_counts(AV1_COMP *cpi) {
|
||||
update_keyframe_counters(cpi);
|
||||
update_frames_till_gf_update(cpi);
|
||||
if (cpi->oxcf.pass == 2) update_twopass_gf_group_index(cpi);
|
||||
}
|
||||
|
||||
static void check_show_existing_frame(AV1_COMP *cpi) {
|
||||
const GF_GROUP *const gf_group = &cpi->twopass.gf_group;
|
||||
AV1_COMMON *const cm = &cpi->common;
|
||||
const FRAME_UPDATE_TYPE next_frame_update_type =
|
||||
gf_group->update_type[gf_group->index];
|
||||
const int which_arf = (cpi->new_bwdref_update_rule == 1)
|
||||
? gf_group->arf_update_idx[gf_group->index] > 0
|
||||
: gf_group->arf_update_idx[gf_group->index];
|
||||
|
||||
if (cm->show_existing_frame == 1) {
|
||||
cm->show_existing_frame = 0;
|
||||
} else if (cpi->rc.is_last_bipred_frame) {
|
||||
// NOTE: When new structure is used, every bwdref will have one overlay
|
||||
// frame. Therefore, there is no need to find out which frame to
|
||||
// show in advance.
|
||||
if (cpi->new_bwdref_update_rule == 0) {
|
||||
// NOTE: If the current frame is a last bi-predictive frame, it is
|
||||
// needed next to show the BWDREF_FRAME, which is pointed by
|
||||
// the last_fb_idxes[0] after reference frame buffer update
|
||||
cpi->rc.is_last_bipred_frame = 0;
|
||||
cm->show_existing_frame = 1;
|
||||
cpi->existing_fb_idx_to_show = cm->remapped_ref_idx[0];
|
||||
}
|
||||
} else if (cpi->is_arf_filter_off[which_arf] &&
|
||||
(next_frame_update_type == OVERLAY_UPDATE ||
|
||||
next_frame_update_type == INTNL_OVERLAY_UPDATE)) {
|
||||
const int bwdref_to_show =
|
||||
(cpi->new_bwdref_update_rule == 1) ? BWDREF_FRAME : ALTREF2_FRAME;
|
||||
// Other parameters related to OVERLAY_UPDATE will be taken care of
|
||||
// in av1_rc_get_second_pass_params(cpi)
|
||||
cm->show_existing_frame = 1;
|
||||
cpi->rc.is_src_frame_alt_ref = 1;
|
||||
cpi->existing_fb_idx_to_show =
|
||||
(next_frame_update_type == OVERLAY_UPDATE)
|
||||
? get_ref_frame_map_idx(cm, ALTREF_FRAME)
|
||||
: get_ref_frame_map_idx(cm, bwdref_to_show);
|
||||
if (cpi->new_bwdref_update_rule == 0) {
|
||||
cpi->is_arf_filter_off[which_arf] = 0;
|
||||
}
|
||||
}
|
||||
cpi->rc.is_src_frame_ext_arf = 0;
|
||||
}
|
||||
|
||||
static void set_ext_overrides(AV1_COMP *const cpi,
|
||||
EncodeFrameParams *const frame_params) {
|
||||
// Overrides the defaults with the externally supplied values with
|
||||
// av1_update_reference() and av1_update_entropy() calls
|
||||
// Note: The overrides are valid only for the next frame passed
|
||||
// to av1_encode_lowlevel()
|
||||
|
||||
AV1_COMMON *const cm = &cpi->common;
|
||||
|
||||
if (cpi->ext_use_s_frame) {
|
||||
frame_params->frame_type = S_FRAME;
|
||||
}
|
||||
|
||||
if (cpi->ext_refresh_frame_context_pending) {
|
||||
cm->refresh_frame_context = cpi->ext_refresh_frame_context;
|
||||
cpi->ext_refresh_frame_context_pending = 0;
|
||||
}
|
||||
if (cpi->ext_refresh_frame_flags_pending) {
|
||||
cpi->refresh_last_frame = cpi->ext_refresh_last_frame;
|
||||
cpi->refresh_golden_frame = cpi->ext_refresh_golden_frame;
|
||||
cpi->refresh_alt_ref_frame = cpi->ext_refresh_alt_ref_frame;
|
||||
cpi->refresh_bwd_ref_frame = cpi->ext_refresh_bwd_ref_frame;
|
||||
cpi->refresh_alt2_ref_frame = cpi->ext_refresh_alt2_ref_frame;
|
||||
cpi->ext_refresh_frame_flags_pending = 0;
|
||||
}
|
||||
cm->allow_ref_frame_mvs = cpi->ext_use_ref_frame_mvs;
|
||||
|
||||
frame_params->error_resilient_mode = cpi->ext_use_error_resilient;
|
||||
// A keyframe is already error resilient and keyframes with
|
||||
// error_resilient_mode interferes with the use of show_existing_frame
|
||||
// when forward reference keyframes are enabled.
|
||||
frame_params->error_resilient_mode &= frame_params->frame_type != KEY_FRAME;
|
||||
// For bitstream conformance, s-frames must be error-resilient
|
||||
frame_params->error_resilient_mode |= frame_params->frame_type == S_FRAME;
|
||||
}
|
||||
|
||||
static int get_ref_frame_flags(const AV1_COMP *const cpi) {
|
||||
const AV1_COMMON *const cm = &cpi->common;
|
||||
|
||||
const RefCntBuffer *last_buf = get_ref_frame_buf(cm, LAST_FRAME);
|
||||
const RefCntBuffer *last2_buf = get_ref_frame_buf(cm, LAST2_FRAME);
|
||||
const RefCntBuffer *last3_buf = get_ref_frame_buf(cm, LAST3_FRAME);
|
||||
const RefCntBuffer *golden_buf = get_ref_frame_buf(cm, GOLDEN_FRAME);
|
||||
const RefCntBuffer *bwd_buf = get_ref_frame_buf(cm, BWDREF_FRAME);
|
||||
const RefCntBuffer *alt2_buf = get_ref_frame_buf(cm, ALTREF2_FRAME);
|
||||
const RefCntBuffer *alt_buf = get_ref_frame_buf(cm, ALTREF_FRAME);
|
||||
|
||||
// No.1 Priority: LAST_FRAME
|
||||
const int last2_is_last = (last2_buf == last_buf);
|
||||
const int last3_is_last = (last3_buf == last_buf);
|
||||
const int gld_is_last = (golden_buf == last_buf);
|
||||
const int bwd_is_last = (bwd_buf == last_buf);
|
||||
const int alt2_is_last = (alt2_buf == last_buf);
|
||||
const int alt_is_last = (alt_buf == last_buf);
|
||||
|
||||
// No.2 Priority: ALTREF_FRAME
|
||||
const int last2_is_alt = (last2_buf == alt_buf);
|
||||
const int last3_is_alt = (last3_buf == alt_buf);
|
||||
const int gld_is_alt = (golden_buf == alt_buf);
|
||||
const int bwd_is_alt = (bwd_buf == alt_buf);
|
||||
const int alt2_is_alt = (alt2_buf == alt_buf);
|
||||
|
||||
// No.3 Priority: LAST2_FRAME
|
||||
const int last3_is_last2 = (last3_buf == last2_buf);
|
||||
const int gld_is_last2 = (golden_buf == last2_buf);
|
||||
const int bwd_is_last2 = (bwd_buf == last2_buf);
|
||||
const int alt2_is_last2 = (alt2_buf == last2_buf);
|
||||
|
||||
// No.4 Priority: LAST3_FRAME
|
||||
const int gld_is_last3 = (golden_buf == last3_buf);
|
||||
const int bwd_is_last3 = (bwd_buf == last3_buf);
|
||||
const int alt2_is_last3 = (alt2_buf == last3_buf);
|
||||
|
||||
// No.5 Priority: GOLDEN_FRAME
|
||||
const int bwd_is_gld = (bwd_buf == golden_buf);
|
||||
const int alt2_is_gld = (alt2_buf == golden_buf);
|
||||
|
||||
// No.6 Priority: BWDREF_FRAME
|
||||
const int alt2_is_bwd = (alt2_buf == bwd_buf);
|
||||
|
||||
// No.7 Priority: ALTREF2_FRAME
|
||||
|
||||
// cpi->ext_ref_frame_flags allows certain reference types to be disabled
|
||||
// by the external interface. These are set by av1_apply_encoding_flags().
|
||||
// Start with what the external interface allows, then suppress any reference
|
||||
// types which we have found to be duplicates.
|
||||
|
||||
int flags = cpi->ext_ref_frame_flags;
|
||||
|
||||
if (cpi->rc.frames_till_gf_update_due == INT_MAX) flags &= ~AOM_GOLD_FLAG;
|
||||
|
||||
if (alt_is_last) flags &= ~AOM_ALT_FLAG;
|
||||
|
||||
if (last2_is_last || last2_is_alt) flags &= ~AOM_LAST2_FLAG;
|
||||
|
||||
if (last3_is_last || last3_is_alt || last3_is_last2) flags &= ~AOM_LAST3_FLAG;
|
||||
|
||||
if (gld_is_last || gld_is_alt || gld_is_last2 || gld_is_last3)
|
||||
flags &= ~AOM_GOLD_FLAG;
|
||||
|
||||
if ((bwd_is_last || bwd_is_alt || bwd_is_last2 || bwd_is_last3 || bwd_is_gld))
|
||||
flags &= ~AOM_BWD_FLAG;
|
||||
|
||||
if ((alt2_is_last || alt2_is_alt || alt2_is_last2 || alt2_is_last3 ||
|
||||
alt2_is_gld || alt2_is_bwd))
|
||||
flags &= ~AOM_ALT2_FLAG;
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
static int get_current_frame_ref_type(
|
||||
const AV1_COMP *const cpi, const EncodeFrameParams *const frame_params) {
|
||||
const GF_GROUP *const gf_group = &cpi->twopass.gf_group;
|
||||
// We choose the reference "type" of this frame from the flags which indicate
|
||||
// which reference frames will be refreshed by it. More than one of these
|
||||
// flags may be set, so the order here implies an order of precedence.
|
||||
// This is just used to choose the primary_ref_frame (as the most recent
|
||||
// reference buffer of the same reference-type as the current frame)
|
||||
|
||||
const int intra_only = frame_params->frame_type == KEY_FRAME ||
|
||||
frame_params->frame_type == INTRA_ONLY_FRAME;
|
||||
if (intra_only || frame_params->error_resilient_mode ||
|
||||
cpi->ext_use_primary_ref_none)
|
||||
return REGULAR_FRAME;
|
||||
else if (gf_group->update_type[gf_group->index] == INTNL_ARF_UPDATE)
|
||||
return EXT_ARF_FRAME;
|
||||
else if (cpi->refresh_alt_ref_frame)
|
||||
return ARF_FRAME;
|
||||
else if (cpi->rc.is_src_frame_alt_ref)
|
||||
return OVERLAY_FRAME;
|
||||
else if (cpi->refresh_golden_frame)
|
||||
return GLD_FRAME;
|
||||
else if (cpi->refresh_bwd_ref_frame)
|
||||
return BRF_FRAME;
|
||||
else
|
||||
return REGULAR_FRAME;
|
||||
}
|
||||
|
||||
static int choose_primary_ref_frame(
|
||||
const AV1_COMP *const cpi, const EncodeFrameParams *const frame_params) {
|
||||
const AV1_COMMON *const cm = &cpi->common;
|
||||
|
||||
const int intra_only = frame_params->frame_type == KEY_FRAME ||
|
||||
frame_params->frame_type == INTRA_ONLY_FRAME;
|
||||
if (intra_only || frame_params->error_resilient_mode ||
|
||||
cpi->ext_use_primary_ref_none) {
|
||||
return PRIMARY_REF_NONE;
|
||||
}
|
||||
|
||||
// Find the most recent reference frame with the same reference type as the
|
||||
// current frame
|
||||
const FRAME_CONTEXT_INDEX current_ref_type =
|
||||
get_current_frame_ref_type(cpi, frame_params);
|
||||
int wanted_fb = cpi->fb_of_context_type[current_ref_type];
|
||||
|
||||
int primary_ref_frame = PRIMARY_REF_NONE;
|
||||
for (int ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ref_frame++) {
|
||||
if (get_ref_frame_map_idx(cm, ref_frame) == wanted_fb) {
|
||||
primary_ref_frame = ref_frame - LAST_FRAME;
|
||||
}
|
||||
}
|
||||
return primary_ref_frame;
|
||||
}
|
||||
|
||||
static void update_fb_of_context_type(
|
||||
const AV1_COMP *const cpi, const EncodeFrameParams *const frame_params,
|
||||
int *const fb_of_context_type) {
|
||||
const AV1_COMMON *const cm = &cpi->common;
|
||||
|
||||
if (frame_is_intra_only(cm) || cm->error_resilient_mode ||
|
||||
cpi->ext_use_primary_ref_none) {
|
||||
for (int i = 0; i < REF_FRAMES; i++) {
|
||||
fb_of_context_type[i] = -1;
|
||||
}
|
||||
fb_of_context_type[REGULAR_FRAME] =
|
||||
cm->show_frame ? get_ref_frame_map_idx(cm, GOLDEN_FRAME)
|
||||
: get_ref_frame_map_idx(cm, ALTREF_FRAME);
|
||||
}
|
||||
|
||||
if (!encode_show_existing_frame(cm)) {
|
||||
// Refresh fb_of_context_type[]: see encoder.h for explanation
|
||||
// Note that we want the value of refresh_frame_flags for the frame that
|
||||
// just happened. If we call get_refresh_frame_flags now we will get a
|
||||
// different answer, because update_reference_frames() has happened.
|
||||
if (cm->current_frame.frame_type == KEY_FRAME) {
|
||||
// All ref frames are refreshed, pick one that will live long enough
|
||||
fb_of_context_type[REGULAR_FRAME] = 0;
|
||||
} else {
|
||||
// If more than one frame is refreshed, it doesn't matter which one we
|
||||
// pick so pick the first. LST sometimes doesn't refresh any: this is ok
|
||||
const int current_frame_ref_type =
|
||||
get_current_frame_ref_type(cpi, frame_params);
|
||||
for (int i = 0; i < REF_FRAMES; i++) {
|
||||
if (cm->current_frame.refresh_frame_flags & (1 << i)) {
|
||||
fb_of_context_type[current_frame_ref_type] = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int get_order_offset(const AV1_COMP *const cpi,
|
||||
const EncodeFrameParams *const frame_params) {
|
||||
// shown frame by definition has order offset 0
|
||||
// show_existing_frame ignores order_offset and simply takes the order_hint
|
||||
// from the reference frame being shown.
|
||||
if (frame_params->show_frame || cpi->common.show_existing_frame) return 0;
|
||||
|
||||
const GF_GROUP *const gf_group = &cpi->twopass.gf_group;
|
||||
const int arf_offset =
|
||||
AOMMIN((MAX_GF_INTERVAL - 1), gf_group->arf_src_offset[gf_group->index]);
|
||||
const int brf_offset = gf_group->brf_src_offset[gf_group->index];
|
||||
return AOMMIN((MAX_GF_INTERVAL - 1), arf_offset + brf_offset);
|
||||
}
|
||||
|
||||
static void adjust_frame_rate(AV1_COMP *cpi,
|
||||
const struct lookahead_entry *source) {
|
||||
int64_t this_duration;
|
||||
int step = 0;
|
||||
|
||||
// Clear down mmx registers
|
||||
aom_clear_system_state();
|
||||
|
||||
if (source->ts_start == cpi->first_time_stamp_ever) {
|
||||
this_duration = source->ts_end - source->ts_start;
|
||||
step = 1;
|
||||
} else {
|
||||
int64_t last_duration =
|
||||
cpi->last_end_time_stamp_seen - cpi->last_time_stamp_seen;
|
||||
|
||||
this_duration = source->ts_end - cpi->last_end_time_stamp_seen;
|
||||
|
||||
// do a step update if the duration changes by 10%
|
||||
if (last_duration)
|
||||
step = (int)((this_duration - last_duration) * 10 / last_duration);
|
||||
}
|
||||
|
||||
if (this_duration) {
|
||||
if (step) {
|
||||
av1_new_framerate(cpi, 10000000.0 / this_duration);
|
||||
} else {
|
||||
// Average this frame's rate into the last second's average
|
||||
// frame rate. If we haven't seen 1 second yet, then average
|
||||
// over the whole interval seen.
|
||||
const double interval = AOMMIN(
|
||||
(double)(source->ts_end - cpi->first_time_stamp_ever), 10000000.0);
|
||||
double avg_duration = 10000000.0 / cpi->framerate;
|
||||
avg_duration *= (interval - avg_duration + this_duration);
|
||||
avg_duration /= interval;
|
||||
|
||||
av1_new_framerate(cpi, 10000000.0 / avg_duration);
|
||||
}
|
||||
}
|
||||
cpi->last_time_stamp_seen = source->ts_start;
|
||||
cpi->last_end_time_stamp_seen = source->ts_end;
|
||||
}
|
||||
|
||||
static void check_src_altref(AV1_COMP *cpi,
|
||||
const struct lookahead_entry *source) {
|
||||
RATE_CONTROL *const rc = &cpi->rc;
|
||||
|
||||
// If pass == 2, the parameters set here will be reset in
|
||||
// av1_rc_get_second_pass_params()
|
||||
|
||||
if (cpi->oxcf.pass == 2) {
|
||||
const GF_GROUP *const gf_group = &cpi->twopass.gf_group;
|
||||
rc->is_src_frame_alt_ref =
|
||||
(gf_group->update_type[gf_group->index] == INTNL_OVERLAY_UPDATE) ||
|
||||
(gf_group->update_type[gf_group->index] == OVERLAY_UPDATE);
|
||||
rc->is_src_frame_ext_arf =
|
||||
gf_group->update_type[gf_group->index] == INTNL_OVERLAY_UPDATE;
|
||||
} else {
|
||||
rc->is_src_frame_alt_ref =
|
||||
cpi->alt_ref_source && (source == cpi->alt_ref_source);
|
||||
}
|
||||
|
||||
if (rc->is_src_frame_alt_ref) {
|
||||
// Current frame is an ARF overlay frame.
|
||||
cpi->alt_ref_source = NULL;
|
||||
|
||||
if (rc->is_src_frame_ext_arf && !cpi->common.show_existing_frame) {
|
||||
// For INTNL_OVERLAY, when show_existing_frame == 0, they do need to
|
||||
// refresh the LAST_FRAME, i.e. LAST3 gets retired, LAST2 becomes LAST3,
|
||||
// LAST becomes LAST2, and INTNL_OVERLAY becomes LAST.
|
||||
cpi->refresh_last_frame = 1;
|
||||
} else {
|
||||
// Don't refresh the last buffer for an ARF overlay frame. It will
|
||||
// become the GF so preserve last as an alternative prediction option.
|
||||
cpi->refresh_last_frame = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Returns 0 if this is not an alt ref else the offset of the source frame
|
||||
// used as the arf midpoint.
|
||||
static int get_arf_src_index(AV1_COMP *cpi) {
|
||||
RATE_CONTROL *const rc = &cpi->rc;
|
||||
int arf_src_index = 0;
|
||||
if (is_altref_enabled(cpi)) {
|
||||
if (cpi->oxcf.pass == 2) {
|
||||
const GF_GROUP *const gf_group = &cpi->twopass.gf_group;
|
||||
if (gf_group->update_type[gf_group->index] == ARF_UPDATE) {
|
||||
arf_src_index = gf_group->arf_src_offset[gf_group->index];
|
||||
}
|
||||
} else if (rc->source_alt_ref_pending) {
|
||||
arf_src_index = rc->frames_till_gf_update_due;
|
||||
}
|
||||
}
|
||||
return arf_src_index;
|
||||
}
|
||||
|
||||
static int get_brf_src_index(AV1_COMP *cpi) {
|
||||
int brf_src_index = 0;
|
||||
const GF_GROUP *const gf_group = &cpi->twopass.gf_group;
|
||||
|
||||
// TODO(zoeliu): We need to add the check on the -bwd_ref command line setup
|
||||
// flag.
|
||||
if (gf_group->bidir_pred_enabled[gf_group->index]) {
|
||||
if (cpi->oxcf.pass == 2) {
|
||||
if (gf_group->update_type[gf_group->index] == BRF_UPDATE)
|
||||
brf_src_index = gf_group->brf_src_offset[gf_group->index];
|
||||
} else {
|
||||
// TODO(zoeliu): To re-visit the setup for this scenario
|
||||
brf_src_index = cpi->rc.bipred_group_interval - 1;
|
||||
}
|
||||
}
|
||||
|
||||
return brf_src_index;
|
||||
}
|
||||
|
||||
// Returns 0 if this is not an alt ref else the offset of the source frame
|
||||
// used as the arf midpoint.
|
||||
static int get_arf2_src_index(AV1_COMP *cpi) {
|
||||
int arf2_src_index = 0;
|
||||
if (is_altref_enabled(cpi) && cpi->num_extra_arfs) {
|
||||
if (cpi->oxcf.pass == 2) {
|
||||
const GF_GROUP *const gf_group = &cpi->twopass.gf_group;
|
||||
if (gf_group->update_type[gf_group->index] == INTNL_ARF_UPDATE) {
|
||||
arf2_src_index = gf_group->arf_src_offset[gf_group->index];
|
||||
}
|
||||
}
|
||||
}
|
||||
return arf2_src_index;
|
||||
}
|
||||
|
||||
// Called if this frame is an ARF or ARF2. Also handles forward-keyframes
|
||||
// For an ARF set arf2=0, for ARF2 set arf2=1
|
||||
// temporal_filtered is set to 1 if we temporally filter the ARF frame, so that
|
||||
// the correct post-filter buffer can be used.
|
||||
static struct lookahead_entry *setup_arf_or_arf2(
|
||||
AV1_COMP *const cpi, const int arf_src_index, const int arf2,
|
||||
int *temporal_filtered, EncodeFrameParams *const frame_params) {
|
||||
AV1_COMMON *const cm = &cpi->common;
|
||||
RATE_CONTROL *const rc = &cpi->rc;
|
||||
const AV1EncoderConfig *const oxcf = &cpi->oxcf;
|
||||
|
||||
assert(arf_src_index <= rc->frames_to_key);
|
||||
*temporal_filtered = 0;
|
||||
|
||||
struct lookahead_entry *source =
|
||||
av1_lookahead_peek(cpi->lookahead, arf_src_index);
|
||||
|
||||
if (source != NULL) {
|
||||
cm->showable_frame = 1;
|
||||
cpi->alt_ref_source = source;
|
||||
|
||||
// When arf_src_index == rc->frames_to_key, it indicates a fwd_kf
|
||||
if (!arf2 && arf_src_index == rc->frames_to_key) {
|
||||
// Skip temporal filtering and mark as intra_only if we have a fwd_kf
|
||||
const GF_GROUP *const gf_group = &cpi->twopass.gf_group;
|
||||
int which_arf = gf_group->arf_update_idx[gf_group->index];
|
||||
cpi->is_arf_filter_off[which_arf] = 1;
|
||||
cpi->no_show_kf = 1;
|
||||
} else {
|
||||
if (oxcf->arnr_max_frames > 0) {
|
||||
// Produce the filtered ARF frame.
|
||||
av1_temporal_filter(cpi, arf_src_index);
|
||||
aom_extend_frame_borders(&cpi->alt_ref_buffer, av1_num_planes(cm));
|
||||
*temporal_filtered = 1;
|
||||
}
|
||||
}
|
||||
frame_params->show_frame = 0;
|
||||
|
||||
if (oxcf->pass < 2) {
|
||||
// In second pass, the buffer updates configure will be set
|
||||
// in the function av1_rc_get_second_pass_params
|
||||
av1_configure_buffer_updates(cpi, arf2 ? INTNL_ARF_UPDATE : ARF_UPDATE);
|
||||
}
|
||||
}
|
||||
rc->source_alt_ref_pending = 0;
|
||||
return source;
|
||||
}
|
||||
|
||||
// Determine whether there is a forced keyframe pending in the lookahead buffer
|
||||
static int is_forced_keyframe_pending(struct lookahead_ctx *lookahead,
|
||||
const int up_to_index) {
|
||||
for (int i = 0; i <= up_to_index; i++) {
|
||||
const struct lookahead_entry *e = av1_lookahead_peek(lookahead, i);
|
||||
if (e == NULL) {
|
||||
// We have reached the end of the lookahead buffer and not early-returned
|
||||
// so there isn't a forced key-frame pending.
|
||||
return 0;
|
||||
} else if (e->flags == AOM_EFLAG_FORCE_KF) {
|
||||
return 1;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return 0; // Never reached
|
||||
}
|
||||
|
||||
// Check if we should encode an ARF, ARF2 or BRF. If not, try a LAST
|
||||
// Do some setup associated with the chosen source
|
||||
// Return the frame source, or NULL if we couldn't find one
|
||||
struct lookahead_entry *choose_frame_source(
|
||||
AV1_COMP *const cpi, int *const temporal_filtered, int *const flush,
|
||||
struct lookahead_entry **last_source,
|
||||
EncodeFrameParams *const frame_params) {
|
||||
AV1_COMMON *const cm = &cpi->common;
|
||||
struct lookahead_entry *source = NULL;
|
||||
*temporal_filtered = 0;
|
||||
|
||||
// Should we encode an alt-ref frame.
|
||||
int arf_src_index = get_arf_src_index(cpi);
|
||||
if (arf_src_index &&
|
||||
is_forced_keyframe_pending(cpi->lookahead, arf_src_index)) {
|
||||
arf_src_index = 0;
|
||||
*flush = 1;
|
||||
}
|
||||
|
||||
if (arf_src_index) {
|
||||
source = setup_arf_or_arf2(cpi, arf_src_index, 0, temporal_filtered,
|
||||
frame_params);
|
||||
}
|
||||
|
||||
// Should we encode an arf2 frame (mutually exclusive to ARF)
|
||||
arf_src_index = get_arf2_src_index(cpi);
|
||||
if (arf_src_index &&
|
||||
is_forced_keyframe_pending(cpi->lookahead, arf_src_index)) {
|
||||
arf_src_index = 0;
|
||||
*flush = 1;
|
||||
}
|
||||
|
||||
if (arf_src_index) {
|
||||
source = setup_arf_or_arf2(cpi, arf_src_index, 1, temporal_filtered,
|
||||
frame_params);
|
||||
}
|
||||
|
||||
cpi->rc.is_bwd_ref_frame = 0;
|
||||
int brf_src_index = get_brf_src_index(cpi);
|
||||
if (brf_src_index) {
|
||||
assert(brf_src_index <= cpi->rc.frames_to_key);
|
||||
if ((source = av1_lookahead_peek(cpi->lookahead, brf_src_index)) != NULL) {
|
||||
cm->showable_frame = 1;
|
||||
frame_params->show_frame = 0;
|
||||
|
||||
if (cpi->oxcf.pass < 2) {
|
||||
// In second pass, the buffer updates configure will be set
|
||||
// in the function av1_rc_get_second_pass_params
|
||||
av1_configure_buffer_updates(cpi, BRF_UPDATE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!source) {
|
||||
// Get last frame source.
|
||||
if (cm->current_frame.frame_number > 0) {
|
||||
*last_source = av1_lookahead_peek(cpi->lookahead, -1);
|
||||
}
|
||||
// Read in the source frame.
|
||||
source = av1_lookahead_pop(cpi->lookahead, *flush);
|
||||
|
||||
if (source != NULL) {
|
||||
frame_params->show_frame = 1;
|
||||
|
||||
// Check to see if the frame should be encoded as an arf overlay.
|
||||
check_src_altref(cpi, source);
|
||||
}
|
||||
}
|
||||
return source;
|
||||
}
|
||||
|
||||
int av1_encode_strategy(AV1_COMP *const cpi, size_t *const size,
|
||||
uint8_t *const dest, unsigned int *frame_flags,
|
||||
int64_t *const time_stamp, int64_t *const time_end,
|
||||
const aom_rational_t *const timebase, int flush) {
|
||||
const AV1EncoderConfig *const oxcf = &cpi->oxcf;
|
||||
AV1_COMMON *const cm = &cpi->common;
|
||||
|
||||
EncodeFrameInput frame_input;
|
||||
EncodeFrameParams frame_params;
|
||||
EncodeFrameResults frame_results;
|
||||
memset(&frame_input, 0, sizeof(frame_input));
|
||||
memset(&frame_params, 0, sizeof(frame_params));
|
||||
memset(&frame_results, 0, sizeof(frame_results));
|
||||
|
||||
int temporal_filtered = 0;
|
||||
struct lookahead_entry *source = NULL;
|
||||
struct lookahead_entry *last_source = NULL;
|
||||
if (cm->show_existing_frame) {
|
||||
source = av1_lookahead_pop(cpi->lookahead, flush);
|
||||
} else {
|
||||
source = choose_frame_source(cpi, &temporal_filtered, &flush, &last_source,
|
||||
&frame_params);
|
||||
}
|
||||
|
||||
if (source == NULL) { // If no source was found, we can't encode a frame.
|
||||
if (flush && oxcf->pass == 1 && !cpi->twopass.first_pass_done) {
|
||||
av1_end_first_pass(cpi); /* get last stats packet */
|
||||
cpi->twopass.first_pass_done = 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
frame_input.source = temporal_filtered ? &cpi->alt_ref_buffer : &source->img;
|
||||
frame_input.last_source = last_source != NULL ? &last_source->img : NULL;
|
||||
frame_input.ts_duration = source->ts_end - source->ts_start;
|
||||
|
||||
*time_stamp = source->ts_start;
|
||||
*time_end = source->ts_end;
|
||||
if (source->ts_start < cpi->first_time_stamp_ever) {
|
||||
cpi->first_time_stamp_ever = source->ts_start;
|
||||
cpi->last_end_time_stamp_seen = source->ts_start;
|
||||
}
|
||||
|
||||
av1_apply_encoding_flags(cpi, source->flags);
|
||||
if (!cm->show_existing_frame)
|
||||
*frame_flags = (source->flags & AOM_EFLAG_FORCE_KF) ? FRAMEFLAGS_KEY : 0;
|
||||
cpi->frame_flags = *frame_flags;
|
||||
|
||||
if (frame_params.show_frame ||
|
||||
(cm->show_existing_frame && cpi->rc.is_src_frame_alt_ref)) {
|
||||
// Shown frames and arf-overlay frames need frame-rate considering
|
||||
adjust_frame_rate(cpi, source);
|
||||
}
|
||||
|
||||
if (cm->show_existing_frame) {
|
||||
// show_existing_frame implies this frame is shown!
|
||||
frame_params.show_frame = 1;
|
||||
} else {
|
||||
// Retain the RF_LEVEL for the current newly coded frame.
|
||||
cm->cur_frame->frame_rf_level =
|
||||
cpi->twopass.gf_group.rf_level[cpi->twopass.gf_group.index];
|
||||
|
||||
if (cpi->film_grain_table) {
|
||||
cm->seq_params.film_grain_params_present = aom_film_grain_table_lookup(
|
||||
cpi->film_grain_table, *time_stamp, *time_end, 0 /* =erase */,
|
||||
&cm->film_grain_params);
|
||||
}
|
||||
cm->cur_frame->film_grain_params_present =
|
||||
cm->seq_params.film_grain_params_present;
|
||||
|
||||
// only one operating point supported now
|
||||
const int64_t pts64 = ticks_to_timebase_units(timebase, *time_stamp);
|
||||
if (pts64 < 0 || pts64 > UINT32_MAX) return AOM_CODEC_ERROR;
|
||||
cpi->common.frame_presentation_time = (uint32_t)pts64;
|
||||
}
|
||||
|
||||
if (oxcf->pass == 2 &&
|
||||
(!cm->show_existing_frame || cpi->rc.is_src_frame_alt_ref)) {
|
||||
// GF_GROUP needs updating for arf overlays as well as non-show-existing
|
||||
av1_rc_get_second_pass_params(cpi, &frame_params);
|
||||
}
|
||||
if (cm->show_existing_frame && frame_params.frame_type != KEY_FRAME) {
|
||||
// Force show-existing frames to be INTER, except forward keyframes
|
||||
frame_params.frame_type = INTER_FRAME;
|
||||
}
|
||||
|
||||
if (!cm->show_existing_frame) {
|
||||
cm->using_qmatrix = cpi->oxcf.using_qm;
|
||||
cm->min_qmlevel = cpi->oxcf.qm_minlevel;
|
||||
cm->max_qmlevel = cpi->oxcf.qm_maxlevel;
|
||||
if (cpi->twopass.gf_group.index == 1 && cpi->oxcf.enable_tpl_model) {
|
||||
av1_set_frame_size(cpi, cm->width, cm->height);
|
||||
av1_tpl_setup_stats(cpi, &frame_input);
|
||||
}
|
||||
}
|
||||
|
||||
frame_params.frame_flags = frame_flags;
|
||||
|
||||
// TODO(david.turner@argondesign.com): Move all the encode strategy
|
||||
// (largely near av1_get_compressed_data) in here
|
||||
|
||||
// TODO(david.turner@argondesign.com): Change all the encode strategy to
|
||||
// modify frame_params instead of cm or cpi.
|
||||
|
||||
// Per-frame encode speed. In theory this can vary, but things may have been
|
||||
// written assuming speed-level will not change within a sequence, so this
|
||||
// parameter should be used with caution.
|
||||
frame_params.speed = oxcf->speed;
|
||||
|
||||
// Work out some encoding parameters specific to the pass:
|
||||
if (oxcf->pass == 0) {
|
||||
if (cpi->oxcf.rc_mode == AOM_CBR) {
|
||||
av1_rc_get_one_pass_cbr_params(cpi, &frame_params);
|
||||
} else {
|
||||
av1_rc_get_one_pass_vbr_params(cpi, &frame_params);
|
||||
}
|
||||
} else if (oxcf->pass == 1) {
|
||||
av1_setup_frame_size(cpi);
|
||||
cpi->td.mb.e_mbd.lossless[0] = is_lossless_requested(&cpi->oxcf);
|
||||
if (!cpi->refresh_alt_ref_frame && (cm->current_frame.frame_number == 0 ||
|
||||
(cpi->frame_flags & FRAMEFLAGS_KEY))) {
|
||||
frame_params.frame_type = KEY_FRAME;
|
||||
} else {
|
||||
frame_params.frame_type = INTER_FRAME;
|
||||
}
|
||||
} else if (oxcf->pass == 2) {
|
||||
#if CONFIG_MISMATCH_DEBUG
|
||||
mismatch_move_frame_idx_w();
|
||||
#endif
|
||||
#if TXCOEFF_COST_TIMER
|
||||
cm->txcoeff_cost_timer = 0;
|
||||
cm->txcoeff_cost_count = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (oxcf->pass == 0 || oxcf->pass == 2) {
|
||||
// Apply external override flags
|
||||
set_ext_overrides(cpi, &frame_params);
|
||||
|
||||
// Work out which reference frame slots may be used.
|
||||
frame_params.ref_frame_flags = get_ref_frame_flags(cpi);
|
||||
}
|
||||
|
||||
if (oxcf->pass == 0 || oxcf->pass == 2) {
|
||||
frame_params.primary_ref_frame =
|
||||
choose_primary_ref_frame(cpi, &frame_params);
|
||||
frame_params.order_offset = get_order_offset(cpi, &frame_params);
|
||||
}
|
||||
|
||||
if (av1_encode(cpi, dest, &frame_input, &frame_params, &frame_results) !=
|
||||
AOM_CODEC_OK) {
|
||||
return AOM_CODEC_ERROR;
|
||||
}
|
||||
|
||||
if (oxcf->pass == 2) {
|
||||
#if TXCOEFF_COST_TIMER
|
||||
cm->cum_txcoeff_cost_timer += cm->txcoeff_cost_timer;
|
||||
fprintf(stderr,
|
||||
"\ntxb coeff cost block number: %ld, frame time: %ld, cum time %ld "
|
||||
"in us\n",
|
||||
cm->txcoeff_cost_count, cm->txcoeff_cost_timer,
|
||||
cm->cum_txcoeff_cost_timer);
|
||||
#endif
|
||||
av1_twopass_postencode_update(cpi);
|
||||
}
|
||||
|
||||
if (oxcf->pass == 0 || oxcf->pass == 2) {
|
||||
update_fb_of_context_type(cpi, &frame_params, cpi->fb_of_context_type);
|
||||
set_additional_frame_flags(cm, frame_params.frame_flags);
|
||||
update_rc_counts(cpi);
|
||||
check_show_existing_frame(cpi); // Is next frame a show_existing frame?
|
||||
}
|
||||
|
||||
// Unpack frame_results:
|
||||
*size = frame_results.size;
|
||||
|
||||
// Leave a signal for a higher level caller about if this frame is droppable
|
||||
if (*size > 0) {
|
||||
cpi->droppable = is_frame_droppable(cpi);
|
||||
}
|
||||
|
||||
return AOM_CODEC_OK;
|
||||
}
|
||||
42
third_party/aom/av1/encoder/encode_strategy.h
vendored
Normal file
42
third_party/aom/av1/encoder/encode_strategy.h
vendored
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (c) 2019, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#ifndef AOM_AV1_ENCODER_ENCODE_STRATEGY_H_
|
||||
#define AOM_AV1_ENCODER_ENCODE_STRATEGY_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "aom/aom_encoder.h"
|
||||
|
||||
#include "av1/encoder/encoder.h"
|
||||
#include "av1/encoder/firstpass.h"
|
||||
|
||||
// This function will implement high-level encode strategy, choosing frame type,
|
||||
// frame placement, etc. It populates an EncodeFrameParams struct with the
|
||||
// results of these decisions and then calls av1_encode()
|
||||
int av1_encode_strategy(AV1_COMP *const cpi, size_t *const size,
|
||||
uint8_t *const dest, unsigned int *frame_flags,
|
||||
int64_t *const time_stamp, int64_t *const time_end,
|
||||
const aom_rational_t *const timebase, int flush);
|
||||
|
||||
// Set individual buffer update flags based on frame reference type
|
||||
void av1_configure_buffer_updates(AV1_COMP *const cpi,
|
||||
const FRAME_UPDATE_TYPE type);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // AOM_AV1_ENCODER_ENCODE_STRATEGY_H_
|
||||
2297
third_party/aom/av1/encoder/encodeframe.c
vendored
2297
third_party/aom/av1/encoder/encodeframe.c
vendored
File diff suppressed because it is too large
Load diff
2
third_party/aom/av1/encoder/encodeframe.h
vendored
2
third_party/aom/av1/encoder/encodeframe.h
vendored
|
|
@ -29,7 +29,7 @@ struct ThreadData;
|
|||
|
||||
void av1_setup_src_planes(struct macroblock *x,
|
||||
const struct yv12_buffer_config *src, int mi_row,
|
||||
int mi_col, const int num_planes);
|
||||
int mi_col, const int num_planes, BLOCK_SIZE bsize);
|
||||
|
||||
void av1_encode_frame(struct AV1_COMP *cpi);
|
||||
|
||||
|
|
|
|||
41
third_party/aom/av1/encoder/encodemb.c
vendored
41
third_party/aom/av1/encoder/encodemb.c
vendored
|
|
@ -43,7 +43,7 @@ static void subtract_block(const MACROBLOCKD *xd, int rows, int cols,
|
|||
const uint8_t *src8, ptrdiff_t src_stride,
|
||||
const uint8_t *pred8, ptrdiff_t pred_stride) {
|
||||
if (check_subtract_block_size(rows, cols)) {
|
||||
if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) {
|
||||
if (is_cur_buf_hbd(xd)) {
|
||||
aom_highbd_subtract_block_c(rows, cols, diff, diff_stride, src8,
|
||||
src_stride, pred8, pred_stride, xd->bd);
|
||||
return;
|
||||
|
|
@ -54,7 +54,7 @@ static void subtract_block(const MACROBLOCKD *xd, int rows, int cols,
|
|||
return;
|
||||
}
|
||||
|
||||
if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) {
|
||||
if (is_cur_buf_hbd(xd)) {
|
||||
aom_highbd_subtract_block(rows, cols, diff, diff_stride, src8, src_stride,
|
||||
pred8, pred_stride, xd->bd);
|
||||
return;
|
||||
|
|
@ -116,11 +116,11 @@ int av1_optimize_b(const struct AV1_COMP *cpi, MACROBLOCK *mb, int plane,
|
|||
rate_cost, cpi->oxcf.sharpness);
|
||||
}
|
||||
|
||||
typedef enum QUANT_FUNC {
|
||||
enum {
|
||||
QUANT_FUNC_LOWBD = 0,
|
||||
QUANT_FUNC_HIGHBD = 1,
|
||||
QUANT_FUNC_TYPES = 2
|
||||
} QUANT_FUNC;
|
||||
} UENUM1BYTE(QUANT_FUNC);
|
||||
|
||||
static AV1_QUANT_FACADE
|
||||
quant_func_list[AV1_XFORM_QUANT_TYPES][QUANT_FUNC_TYPES] = {
|
||||
|
|
@ -163,6 +163,7 @@ void av1_xform_quant(const AV1_COMMON *cm, MACROBLOCK *x, int plane, int block,
|
|||
qparam.tx_size = tx_size;
|
||||
qparam.qmatrix = qmatrix;
|
||||
qparam.iqmatrix = iqmatrix;
|
||||
qparam.use_quant_b_adapt = cm->use_quant_b_adapt;
|
||||
TxfmParam txfm_param;
|
||||
txfm_param.tx_type = tx_type;
|
||||
txfm_param.tx_size = tx_size;
|
||||
|
|
@ -171,7 +172,7 @@ void av1_xform_quant(const AV1_COMMON *cm, MACROBLOCK *x, int plane, int block,
|
|||
txfm_param.tx_size, is_inter_block(mbmi), cm->reduced_tx_set_used);
|
||||
|
||||
txfm_param.bd = xd->bd;
|
||||
txfm_param.is_hbd = get_bitdepth_data_path_index(xd);
|
||||
txfm_param.is_hbd = is_cur_buf_hbd(xd);
|
||||
|
||||
av1_fwd_txfm(src_diff, coeff, diff_stride, &txfm_param);
|
||||
|
||||
|
|
@ -226,7 +227,7 @@ static void encode_block(int plane, int block, int blk_row, int blk_col,
|
|||
if (!is_blk_skip(x, plane, blk_row * bw + blk_col) && !mbmi->skip_mode) {
|
||||
TX_TYPE tx_type = av1_get_tx_type(pd->plane_type, xd, blk_row, blk_col,
|
||||
tx_size, cm->reduced_tx_set_used);
|
||||
if (args->enable_optimize_b) {
|
||||
if (args->enable_optimize_b != NO_TRELLIS_OPT) {
|
||||
av1_xform_quant(cm, x, plane, block, blk_row, blk_col, plane_bsize,
|
||||
tx_size, tx_type, AV1_XFORM_QUANT_FP);
|
||||
TXB_CTX txb_ctx;
|
||||
|
|
@ -256,11 +257,11 @@ static void encode_block(int plane, int block, int blk_row, int blk_col,
|
|||
}
|
||||
|
||||
if (p->eobs[block] == 0 && plane == 0) {
|
||||
// TODO(debargha, jingning): Temporarily disable txk_type check for eob=0
|
||||
// case. It is possible that certain collision in hash index would cause
|
||||
// the assertion failure. To further optimize the rate-distortion
|
||||
// performance, we need to re-visit this part and enable this assert
|
||||
// again.
|
||||
// TODO(debargha, jingning): Temporarily disable txk_type check for eob=0
|
||||
// case. It is possible that certain collision in hash index would cause
|
||||
// the assertion failure. To further optimize the rate-distortion
|
||||
// performance, we need to re-visit this part and enable this assert
|
||||
// again.
|
||||
#if 0
|
||||
if (args->cpi->oxcf.aq_mode == NO_AQ &&
|
||||
args->cpi->oxcf.deltaq_mode == NO_DELTA_Q) {
|
||||
|
|
@ -285,8 +286,8 @@ static void encode_block(int plane, int block, int blk_row, int blk_col,
|
|||
int blk_h = block_size_high[bsize];
|
||||
mi_to_pixel_loc(&pixel_c, &pixel_r, mi_col, mi_row, blk_col, blk_row,
|
||||
pd->subsampling_x, pd->subsampling_y);
|
||||
mismatch_record_block_tx(dst, pd->dst.stride, cm->frame_offset, plane,
|
||||
pixel_c, pixel_r, blk_w, blk_h,
|
||||
mismatch_record_block_tx(dst, pd->dst.stride, cm->current_frame.order_hint,
|
||||
plane, pixel_c, pixel_r, blk_w, blk_h,
|
||||
xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH);
|
||||
}
|
||||
#endif
|
||||
|
|
@ -431,7 +432,7 @@ static void encode_block_pass1(int plane, int block, int blk_row, int blk_col,
|
|||
|
||||
if (p->eobs[block] > 0) {
|
||||
txfm_param.bd = xd->bd;
|
||||
txfm_param.is_hbd = get_bitdepth_data_path_index(xd);
|
||||
txfm_param.is_hbd = is_cur_buf_hbd(xd);
|
||||
txfm_param.tx_type = DCT_DCT;
|
||||
txfm_param.tx_size = tx_size;
|
||||
txfm_param.eob = p->eobs[block];
|
||||
|
|
@ -578,7 +579,7 @@ void av1_encode_block_intra(int plane, int block, int blk_row, int blk_col,
|
|||
|
||||
const ENTROPY_CONTEXT *a = &args->ta[blk_col];
|
||||
const ENTROPY_CONTEXT *l = &args->tl[blk_row];
|
||||
if (args->enable_optimize_b) {
|
||||
if (args->enable_optimize_b != NO_TRELLIS_OPT) {
|
||||
av1_xform_quant(cm, x, plane, block, blk_row, blk_col, plane_bsize,
|
||||
tx_size, tx_type, AV1_XFORM_QUANT_FP);
|
||||
TXB_CTX txb_ctx;
|
||||
|
|
@ -598,11 +599,11 @@ void av1_encode_block_intra(int plane, int block, int blk_row, int blk_col,
|
|||
}
|
||||
|
||||
if (*eob == 0 && plane == 0) {
|
||||
// TODO(jingning): Temporarily disable txk_type check for eob=0 case.
|
||||
// It is possible that certain collision in hash index would cause
|
||||
// the assertion failure. To further optimize the rate-distortion
|
||||
// performance, we need to re-visit this part and enable this assert
|
||||
// again.
|
||||
// TODO(jingning): Temporarily disable txk_type check for eob=0 case.
|
||||
// It is possible that certain collision in hash index would cause
|
||||
// the assertion failure. To further optimize the rate-distortion
|
||||
// performance, we need to re-visit this part and enable this assert
|
||||
// again.
|
||||
#if 0
|
||||
if (args->cpi->oxcf.aq_mode == NO_AQ
|
||||
&& args->cpi->oxcf.deltaq_mode == NO_DELTA_Q) {
|
||||
|
|
|
|||
4
third_party/aom/av1/encoder/encodemb.h
vendored
4
third_party/aom/av1/encoder/encodemb.h
vendored
|
|
@ -37,13 +37,13 @@ struct encode_b_args {
|
|||
int8_t enable_optimize_b;
|
||||
};
|
||||
|
||||
typedef enum AV1_XFORM_QUANT {
|
||||
enum {
|
||||
AV1_XFORM_QUANT_FP = 0,
|
||||
AV1_XFORM_QUANT_B = 1,
|
||||
AV1_XFORM_QUANT_DC = 2,
|
||||
AV1_XFORM_QUANT_SKIP_QUANT,
|
||||
AV1_XFORM_QUANT_TYPES,
|
||||
} AV1_XFORM_QUANT;
|
||||
} UENUM1BYTE(AV1_XFORM_QUANT);
|
||||
|
||||
void av1_encode_sb(const struct AV1_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bsize,
|
||||
int mi_row, int mi_col, RUN_TYPE dry_run);
|
||||
|
|
|
|||
3862
third_party/aom/av1/encoder/encoder.c
vendored
3862
third_party/aom/av1/encoder/encoder.c
vendored
File diff suppressed because it is too large
Load diff
407
third_party/aom/av1/encoder/encoder.h
vendored
407
third_party/aom/av1/encoder/encoder.h
vendored
|
|
@ -59,7 +59,7 @@ typedef struct {
|
|||
FRAME_CONTEXT fc;
|
||||
} CODING_CONTEXT;
|
||||
|
||||
typedef enum {
|
||||
enum {
|
||||
// regular inter frame
|
||||
REGULAR_FRAME = 0,
|
||||
// alternate reference frame
|
||||
|
|
@ -73,51 +73,54 @@ typedef enum {
|
|||
// extra alternate reference frame
|
||||
EXT_ARF_FRAME = 5,
|
||||
FRAME_CONTEXT_INDEXES
|
||||
} FRAME_CONTEXT_INDEX;
|
||||
} UENUM1BYTE(FRAME_CONTEXT_INDEX);
|
||||
|
||||
typedef enum {
|
||||
enum {
|
||||
NORMAL = 0,
|
||||
FOURFIVE = 1,
|
||||
THREEFIVE = 2,
|
||||
ONETWO = 3
|
||||
} AOM_SCALING;
|
||||
} UENUM1BYTE(AOM_SCALING);
|
||||
|
||||
typedef enum {
|
||||
enum {
|
||||
// Good Quality Fast Encoding. The encoder balances quality with the amount of
|
||||
// time it takes to encode the output. Speed setting controls how fast.
|
||||
GOOD
|
||||
} MODE;
|
||||
} UENUM1BYTE(MODE);
|
||||
|
||||
typedef enum {
|
||||
enum {
|
||||
FRAMEFLAGS_KEY = 1 << 0,
|
||||
FRAMEFLAGS_GOLDEN = 1 << 1,
|
||||
FRAMEFLAGS_BWDREF = 1 << 2,
|
||||
// TODO(zoeliu): To determine whether a frame flag is needed for ALTREF2_FRAME
|
||||
FRAMEFLAGS_ALTREF = 1 << 3,
|
||||
} FRAMETYPE_FLAGS;
|
||||
FRAMEFLAGS_INTRAONLY = 1 << 4,
|
||||
FRAMEFLAGS_SWITCH = 1 << 5,
|
||||
FRAMEFLAGS_ERROR_RESILIENT = 1 << 6,
|
||||
} UENUM1BYTE(FRAMETYPE_FLAGS);
|
||||
|
||||
typedef enum {
|
||||
enum {
|
||||
NO_AQ = 0,
|
||||
VARIANCE_AQ = 1,
|
||||
COMPLEXITY_AQ = 2,
|
||||
CYCLIC_REFRESH_AQ = 3,
|
||||
AQ_MODE_COUNT // This should always be the last member of the enum
|
||||
} AQ_MODE;
|
||||
typedef enum {
|
||||
} UENUM1BYTE(AQ_MODE);
|
||||
enum {
|
||||
NO_DELTA_Q = 0,
|
||||
DELTA_Q_ONLY = 1,
|
||||
DELTA_Q_LF = 2,
|
||||
DELTAQ_MODE_COUNT // This should always be the last member of the enum
|
||||
} DELTAQ_MODE;
|
||||
} UENUM1BYTE(DELTAQ_MODE);
|
||||
|
||||
typedef enum {
|
||||
enum {
|
||||
RESIZE_NONE = 0, // No frame resizing allowed.
|
||||
RESIZE_FIXED = 1, // All frames are coded at the specified scale.
|
||||
RESIZE_RANDOM = 2, // All frames are coded at a random scale.
|
||||
RESIZE_MODES
|
||||
} RESIZE_MODE;
|
||||
} UENUM1BYTE(RESIZE_MODE);
|
||||
|
||||
typedef enum {
|
||||
enum {
|
||||
SUPERRES_NONE = 0, // No frame superres allowed
|
||||
SUPERRES_FIXED = 1, // All frames are coded at the specified scale,
|
||||
// and super-resolved.
|
||||
|
|
@ -126,7 +129,31 @@ typedef enum {
|
|||
SUPERRES_QTHRESH = 3, // Superres scale for a frame is determined based on
|
||||
// q_index
|
||||
SUPERRES_MODES
|
||||
} SUPERRES_MODE;
|
||||
} UENUM1BYTE(SUPERRES_MODE);
|
||||
|
||||
typedef struct TplDepStats {
|
||||
int64_t intra_cost;
|
||||
int64_t inter_cost;
|
||||
int64_t mc_flow;
|
||||
int64_t mc_dep_cost;
|
||||
int64_t mc_ref_cost;
|
||||
|
||||
int ref_frame_index;
|
||||
int_mv mv;
|
||||
} TplDepStats;
|
||||
|
||||
typedef struct TplDepFrame {
|
||||
uint8_t is_valid;
|
||||
TplDepStats *tpl_stats_ptr;
|
||||
int stride;
|
||||
int width;
|
||||
int height;
|
||||
int mi_rows;
|
||||
int mi_cols;
|
||||
int base_qindex;
|
||||
} TplDepFrame;
|
||||
|
||||
#define TPL_DEP_COST_SCALE_LOG2 4
|
||||
|
||||
typedef struct AV1EncoderConfig {
|
||||
BITSTREAM_PROFILE profile;
|
||||
|
|
@ -188,6 +215,7 @@ typedef struct AV1EncoderConfig {
|
|||
DELTAQ_MODE deltaq_mode;
|
||||
int enable_cdef;
|
||||
int enable_restoration;
|
||||
int enable_obmc;
|
||||
int disable_trellis_quant;
|
||||
int using_qm;
|
||||
int qm_y;
|
||||
|
|
@ -247,6 +275,7 @@ typedef struct AV1EncoderConfig {
|
|||
|
||||
int min_gf_interval;
|
||||
int max_gf_interval;
|
||||
int gf_max_pyr_height;
|
||||
|
||||
int row_mt;
|
||||
int tile_columns;
|
||||
|
|
@ -256,10 +285,11 @@ typedef struct AV1EncoderConfig {
|
|||
int tile_widths[MAX_TILE_COLS];
|
||||
int tile_heights[MAX_TILE_ROWS];
|
||||
|
||||
int enable_tpl_model;
|
||||
|
||||
int max_threads;
|
||||
|
||||
aom_fixed_buf_t two_pass_stats_in;
|
||||
struct aom_codec_pkt_list *output_pkt_list;
|
||||
|
||||
#if CONFIG_FP_MB_STATS
|
||||
aom_fixed_buf_t firstpass_mb_stats_in;
|
||||
|
|
@ -275,15 +305,12 @@ typedef struct AV1EncoderConfig {
|
|||
int color_range;
|
||||
int render_width;
|
||||
int render_height;
|
||||
aom_timing_info_type_t timing_info_type;
|
||||
int timing_info_present;
|
||||
aom_timing_info_t timing_info;
|
||||
int decoder_model_info_present_flag;
|
||||
int display_model_info_present_flag;
|
||||
int buffer_removal_time_present;
|
||||
aom_dec_model_info_t buffer_model;
|
||||
aom_dec_model_op_parameters_t op_params[MAX_NUM_OPERATING_POINTS + 1];
|
||||
aom_op_timing_info_t op_frame_timing[MAX_NUM_OPERATING_POINTS + 1];
|
||||
int film_grain_test_vector;
|
||||
const char *film_grain_table_filename;
|
||||
|
||||
|
|
@ -291,18 +318,36 @@ typedef struct AV1EncoderConfig {
|
|||
aom_superblock_size_t superblock_size;
|
||||
unsigned int large_scale_tile;
|
||||
unsigned int single_tile_decoding;
|
||||
int monochrome;
|
||||
uint8_t monochrome;
|
||||
unsigned int full_still_picture_hdr;
|
||||
int enable_dual_filter;
|
||||
unsigned int motion_vector_unit_test;
|
||||
const cfg_options_t *cfg;
|
||||
int enable_rect_partitions;
|
||||
int enable_intra_edge_filter;
|
||||
int enable_tx64;
|
||||
int enable_order_hint;
|
||||
int enable_jnt_comp;
|
||||
int enable_dist_wtd_comp;
|
||||
int enable_ref_frame_mvs;
|
||||
unsigned int max_reference_frames;
|
||||
unsigned int allow_ref_frame_mvs;
|
||||
int enable_masked_comp;
|
||||
int enable_interintra_comp;
|
||||
int enable_smooth_interintra;
|
||||
int enable_diff_wtd_comp;
|
||||
int enable_interinter_wedge;
|
||||
int enable_interintra_wedge;
|
||||
int enable_global_motion;
|
||||
int enable_warped_motion;
|
||||
int allow_warped_motion;
|
||||
int enable_filter_intra;
|
||||
int enable_smooth_intra;
|
||||
int enable_paeth_intra;
|
||||
int enable_cfl_intra;
|
||||
int enable_superres;
|
||||
int enable_palette;
|
||||
int enable_intrabc;
|
||||
int enable_angle_delta;
|
||||
unsigned int save_as_annexb;
|
||||
|
||||
#if CONFIG_DENOISE
|
||||
|
|
@ -312,6 +357,11 @@ typedef struct AV1EncoderConfig {
|
|||
|
||||
unsigned int chroma_subsampling_x;
|
||||
unsigned int chroma_subsampling_y;
|
||||
int reduced_tx_type_set;
|
||||
int use_intra_dct_only;
|
||||
int use_inter_dct_only;
|
||||
int quant_b_adapt;
|
||||
int border_in_pixels;
|
||||
} AV1EncoderConfig;
|
||||
|
||||
static INLINE int is_lossless_requested(const AV1EncoderConfig *cfg) {
|
||||
|
|
@ -404,7 +454,6 @@ typedef struct FRAME_COUNTS {
|
|||
[SWITCHABLE_FILTERS];
|
||||
} FRAME_COUNTS;
|
||||
|
||||
#if CONFIG_COLLECT_INTER_MODE_RD_STATS
|
||||
#define INTER_MODE_RD_DATA_OVERALL_SIZE 6400
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -439,22 +488,37 @@ typedef struct inter_modes_info {
|
|||
int64_t est_rd_arr[MAX_INTER_MODES];
|
||||
RdIdxPair rd_idx_pair_arr[MAX_INTER_MODES];
|
||||
} InterModesInfo;
|
||||
|
||||
// Encoder row synchronization
|
||||
typedef struct AV1RowMTSyncData {
|
||||
#if CONFIG_MULTITHREAD
|
||||
pthread_mutex_t *mutex_;
|
||||
pthread_cond_t *cond_;
|
||||
#endif
|
||||
// Allocate memory to store the sb/mb block index in each row.
|
||||
int *cur_col;
|
||||
int sync_range;
|
||||
int rows;
|
||||
} AV1RowMTSync;
|
||||
|
||||
typedef struct AV1RowMTInfo {
|
||||
int current_mi_row;
|
||||
int num_threads_working;
|
||||
} AV1RowMTInfo;
|
||||
|
||||
// TODO(jingning) All spatially adaptive variables should go to TileDataEnc.
|
||||
typedef struct TileDataEnc {
|
||||
TileInfo tile_info;
|
||||
int thresh_freq_fact[BLOCK_SIZES_ALL][MAX_MODES];
|
||||
int mode_map[BLOCK_SIZES_ALL][MAX_MODES];
|
||||
int m_search_count;
|
||||
int ex_search_count;
|
||||
CFL_CTX cfl;
|
||||
DECLARE_ALIGNED(16, FRAME_CONTEXT, tctx);
|
||||
FRAME_CONTEXT *row_ctx;
|
||||
uint8_t allow_update_cdf;
|
||||
#if CONFIG_COLLECT_INTER_MODE_RD_STATS
|
||||
InterModeRdModel inter_mode_rd_models[BLOCK_SIZES_ALL];
|
||||
InterModesInfo inter_modes_info;
|
||||
#endif
|
||||
AV1RowMTSync row_mt_sync;
|
||||
AV1RowMTInfo row_mt_info;
|
||||
} TileDataEnc;
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -463,6 +527,13 @@ typedef struct {
|
|||
unsigned int count;
|
||||
} TOKENLIST;
|
||||
|
||||
typedef struct MultiThreadHandle {
|
||||
int allocated_tile_rows;
|
||||
int allocated_tile_cols;
|
||||
int allocated_sb_rows;
|
||||
int thread_id_to_tile_id[MAX_NUM_THREADS]; // Mapping of threads to tiles
|
||||
} MultiThreadHandle;
|
||||
|
||||
typedef struct RD_COUNTS {
|
||||
int64_t comp_pred_diff[REFERENCE_MODES];
|
||||
// Stores number of 4x4 blocks using global motion per reference frame.
|
||||
|
|
@ -477,6 +548,10 @@ typedef struct ThreadData {
|
|||
FRAME_COUNTS *counts;
|
||||
PC_TREE *pc_tree;
|
||||
PC_TREE *pc_root[MAX_MIB_SIZE_LOG2 - MIN_MIB_SIZE_LOG2 + 1];
|
||||
tran_low_t *tree_coeff_buf[MAX_MB_PLANE];
|
||||
tran_low_t *tree_qcoeff_buf[MAX_MB_PLANE];
|
||||
tran_low_t *tree_dqcoeff_buf[MAX_MB_PLANE];
|
||||
InterModesInfo *inter_modes_info;
|
||||
uint32_t *hash_value_buffer[2][2];
|
||||
int32_t *wsrc_buf;
|
||||
int32_t *mask_buf;
|
||||
|
|
@ -485,7 +560,8 @@ typedef struct ThreadData {
|
|||
PALETTE_BUFFER *palette_buffer;
|
||||
CONV_BUF_TYPE *tmp_conv_dst;
|
||||
uint8_t *tmp_obmc_bufs[2];
|
||||
int intrabc_used_this_tile;
|
||||
int intrabc_used;
|
||||
FRAME_CONTEXT *tctx;
|
||||
} ThreadData;
|
||||
|
||||
struct EncWorkerData;
|
||||
|
|
@ -498,13 +574,13 @@ typedef struct ActiveMap {
|
|||
|
||||
#if CONFIG_INTERNAL_STATS
|
||||
// types of stats
|
||||
typedef enum {
|
||||
enum {
|
||||
STAT_Y,
|
||||
STAT_U,
|
||||
STAT_V,
|
||||
STAT_ALL,
|
||||
NUM_STAT_TYPES // This should always be the last member of the enum
|
||||
} StatType;
|
||||
} UENUM1BYTE(StatType);
|
||||
|
||||
typedef struct IMAGE_STAT {
|
||||
double stat[NUM_STAT_TYPES];
|
||||
|
|
@ -517,10 +593,14 @@ typedef struct {
|
|||
YV12_BUFFER_CONFIG buf;
|
||||
} EncRefCntBuffer;
|
||||
|
||||
typedef struct TileBufferEnc {
|
||||
uint8_t *data;
|
||||
size_t size;
|
||||
} TileBufferEnc;
|
||||
#if CONFIG_COLLECT_PARTITION_STATS
|
||||
typedef struct PartitionStats {
|
||||
int partition_decisions[6][EXT_PARTITION_TYPES];
|
||||
int partition_attempts[6][EXT_PARTITION_TYPES];
|
||||
|
||||
int partition_redo;
|
||||
} PartitionStats;
|
||||
#endif
|
||||
|
||||
typedef struct AV1_COMP {
|
||||
QUANTS quants;
|
||||
|
|
@ -545,6 +625,9 @@ typedef struct AV1_COMP {
|
|||
YV12_BUFFER_CONFIG *unscaled_last_source;
|
||||
YV12_BUFFER_CONFIG scaled_last_source;
|
||||
|
||||
TplDepFrame tpl_stats[MAX_LAG_BUFFERS];
|
||||
YV12_BUFFER_CONFIG *tpl_recon_frames[INTER_REFS_PER_FRAME + 1];
|
||||
|
||||
// For a still frame, this flag is set to 1 to skip partition search.
|
||||
int partition_search_skippable_frame;
|
||||
double csm_rate_array[32];
|
||||
|
|
@ -553,23 +636,41 @@ typedef struct AV1_COMP {
|
|||
int rate_index;
|
||||
hash_table *previous_hash_table;
|
||||
int previous_index;
|
||||
int cur_poc; // DebugInfo
|
||||
|
||||
unsigned int row_mt;
|
||||
int scaled_ref_idx[REF_FRAMES];
|
||||
int ref_fb_idx[REF_FRAMES];
|
||||
int refresh_fb_idx; // ref frame buffer index to refresh
|
||||
RefCntBuffer *scaled_ref_buf[INTER_REFS_PER_FRAME];
|
||||
|
||||
int last_show_frame_buf_idx; // last show frame buffer index
|
||||
RefCntBuffer *last_show_frame_buf; // last show frame buffer
|
||||
|
||||
// refresh_*_frame are boolean flags. If 'refresh_xyz_frame' is true, then
|
||||
// after the current frame is encoded, the XYZ reference frame gets refreshed
|
||||
// (updated) to be the current frame.
|
||||
//
|
||||
// Special case: 'refresh_last_frame' specifies that:
|
||||
// - LAST_FRAME reference should be updated to be the current frame (as usual)
|
||||
// - Also, LAST2_FRAME and LAST3_FRAME references are implicitly updated to be
|
||||
// the two past reference frames just before LAST_FRAME that are available.
|
||||
//
|
||||
// Note: Usually at most one of these refresh flags is true at a time.
|
||||
// But a key-frame is special, for which all the flags are true at once.
|
||||
int refresh_last_frame;
|
||||
int refresh_golden_frame;
|
||||
int refresh_bwd_ref_frame;
|
||||
int refresh_alt2_ref_frame;
|
||||
int refresh_alt_ref_frame;
|
||||
#if USE_SYMM_MULTI_LAYER
|
||||
|
||||
// For each type of reference frame, this contains the index of a reference
|
||||
// frame buffer for a reference frame of the same type. We use this to
|
||||
// choose our primary reference frame (which is the most recent reference
|
||||
// frame of the same type as the current frame).
|
||||
int fb_of_context_type[REF_FRAMES];
|
||||
|
||||
// When true, a new rule for backward (future) reference frames is in effect:
|
||||
// - BWDREF_FRAME is always the closest future frame available
|
||||
// - ALTREF2_FRAME is always the 2nd closest future frame available
|
||||
// - 'refresh_bwd_ref_frame' flag is used for updating both the BWDREF_FRAME
|
||||
// and ALTREF2_FRAME. ('refresh_alt2_ref_frame' flag is irrelevant).
|
||||
int new_bwdref_update_rule;
|
||||
#endif
|
||||
|
||||
int ext_refresh_frame_flags_pending;
|
||||
int ext_refresh_last_frame;
|
||||
|
|
@ -608,9 +709,10 @@ typedef struct AV1_COMP {
|
|||
RATE_CONTROL rc;
|
||||
double framerate;
|
||||
|
||||
// NOTE(zoeliu): Any inter frame allows maximum of REF_FRAMES inter
|
||||
// references; Plus the currently coded frame itself, it is needed to allocate
|
||||
// sufficient space to the size of the maximum possible number of frames.
|
||||
// Relevant for an inter frame.
|
||||
// - Index '0' corresponds to the values for the currently coded frame.
|
||||
// - Indices LAST_FRAME ... EXTREF_FRAMES are used to store values for all the
|
||||
// possible inter reference frames.
|
||||
int interp_filter_selected[REF_FRAMES + 1][SWITCHABLE];
|
||||
|
||||
struct aom_codec_pkt_list *output_pkt_list;
|
||||
|
|
@ -620,14 +722,15 @@ typedef struct AV1_COMP {
|
|||
int static_mb_pct; // % forced skip mbs by segmentation
|
||||
int ref_frame_flags;
|
||||
int ext_ref_frame_flags;
|
||||
RATE_FACTOR_LEVEL frame_rf_level[FRAME_BUFFERS];
|
||||
|
||||
// speed is passed as a per-frame parameter into the encoder
|
||||
int speed;
|
||||
// sf contains fine-grained config set internally based on speed
|
||||
SPEED_FEATURES sf;
|
||||
|
||||
unsigned int max_mv_magnitude;
|
||||
int mv_step_param;
|
||||
|
||||
int allow_comp_inter_inter;
|
||||
int all_one_sided_refs;
|
||||
|
||||
uint8_t *segmentation_map;
|
||||
|
|
@ -641,7 +744,6 @@ typedef struct AV1_COMP {
|
|||
uint64_t time_receive_data;
|
||||
uint64_t time_compress_data;
|
||||
uint64_t time_pick_lpf;
|
||||
uint64_t time_encode_sb_row;
|
||||
|
||||
#if CONFIG_FP_MB_STATS
|
||||
int use_fp_mb_stats;
|
||||
|
|
@ -680,6 +782,9 @@ typedef struct AV1_COMP {
|
|||
Metrics metrics;
|
||||
#endif
|
||||
int b_calculate_psnr;
|
||||
#if CONFIG_SPEED_STATS
|
||||
unsigned int tx_search_count;
|
||||
#endif // CONFIG_SPEED_STATS
|
||||
|
||||
int droppable;
|
||||
|
||||
|
|
@ -705,15 +810,11 @@ typedef struct AV1_COMP {
|
|||
int allocated_tiles; // Keep track of memory allocated for tiles.
|
||||
|
||||
TOKENEXTRA *tile_tok[MAX_TILE_ROWS][MAX_TILE_COLS];
|
||||
unsigned int tok_count[MAX_TILE_ROWS][MAX_TILE_COLS];
|
||||
TOKENLIST *tplist[MAX_TILE_ROWS][MAX_TILE_COLS];
|
||||
|
||||
TileBufferEnc tile_buffers[MAX_TILE_ROWS][MAX_TILE_COLS];
|
||||
|
||||
int resize_state;
|
||||
int resize_avg_qp;
|
||||
int resize_buffer_underflow;
|
||||
int resize_count;
|
||||
|
||||
// Sequence parameters have been transmitted already and locked
|
||||
// or not. Once locked av1_change_config cannot change the seq
|
||||
|
|
@ -727,14 +828,12 @@ typedef struct AV1_COMP {
|
|||
int num_workers;
|
||||
AVxWorker *workers;
|
||||
struct EncWorkerData *tile_thr_data;
|
||||
int refresh_frame_mask;
|
||||
int existing_fb_idx_to_show;
|
||||
int is_arf_filter_off[MAX_EXT_ARFS + 1];
|
||||
int num_extra_arfs;
|
||||
int arf_pos_in_gf[MAX_EXT_ARFS + 1];
|
||||
int arf_pos_for_ovrly[MAX_EXT_ARFS + 1];
|
||||
int global_motion_search_done;
|
||||
tran_low_t *tcoeff_buf[MAX_MB_PLANE];
|
||||
int extra_arf_allowed;
|
||||
// A flag to indicate if intrabc is ever used in current frame.
|
||||
int intrabc_used;
|
||||
|
|
@ -743,10 +842,16 @@ typedef struct AV1_COMP {
|
|||
int dv_joint_cost[MV_JOINTS];
|
||||
int has_lossless_segment;
|
||||
|
||||
// For frame refs short signaling:
|
||||
// A mapping of each reference frame from its encoder side value to the
|
||||
// decoder side value obtained following the short signaling procedure.
|
||||
int ref_conv[REF_FRAMES];
|
||||
// Factors to control gating of compound type selection based on best
|
||||
// approximate rd so far
|
||||
int max_comp_type_rd_threshold_mul;
|
||||
int max_comp_type_rd_threshold_div;
|
||||
|
||||
unsigned int tx_domain_dist_threshold;
|
||||
|
||||
// Factor to control R-D optimization of coeffs based on block
|
||||
// mse.
|
||||
unsigned int coeff_opt_dist_threshold;
|
||||
|
||||
AV1LfSync lf_row_sync;
|
||||
AV1LrSync lr_row_sync;
|
||||
|
|
@ -760,8 +865,50 @@ typedef struct AV1_COMP {
|
|||
// Set as 1 for monochrome and 3 for other color formats
|
||||
int default_interp_skip_flags;
|
||||
int preserve_arf_as_gld;
|
||||
MultiThreadHandle multi_thread_ctxt;
|
||||
void (*row_mt_sync_read_ptr)(AV1RowMTSync *const, int, int);
|
||||
void (*row_mt_sync_write_ptr)(AV1RowMTSync *const, int, int, const int);
|
||||
#if CONFIG_MULTITHREAD
|
||||
pthread_mutex_t *row_mt_mutex_;
|
||||
#endif
|
||||
// Set if screen content is set or relevant tools are enabled
|
||||
int is_screen_content_type;
|
||||
#if CONFIG_COLLECT_PARTITION_STATS
|
||||
PartitionStats partition_stats;
|
||||
#endif
|
||||
} AV1_COMP;
|
||||
|
||||
typedef struct {
|
||||
YV12_BUFFER_CONFIG *source;
|
||||
YV12_BUFFER_CONFIG *last_source;
|
||||
int64_t ts_duration;
|
||||
} EncodeFrameInput;
|
||||
|
||||
// EncodeFrameParams contains per-frame encoding parameters decided upon by
|
||||
// av1_encode_strategy() and passed down to av1_encode()
|
||||
struct EncodeFrameParams {
|
||||
int error_resilient_mode;
|
||||
FRAME_TYPE frame_type;
|
||||
int primary_ref_frame;
|
||||
int order_offset;
|
||||
int show_frame;
|
||||
|
||||
// This is a bitmask of which reference slots can be used in this frame
|
||||
int ref_frame_flags;
|
||||
|
||||
// Speed level to use for this frame: Bigger number means faster.
|
||||
int speed;
|
||||
|
||||
unsigned int *frame_flags;
|
||||
};
|
||||
typedef struct EncodeFrameParams EncodeFrameParams;
|
||||
|
||||
// EncodeFrameResults contains information about the result of encoding a
|
||||
// single frame
|
||||
typedef struct {
|
||||
size_t size; // Size of resulting bitstream
|
||||
} EncodeFrameResults;
|
||||
|
||||
// Must not be called more than once.
|
||||
void av1_initialize_enc(void);
|
||||
|
||||
|
|
@ -782,6 +929,11 @@ int av1_get_compressed_data(AV1_COMP *cpi, unsigned int *frame_flags,
|
|||
int64_t *time_end, int flush,
|
||||
const aom_rational_t *timebase);
|
||||
|
||||
int av1_encode(AV1_COMP *const cpi, uint8_t *const dest,
|
||||
const EncodeFrameInput *const frame_input,
|
||||
const EncodeFrameParams *const frame_params,
|
||||
EncodeFrameResults *const frame_results);
|
||||
|
||||
int av1_get_preview_raw_frame(AV1_COMP *cpi, YV12_BUFFER_CONFIG *dest);
|
||||
|
||||
int av1_get_last_show_frame(AV1_COMP *cpi, YV12_BUFFER_CONFIG *frame);
|
||||
|
|
@ -792,12 +944,12 @@ aom_codec_err_t av1_copy_new_frame_enc(AV1_COMMON *cm,
|
|||
|
||||
int av1_use_as_reference(AV1_COMP *cpi, int ref_frame_flags);
|
||||
|
||||
void av1_update_reference(AV1_COMP *cpi, int ref_frame_flags);
|
||||
|
||||
int av1_copy_reference_enc(AV1_COMP *cpi, int idx, YV12_BUFFER_CONFIG *sd);
|
||||
|
||||
int av1_set_reference_enc(AV1_COMP *cpi, int idx, YV12_BUFFER_CONFIG *sd);
|
||||
|
||||
void av1_set_frame_size(AV1_COMP *cpi, int width, int height);
|
||||
|
||||
int av1_update_entropy(AV1_COMP *cpi, int update);
|
||||
|
||||
int av1_set_active_map(AV1_COMP *cpi, unsigned char *map, int rows, int cols);
|
||||
|
|
@ -811,59 +963,62 @@ int av1_get_quantizer(struct AV1_COMP *cpi);
|
|||
|
||||
int av1_convert_sect5obus_to_annexb(uint8_t *buffer, size_t *input_size);
|
||||
|
||||
int64_t timebase_units_to_ticks(const aom_rational_t *timebase, int64_t n);
|
||||
int64_t ticks_to_timebase_units(const aom_rational_t *timebase, int64_t n);
|
||||
// av1 uses 10,000,000 ticks/second as time stamp
|
||||
#define TICKS_PER_SEC 10000000LL
|
||||
|
||||
static INLINE int64_t timebase_units_to_ticks(const aom_rational_t *timebase,
|
||||
int64_t n) {
|
||||
return n * TICKS_PER_SEC * timebase->num / timebase->den;
|
||||
}
|
||||
|
||||
static INLINE int64_t ticks_to_timebase_units(const aom_rational_t *timebase,
|
||||
int64_t n) {
|
||||
const int64_t round = TICKS_PER_SEC * timebase->num / 2 - 1;
|
||||
return (n * timebase->den + round) / timebase->num / TICKS_PER_SEC;
|
||||
}
|
||||
|
||||
static INLINE int frame_is_kf_gf_arf(const AV1_COMP *cpi) {
|
||||
return frame_is_intra_only(&cpi->common) || cpi->refresh_alt_ref_frame ||
|
||||
(cpi->refresh_golden_frame && !cpi->rc.is_src_frame_alt_ref);
|
||||
}
|
||||
|
||||
static INLINE int get_ref_frame_map_idx(const AV1_COMP *cpi,
|
||||
MV_REFERENCE_FRAME ref_frame) {
|
||||
return (ref_frame >= 1) ? cpi->ref_fb_idx[ref_frame - 1] : INVALID_IDX;
|
||||
}
|
||||
|
||||
static INLINE int get_ref_frame_buf_idx(const AV1_COMP *cpi,
|
||||
MV_REFERENCE_FRAME ref_frame) {
|
||||
const AV1_COMMON *const cm = &cpi->common;
|
||||
const int map_idx = get_ref_frame_map_idx(cpi, ref_frame);
|
||||
return (map_idx != INVALID_IDX) ? cm->ref_frame_map[map_idx] : INVALID_IDX;
|
||||
}
|
||||
|
||||
// TODO(huisu@google.com, youzhou@microsoft.com): enable hash-me for HBD.
|
||||
static INLINE int av1_use_hash_me(const AV1_COMMON *const cm) {
|
||||
return cm->allow_screen_content_tools;
|
||||
}
|
||||
|
||||
static INLINE hash_table *av1_get_ref_frame_hash_map(
|
||||
const AV1_COMP *cpi, MV_REFERENCE_FRAME ref_frame) {
|
||||
const AV1_COMMON *const cm = &cpi->common;
|
||||
const int buf_idx = get_ref_frame_buf_idx(cpi, ref_frame);
|
||||
return buf_idx != INVALID_IDX
|
||||
? &cm->buffer_pool->frame_bufs[buf_idx].hash_table
|
||||
: NULL;
|
||||
const AV1_COMMON *cm, MV_REFERENCE_FRAME ref_frame) {
|
||||
const int map_idx = get_ref_frame_map_idx(cm, ref_frame);
|
||||
RefCntBuffer *buf =
|
||||
(map_idx != INVALID_IDX) ? cm->ref_frame_map[map_idx] : NULL;
|
||||
return buf ? &buf->hash_table : NULL;
|
||||
}
|
||||
|
||||
static INLINE YV12_BUFFER_CONFIG *get_ref_frame_buffer(
|
||||
const AV1_COMP *cpi, MV_REFERENCE_FRAME ref_frame) {
|
||||
const AV1_COMMON *const cm = &cpi->common;
|
||||
const int buf_idx = get_ref_frame_buf_idx(cpi, ref_frame);
|
||||
return buf_idx != INVALID_IDX ? &cm->buffer_pool->frame_bufs[buf_idx].buf
|
||||
: NULL;
|
||||
static INLINE const YV12_BUFFER_CONFIG *get_ref_frame_yv12_buf(
|
||||
const AV1_COMMON *const cm, MV_REFERENCE_FRAME ref_frame) {
|
||||
const RefCntBuffer *const buf = get_ref_frame_buf(cm, ref_frame);
|
||||
return buf != NULL ? &buf->buf : NULL;
|
||||
}
|
||||
|
||||
static INLINE int enc_is_ref_frame_buf(AV1_COMP *cpi, RefCntBuffer *frame_buf) {
|
||||
static INLINE int enc_is_ref_frame_buf(const AV1_COMMON *const cm,
|
||||
const RefCntBuffer *const frame_buf) {
|
||||
MV_REFERENCE_FRAME ref_frame;
|
||||
AV1_COMMON *const cm = &cpi->common;
|
||||
for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) {
|
||||
const int buf_idx = get_ref_frame_buf_idx(cpi, ref_frame);
|
||||
if (buf_idx == INVALID_IDX) continue;
|
||||
if (frame_buf == &cm->buffer_pool->frame_bufs[buf_idx]) break;
|
||||
const RefCntBuffer *const buf = get_ref_frame_buf(cm, ref_frame);
|
||||
if (buf == NULL) continue;
|
||||
if (frame_buf == buf) break;
|
||||
}
|
||||
return (ref_frame <= ALTREF_FRAME);
|
||||
}
|
||||
|
||||
static INLINE void alloc_frame_mvs(AV1_COMMON *const cm, RefCntBuffer *buf) {
|
||||
assert(buf != NULL);
|
||||
ensure_mv_buffer(buf, cm);
|
||||
buf->width = cm->width;
|
||||
buf->height = cm->height;
|
||||
}
|
||||
|
||||
// Token buffer is only used for palette tokens.
|
||||
static INLINE unsigned int get_token_alloc(int mb_rows, int mb_cols,
|
||||
int sb_size_log2,
|
||||
|
|
@ -919,10 +1074,10 @@ static INLINE int is_altref_enabled(const AV1_COMP *const cpi) {
|
|||
static INLINE void set_ref_ptrs(const AV1_COMMON *cm, MACROBLOCKD *xd,
|
||||
MV_REFERENCE_FRAME ref0,
|
||||
MV_REFERENCE_FRAME ref1) {
|
||||
xd->block_refs[0] =
|
||||
&cm->frame_refs[ref0 >= LAST_FRAME ? ref0 - LAST_FRAME : 0];
|
||||
xd->block_refs[1] =
|
||||
&cm->frame_refs[ref1 >= LAST_FRAME ? ref1 - LAST_FRAME : 0];
|
||||
xd->block_ref_scale_factors[0] =
|
||||
get_ref_scale_factors_const(cm, ref0 >= LAST_FRAME ? ref0 : 1);
|
||||
xd->block_ref_scale_factors[1] =
|
||||
get_ref_scale_factors_const(cm, ref1 >= LAST_FRAME ? ref1 : 1);
|
||||
}
|
||||
|
||||
static INLINE int get_chessboard_index(int frame_index) {
|
||||
|
|
@ -935,20 +1090,10 @@ static INLINE int *cond_cost_list(const struct AV1_COMP *cpi, int *cost_list) {
|
|||
|
||||
void av1_new_framerate(AV1_COMP *cpi, double framerate);
|
||||
|
||||
void av1_setup_frame_size(AV1_COMP *cpi);
|
||||
|
||||
#define LAYER_IDS_TO_IDX(sl, tl, num_tl) ((sl) * (num_tl) + (tl))
|
||||
|
||||
// Update up-sampled reference frame index.
|
||||
static INLINE void uref_cnt_fb(EncRefCntBuffer *ubufs, int *uidx,
|
||||
int new_uidx) {
|
||||
const int ref_index = *uidx;
|
||||
|
||||
if (ref_index >= 0 && ubufs[ref_index].ref_count > 0)
|
||||
ubufs[ref_index].ref_count--;
|
||||
|
||||
*uidx = new_uidx;
|
||||
ubufs[new_uidx].ref_count++;
|
||||
}
|
||||
|
||||
// Returns 1 if a frame is scaled and 0 otherwise.
|
||||
static INLINE int av1_resize_scaled(const AV1_COMMON *cm) {
|
||||
return !(cm->superres_upscaled_width == cm->render_width &&
|
||||
|
|
@ -963,8 +1108,8 @@ static INLINE int av1_frame_scaled(const AV1_COMMON *cm) {
|
|||
// frame. An exception can be made for a forward keyframe since it has no
|
||||
// previous dependencies.
|
||||
static INLINE int encode_show_existing_frame(const AV1_COMMON *cm) {
|
||||
return cm->show_existing_frame &&
|
||||
(!cm->error_resilient_mode || cm->frame_type == KEY_FRAME);
|
||||
return cm->show_existing_frame && (!cm->error_resilient_mode ||
|
||||
cm->current_frame.frame_type == KEY_FRAME);
|
||||
}
|
||||
|
||||
// Returns a Sequence Header OBU stored in an aom_fixed_buf_t, or NULL upon
|
||||
|
|
@ -978,6 +1123,52 @@ static INLINE int encode_show_existing_frame(const AV1_COMMON *cm) {
|
|||
// field.
|
||||
aom_fixed_buf_t *av1_get_global_headers(AV1_COMP *cpi);
|
||||
|
||||
#if CONFIG_COLLECT_PARTITION_STATS
|
||||
static INLINE void av1_print_partition_stats(PartitionStats *part_stats) {
|
||||
FILE *f = fopen("partition_stats.csv", "w");
|
||||
if (!f) {
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(f, "bsize,redo,");
|
||||
for (int part = 0; part < EXT_PARTITION_TYPES; part++) {
|
||||
fprintf(f, "decision_%d,", part);
|
||||
}
|
||||
for (int part = 0; part < EXT_PARTITION_TYPES; part++) {
|
||||
fprintf(f, "attempt_%d,", part);
|
||||
}
|
||||
fprintf(f, "\n");
|
||||
|
||||
const int bsizes[6] = { 128, 64, 32, 16, 8, 4 };
|
||||
|
||||
for (int bsize_idx = 0; bsize_idx < 6; bsize_idx++) {
|
||||
fprintf(f, "%d,%d,", bsizes[bsize_idx], part_stats->partition_redo);
|
||||
for (int part = 0; part < EXT_PARTITION_TYPES; part++) {
|
||||
fprintf(f, "%d,", part_stats->partition_decisions[bsize_idx][part]);
|
||||
}
|
||||
for (int part = 0; part < EXT_PARTITION_TYPES; part++) {
|
||||
fprintf(f, "%d,", part_stats->partition_attempts[bsize_idx][part]);
|
||||
}
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
static INLINE int av1_get_bsize_idx_for_part_stats(BLOCK_SIZE bsize) {
|
||||
assert(bsize == BLOCK_128X128 || bsize == BLOCK_64X64 ||
|
||||
bsize == BLOCK_32X32 || bsize == BLOCK_16X16 || bsize == BLOCK_8X8);
|
||||
switch (bsize) {
|
||||
case BLOCK_128X128: return 0;
|
||||
case BLOCK_64X64: return 1;
|
||||
case BLOCK_32X32: return 2;
|
||||
case BLOCK_16X16: return 3;
|
||||
case BLOCK_8X8: return 4;
|
||||
case BLOCK_4X4: return 5;
|
||||
default: assert(0 && "Invalid bsize for partition_stats."); return -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
|
|
|||
307
third_party/aom/av1/encoder/encodetxb.c
vendored
307
third_party/aom/av1/encoder/encodetxb.c
vendored
|
|
@ -284,20 +284,16 @@ static INLINE int get_sign_bit_cost(tran_low_t qc, int coeff_idx,
|
|||
return av1_cost_literal(1);
|
||||
}
|
||||
|
||||
static INLINE int get_br_cost(tran_low_t abs_qc, int ctx,
|
||||
const int *coeff_lps) {
|
||||
const tran_low_t min_level = 1 + NUM_BASE_LEVELS;
|
||||
const tran_low_t max_level = 1 + NUM_BASE_LEVELS + COEFF_BASE_RANGE;
|
||||
(void)ctx;
|
||||
if (abs_qc >= min_level) {
|
||||
if (abs_qc >= max_level) {
|
||||
return coeff_lps[COEFF_BASE_RANGE]; // COEFF_BASE_RANGE * cost0;
|
||||
} else {
|
||||
return coeff_lps[(abs_qc - min_level)]; // * cost0 + cost1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static const int golomb_bits_cost[32] = {
|
||||
0, 512, 512 * 3, 512 * 3, 512 * 5, 512 * 5, 512 * 5, 512 * 5,
|
||||
512 * 7, 512 * 7, 512 * 7, 512 * 7, 512 * 7, 512 * 7, 512 * 7, 512 * 7,
|
||||
512 * 9, 512 * 9, 512 * 9, 512 * 9, 512 * 9, 512 * 9, 512 * 9, 512 * 9,
|
||||
512 * 9, 512 * 9, 512 * 9, 512 * 9, 512 * 9, 512 * 9, 512 * 9, 512 * 9
|
||||
};
|
||||
static const int golomb_cost_diff[32] = {
|
||||
0, 512, 512 * 2, 0, 512 * 2, 0, 0, 0, 512 * 2, 0, 0, 0, 0, 0, 0, 0,
|
||||
512 * 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
static INLINE int get_golomb_cost(int abs_qc) {
|
||||
if (abs_qc >= 1 + NUM_BASE_LEVELS + COEFF_BASE_RANGE) {
|
||||
|
|
@ -308,6 +304,32 @@ static INLINE int get_golomb_cost(int abs_qc) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static INLINE int get_br_cost_with_diff(tran_low_t level, const int *coeff_lps,
|
||||
int *diff) {
|
||||
const int base_range = AOMMIN(level - 1 - NUM_BASE_LEVELS, COEFF_BASE_RANGE);
|
||||
int golomb_bits = 0;
|
||||
if (level <= COEFF_BASE_RANGE + 1 + NUM_BASE_LEVELS)
|
||||
*diff += coeff_lps[base_range + COEFF_BASE_RANGE + 1];
|
||||
|
||||
if (level >= COEFF_BASE_RANGE + 1 + NUM_BASE_LEVELS) {
|
||||
int r = level - COEFF_BASE_RANGE - NUM_BASE_LEVELS;
|
||||
if (r < 32) {
|
||||
golomb_bits = golomb_bits_cost[r];
|
||||
*diff += golomb_cost_diff[r];
|
||||
} else {
|
||||
golomb_bits = get_golomb_cost(level);
|
||||
*diff += (r & (r - 1)) == 0 ? 1024 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
return coeff_lps[base_range] + golomb_bits;
|
||||
}
|
||||
|
||||
static INLINE int get_br_cost(tran_low_t level, const int *coeff_lps) {
|
||||
const int base_range = AOMMIN(level - 1 - NUM_BASE_LEVELS, COEFF_BASE_RANGE);
|
||||
return coeff_lps[base_range] + get_golomb_cost(level);
|
||||
}
|
||||
|
||||
static int get_coeff_cost(const tran_low_t qc, const int scan_idx,
|
||||
const int is_eob, const TxbInfo *const txb_info,
|
||||
const LV_MAP_COEFF_COST *const txb_costs,
|
||||
|
|
@ -331,8 +353,7 @@ static int get_coeff_cost(const tran_low_t qc, const int scan_idx,
|
|||
if (abs_qc > NUM_BASE_LEVELS) {
|
||||
const int ctx =
|
||||
get_br_ctx(txb_info->levels, pos, txb_info->bwl, tx_class);
|
||||
cost += get_br_cost(abs_qc, ctx, txb_costs->lps_cost[ctx]);
|
||||
cost += get_golomb_cost(abs_qc);
|
||||
cost += get_br_cost(abs_qc, txb_costs->lps_cost[ctx]);
|
||||
}
|
||||
}
|
||||
return cost;
|
||||
|
|
@ -464,8 +485,6 @@ void av1_txb_init_levels_c(const tran_low_t *const coeff, const int width,
|
|||
const int stride = width + TX_PAD_HOR;
|
||||
uint8_t *ls = levels;
|
||||
|
||||
memset(levels - TX_PAD_TOP * stride, 0,
|
||||
sizeof(*levels) * TX_PAD_TOP * stride);
|
||||
memset(levels + stride * height, 0,
|
||||
sizeof(*levels) * (TX_PAD_BOTTOM * stride + TX_PAD_END));
|
||||
|
||||
|
|
@ -554,14 +573,15 @@ void av1_write_coeffs_txb(const AV1_COMMON *const cm, MACROBLOCKD *xd,
|
|||
break;
|
||||
}
|
||||
|
||||
if (k_eob_offset_bits[eob_pt] > 0) {
|
||||
const int eob_offset_bits = k_eob_offset_bits[eob_pt];
|
||||
if (eob_offset_bits > 0) {
|
||||
const int eob_ctx = eob_pt - 3;
|
||||
int eob_shift = k_eob_offset_bits[eob_pt] - 1;
|
||||
int eob_shift = eob_offset_bits - 1;
|
||||
int bit = (eob_extra & (1 << eob_shift)) ? 1 : 0;
|
||||
aom_write_symbol(w, bit,
|
||||
ec_ctx->eob_extra_cdf[txs_ctx][plane_type][eob_ctx], 2);
|
||||
for (int i = 1; i < k_eob_offset_bits[eob_pt]; i++) {
|
||||
eob_shift = k_eob_offset_bits[eob_pt] - 1 - i;
|
||||
for (int i = 1; i < eob_offset_bits; i++) {
|
||||
eob_shift = eob_offset_bits - 1 - i;
|
||||
bit = (eob_extra & (1 << eob_shift)) ? 1 : 0;
|
||||
aom_write_bit(w, bit);
|
||||
}
|
||||
|
|
@ -588,12 +608,11 @@ void av1_write_coeffs_txb(const AV1_COMMON *const cm, MACROBLOCKD *xd,
|
|||
// level is above 1.
|
||||
const int base_range = level - 1 - NUM_BASE_LEVELS;
|
||||
const int br_ctx = get_br_ctx(levels, pos, bwl, tx_class);
|
||||
aom_cdf_prob *cdf =
|
||||
ec_ctx->coeff_br_cdf[AOMMIN(txs_ctx, TX_32X32)][plane_type][br_ctx];
|
||||
for (int idx = 0; idx < COEFF_BASE_RANGE; idx += BR_CDF_SIZE - 1) {
|
||||
const int k = AOMMIN(base_range - idx, BR_CDF_SIZE - 1);
|
||||
aom_write_symbol(
|
||||
w, k,
|
||||
ec_ctx->coeff_br_cdf[AOMMIN(txs_ctx, TX_32X32)][plane_type][br_ctx],
|
||||
BR_CDF_SIZE);
|
||||
aom_write_symbol(w, k, cdf, BR_CDF_SIZE);
|
||||
if (k < BR_CDF_SIZE - 1) break;
|
||||
}
|
||||
}
|
||||
|
|
@ -745,7 +764,8 @@ static AOM_FORCE_INLINE int warehouse_efficients_txb(
|
|||
|
||||
av1_get_nz_map_contexts(levels, scan, eob, tx_size, tx_class, coeff_contexts);
|
||||
|
||||
const int(*lps_cost)[COEFF_BASE_RANGE + 1] = coeff_costs->lps_cost;
|
||||
const int(*lps_cost)[COEFF_BASE_RANGE + 1 + COEFF_BASE_RANGE + 1] =
|
||||
coeff_costs->lps_cost;
|
||||
int c = eob - 1;
|
||||
{
|
||||
const int pos = scan[c];
|
||||
|
|
@ -758,11 +778,8 @@ static AOM_FORCE_INLINE int warehouse_efficients_txb(
|
|||
if (v) {
|
||||
// sign bit cost
|
||||
if (level > NUM_BASE_LEVELS) {
|
||||
const int ctx = get_br_ctx(levels, pos, bwl, tx_class);
|
||||
const int base_range =
|
||||
AOMMIN(level - 1 - NUM_BASE_LEVELS, COEFF_BASE_RANGE);
|
||||
cost += lps_cost[ctx][base_range];
|
||||
cost += get_golomb_cost(level);
|
||||
const int ctx = get_br_ctx_eob(pos, bwl, tx_class);
|
||||
cost += get_br_cost(level, lps_cost[ctx]);
|
||||
}
|
||||
if (c) {
|
||||
cost += av1_cost_literal(1);
|
||||
|
|
@ -774,7 +791,7 @@ static AOM_FORCE_INLINE int warehouse_efficients_txb(
|
|||
}
|
||||
}
|
||||
}
|
||||
const int(*base_cost)[4] = coeff_costs->base_cost;
|
||||
const int(*base_cost)[8] = coeff_costs->base_cost;
|
||||
for (c = eob - 2; c >= 1; --c) {
|
||||
const int pos = scan[c];
|
||||
const int coeff_ctx = coeff_contexts[pos];
|
||||
|
|
@ -786,10 +803,7 @@ static AOM_FORCE_INLINE int warehouse_efficients_txb(
|
|||
cost += av1_cost_literal(1);
|
||||
if (level > NUM_BASE_LEVELS) {
|
||||
const int ctx = get_br_ctx(levels, pos, bwl, tx_class);
|
||||
const int base_range =
|
||||
AOMMIN(level - 1 - NUM_BASE_LEVELS, COEFF_BASE_RANGE);
|
||||
cost += lps_cost[ctx][base_range];
|
||||
cost += get_golomb_cost(level);
|
||||
cost += get_br_cost(level, lps_cost[ctx]);
|
||||
}
|
||||
}
|
||||
cost += cost0;
|
||||
|
|
@ -809,10 +823,7 @@ static AOM_FORCE_INLINE int warehouse_efficients_txb(
|
|||
cost += coeff_costs->dc_sign_cost[dc_sign_ctx][sign01];
|
||||
if (level > NUM_BASE_LEVELS) {
|
||||
const int ctx = get_br_ctx(levels, pos, bwl, tx_class);
|
||||
const int base_range =
|
||||
AOMMIN(level - 1 - NUM_BASE_LEVELS, COEFF_BASE_RANGE);
|
||||
cost += lps_cost[ctx][base_range];
|
||||
cost += get_golomb_cost(level);
|
||||
cost += get_br_cost(level, lps_cost[ctx]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1014,13 +1025,7 @@ static int optimize_txb(TxbInfo *txb_info, const LV_MAP_COEFF_COST *txb_costs,
|
|||
return update;
|
||||
}
|
||||
|
||||
// These numbers are empirically obtained.
|
||||
static const int plane_rd_mult[REF_TYPES][PLANE_TYPES] = {
|
||||
{ 17, 13 },
|
||||
{ 16, 10 },
|
||||
};
|
||||
|
||||
void hbt_init() {
|
||||
static void hbt_init() {
|
||||
hbt_hash_table =
|
||||
aom_malloc(sizeof(OptTxbQcoeff) * HBT_TABLE_SIZE * HBT_ARRAY_LENGTH);
|
||||
memset(hbt_hash_table, 0,
|
||||
|
|
@ -1032,11 +1037,11 @@ void hbt_init() {
|
|||
|
||||
void hbt_destroy() { aom_free(hbt_hash_table); }
|
||||
|
||||
int hbt_hash_miss(uint32_t hbt_ctx_hash, uint32_t hbt_qc_hash,
|
||||
TxbInfo *txb_info, const LV_MAP_COEFF_COST *txb_costs,
|
||||
const LV_MAP_EOB_COST *txb_eob_costs,
|
||||
const struct macroblock_plane *p, int block, int fast_mode,
|
||||
int *rate_cost) {
|
||||
static int hbt_hash_miss(uint32_t hbt_ctx_hash, uint32_t hbt_qc_hash,
|
||||
TxbInfo *txb_info, const LV_MAP_COEFF_COST *txb_costs,
|
||||
const LV_MAP_EOB_COST *txb_eob_costs,
|
||||
const struct macroblock_plane *p, int block,
|
||||
int fast_mode, int *rate_cost) {
|
||||
(void)fast_mode;
|
||||
const int16_t *scan = txb_info->scan_order->scan;
|
||||
int prev_eob = txb_info->eob;
|
||||
|
|
@ -1098,9 +1103,9 @@ int hbt_hash_miss(uint32_t hbt_ctx_hash, uint32_t hbt_qc_hash,
|
|||
return txb_info->eob;
|
||||
}
|
||||
|
||||
int hbt_hash_hit(uint32_t hbt_table_index, int hbt_array_index,
|
||||
TxbInfo *txb_info, const struct macroblock_plane *p, int block,
|
||||
int *rate_cost) {
|
||||
static int hbt_hash_hit(uint32_t hbt_table_index, int hbt_array_index,
|
||||
TxbInfo *txb_info, const struct macroblock_plane *p,
|
||||
int block, int *rate_cost) {
|
||||
const int16_t *scan = txb_info->scan_order->scan;
|
||||
int new_eob = 0;
|
||||
int update = 0;
|
||||
|
|
@ -1140,11 +1145,12 @@ int hbt_hash_hit(uint32_t hbt_table_index, int hbt_array_index,
|
|||
return txb_info->eob;
|
||||
}
|
||||
|
||||
int hbt_search_match(uint32_t hbt_ctx_hash, uint32_t hbt_qc_hash,
|
||||
TxbInfo *txb_info, const LV_MAP_COEFF_COST *txb_costs,
|
||||
const LV_MAP_EOB_COST *txb_eob_costs,
|
||||
const struct macroblock_plane *p, int block, int fast_mode,
|
||||
int *rate_cost) {
|
||||
static int hbt_search_match(uint32_t hbt_ctx_hash, uint32_t hbt_qc_hash,
|
||||
TxbInfo *txb_info,
|
||||
const LV_MAP_COEFF_COST *txb_costs,
|
||||
const LV_MAP_EOB_COST *txb_eob_costs,
|
||||
const struct macroblock_plane *p, int block,
|
||||
int fast_mode, int *rate_cost) {
|
||||
// Check for qcoeff match
|
||||
int hbt_array_index = hbt_qc_hash % HBT_ARRAY_LENGTH;
|
||||
int hbt_table_index = hbt_ctx_hash % HBT_TABLE_SIZE;
|
||||
|
|
@ -1163,10 +1169,11 @@ int hbt_search_match(uint32_t hbt_ctx_hash, uint32_t hbt_qc_hash,
|
|||
}
|
||||
}
|
||||
|
||||
int hbt_create_hashes(TxbInfo *txb_info, const LV_MAP_COEFF_COST *txb_costs,
|
||||
const LV_MAP_EOB_COST *txb_eob_costs,
|
||||
const struct macroblock_plane *p, int block,
|
||||
int fast_mode, int *rate_cost) {
|
||||
static int hbt_create_hashes(TxbInfo *txb_info,
|
||||
const LV_MAP_COEFF_COST *txb_costs,
|
||||
const LV_MAP_EOB_COST *txb_eob_costs,
|
||||
const struct macroblock_plane *p, int block,
|
||||
int fast_mode, int *rate_cost) {
|
||||
// Initialize hash table if needed.
|
||||
if (hbt_needs_init) {
|
||||
hbt_init();
|
||||
|
|
@ -1288,20 +1295,47 @@ int hbt_create_hashes(TxbInfo *txb_info, const LV_MAP_COEFF_COST *txb_costs,
|
|||
txb_eob_costs, p, block, fast_mode, rate_cost);
|
||||
}
|
||||
|
||||
static AOM_FORCE_INLINE int get_coeff_cost_simple(
|
||||
static AOM_FORCE_INLINE int get_two_coeff_cost_simple(
|
||||
int ci, tran_low_t abs_qc, int coeff_ctx,
|
||||
const LV_MAP_COEFF_COST *txb_costs, int bwl, TX_CLASS tx_class,
|
||||
const uint8_t *levels) {
|
||||
const uint8_t *levels, int *cost_low) {
|
||||
// this simple version assumes the coeff's scan_idx is not DC (scan_idx != 0)
|
||||
// and not the last (scan_idx != eob - 1)
|
||||
assert(ci > 0);
|
||||
int cost = txb_costs->base_cost[coeff_ctx][AOMMIN(abs_qc, 3)];
|
||||
int diff = 0;
|
||||
if (abs_qc <= 3) diff = txb_costs->base_cost[coeff_ctx][abs_qc + 4];
|
||||
if (abs_qc) {
|
||||
cost += av1_cost_literal(1);
|
||||
if (abs_qc > NUM_BASE_LEVELS) {
|
||||
const int br_ctx = get_br_ctx(levels, ci, bwl, tx_class);
|
||||
cost += get_br_cost(abs_qc, br_ctx, txb_costs->lps_cost[br_ctx]);
|
||||
cost += get_golomb_cost(abs_qc);
|
||||
int brcost_diff = 0;
|
||||
cost += get_br_cost_with_diff(abs_qc, txb_costs->lps_cost[br_ctx],
|
||||
&brcost_diff);
|
||||
diff += brcost_diff;
|
||||
}
|
||||
}
|
||||
*cost_low = cost - diff;
|
||||
|
||||
return cost;
|
||||
}
|
||||
|
||||
static INLINE int get_coeff_cost_eob(int ci, tran_low_t abs_qc, int sign,
|
||||
int coeff_ctx, int dc_sign_ctx,
|
||||
const LV_MAP_COEFF_COST *txb_costs,
|
||||
int bwl, TX_CLASS tx_class) {
|
||||
int cost = 0;
|
||||
cost += txb_costs->base_eob_cost[coeff_ctx][AOMMIN(abs_qc, 3) - 1];
|
||||
if (abs_qc != 0) {
|
||||
if (ci == 0) {
|
||||
cost += txb_costs->dc_sign_cost[dc_sign_ctx][sign];
|
||||
} else {
|
||||
cost += av1_cost_literal(1);
|
||||
}
|
||||
if (abs_qc > NUM_BASE_LEVELS) {
|
||||
int br_ctx;
|
||||
br_ctx = get_br_ctx_eob(ci, bwl, tx_class);
|
||||
cost += get_br_cost(abs_qc, txb_costs->lps_cost[br_ctx]);
|
||||
}
|
||||
}
|
||||
return cost;
|
||||
|
|
@ -1326,9 +1360,12 @@ static INLINE int get_coeff_cost_general(int is_last, int ci, tran_low_t abs_qc,
|
|||
cost += av1_cost_literal(1);
|
||||
}
|
||||
if (abs_qc > NUM_BASE_LEVELS) {
|
||||
const int br_ctx = get_br_ctx(levels, ci, bwl, tx_class);
|
||||
cost += get_br_cost(abs_qc, br_ctx, txb_costs->lps_cost[br_ctx]);
|
||||
cost += get_golomb_cost(abs_qc);
|
||||
int br_ctx;
|
||||
if (is_last)
|
||||
br_ctx = get_br_ctx_eob(ci, bwl, tx_class);
|
||||
else
|
||||
br_ctx = get_br_ctx(levels, ci, bwl, tx_class);
|
||||
cost += get_br_cost(abs_qc, txb_costs->lps_cost[br_ctx]);
|
||||
}
|
||||
}
|
||||
return cost;
|
||||
|
|
@ -1372,13 +1409,23 @@ static INLINE void update_coeff_general(
|
|||
const int64_t rd = RDCOST(rdmult, rate, dist);
|
||||
|
||||
tran_low_t qc_low, dqc_low;
|
||||
get_qc_dqc_low(abs_qc, sign, dqv, shift, &qc_low, &dqc_low);
|
||||
const tran_low_t abs_qc_low = abs_qc - 1;
|
||||
const int64_t dist_low = get_coeff_dist(tqc, dqc_low, shift);
|
||||
const int rate_low =
|
||||
get_coeff_cost_general(is_last, ci, abs_qc_low, sign, coeff_ctx,
|
||||
dc_sign_ctx, txb_costs, bwl, tx_class, levels);
|
||||
const int64_t rd_low = RDCOST(rdmult, rate_low, dist_low);
|
||||
tran_low_t abs_qc_low;
|
||||
int64_t dist_low, rd_low;
|
||||
int rate_low;
|
||||
if (abs_qc == 1) {
|
||||
abs_qc_low = qc_low = dqc_low = 0;
|
||||
dist_low = dist0;
|
||||
rate_low = txb_costs->base_cost[coeff_ctx][0];
|
||||
} else {
|
||||
get_qc_dqc_low(abs_qc, sign, dqv, shift, &qc_low, &dqc_low);
|
||||
abs_qc_low = abs_qc - 1;
|
||||
dist_low = get_coeff_dist(tqc, dqc_low, shift);
|
||||
rate_low =
|
||||
get_coeff_cost_general(is_last, ci, abs_qc_low, sign, coeff_ctx,
|
||||
dc_sign_ctx, txb_costs, bwl, tx_class, levels);
|
||||
}
|
||||
|
||||
rd_low = RDCOST(rdmult, rate_low, dist_low);
|
||||
if (rd_low < rd) {
|
||||
qcoeff[ci] = qc_low;
|
||||
dqcoeff[ci] = dqc_low;
|
||||
|
|
@ -1412,28 +1459,28 @@ static AOM_FORCE_INLINE void update_coeff_simple(
|
|||
*accu_rate += txb_costs->base_cost[coeff_ctx][0];
|
||||
} else {
|
||||
const tran_low_t abs_qc = abs(qc);
|
||||
const tran_low_t tqc = tcoeff[ci];
|
||||
const tran_low_t dqc = dqcoeff[ci];
|
||||
const int rate = get_coeff_cost_simple(ci, abs_qc, coeff_ctx, txb_costs,
|
||||
bwl, tx_class, levels);
|
||||
if (abs(dqc) < abs(tqc)) {
|
||||
const tran_low_t abs_tqc = abs(tcoeff[ci]);
|
||||
const tran_low_t abs_dqc = abs(dqcoeff[ci]);
|
||||
int rate_low = 0;
|
||||
const int rate = get_two_coeff_cost_simple(
|
||||
ci, abs_qc, coeff_ctx, txb_costs, bwl, tx_class, levels, &rate_low);
|
||||
if (abs_dqc < abs_tqc) {
|
||||
*accu_rate += rate;
|
||||
return;
|
||||
}
|
||||
const int64_t dist = get_coeff_dist(tqc, dqc, shift);
|
||||
|
||||
const int64_t dist = get_coeff_dist(abs_tqc, abs_dqc, shift);
|
||||
const int64_t rd = RDCOST(rdmult, rate, dist);
|
||||
|
||||
const int sign = (qc < 0) ? 1 : 0;
|
||||
tran_low_t qc_low, dqc_low;
|
||||
get_qc_dqc_low(abs_qc, sign, dqv, shift, &qc_low, &dqc_low);
|
||||
const tran_low_t abs_qc_low = abs_qc - 1;
|
||||
const int64_t dist_low = get_coeff_dist(tqc, dqc_low, shift);
|
||||
const int rate_low = get_coeff_cost_simple(
|
||||
ci, abs_qc_low, coeff_ctx, txb_costs, bwl, tx_class, levels);
|
||||
const tran_low_t abs_dqc_low = (abs_qc_low * dqv) >> shift;
|
||||
const int64_t dist_low = get_coeff_dist(abs_tqc, abs_dqc_low, shift);
|
||||
const int64_t rd_low = RDCOST(rdmult, rate_low, dist_low);
|
||||
|
||||
if (rd_low < rd) {
|
||||
qcoeff[ci] = qc_low;
|
||||
dqcoeff[ci] = dqc_low;
|
||||
const int sign = (qc < 0) ? 1 : 0;
|
||||
qcoeff[ci] = (-sign ^ abs_qc_low) + sign;
|
||||
dqcoeff[ci] = (-sign ^ abs_dqc_low) + sign;
|
||||
levels[get_padded_idx(ci, bwl)] = AOMMIN(abs_qc_low, INT8_MAX);
|
||||
*accu_rate += rate_low;
|
||||
} else {
|
||||
|
|
@ -1471,40 +1518,42 @@ static AOM_FORCE_INLINE void update_coeff_eob(
|
|||
int64_t rd = RDCOST(rdmult, *accu_rate + rate, *accu_dist + dist);
|
||||
|
||||
tran_low_t qc_low, dqc_low;
|
||||
get_qc_dqc_low(abs_qc, sign, dqv, shift, &qc_low, &dqc_low);
|
||||
const tran_low_t abs_qc_low = abs_qc - 1;
|
||||
const int64_t dist_low = get_coeff_dist(tqc, dqc_low, shift) - dist0;
|
||||
const int rate_low =
|
||||
get_coeff_cost_general(0, ci, abs_qc_low, sign, coeff_ctx, dc_sign_ctx,
|
||||
txb_costs, bwl, tx_class, levels);
|
||||
const int64_t rd_low =
|
||||
RDCOST(rdmult, *accu_rate + rate_low, *accu_dist + dist_low);
|
||||
tran_low_t abs_qc_low;
|
||||
int64_t dist_low, rd_low;
|
||||
int rate_low;
|
||||
if (abs_qc == 1) {
|
||||
abs_qc_low = 0;
|
||||
dqc_low = qc_low = 0;
|
||||
dist_low = 0;
|
||||
rate_low = txb_costs->base_cost[coeff_ctx][0];
|
||||
rd_low = RDCOST(rdmult, *accu_rate + rate_low, *accu_dist);
|
||||
} else {
|
||||
get_qc_dqc_low(abs_qc, sign, dqv, shift, &qc_low, &dqc_low);
|
||||
abs_qc_low = abs_qc - 1;
|
||||
dist_low = get_coeff_dist(tqc, dqc_low, shift) - dist0;
|
||||
rate_low =
|
||||
get_coeff_cost_general(0, ci, abs_qc_low, sign, coeff_ctx,
|
||||
dc_sign_ctx, txb_costs, bwl, tx_class, levels);
|
||||
rd_low = RDCOST(rdmult, *accu_rate + rate_low, *accu_dist + dist_low);
|
||||
}
|
||||
|
||||
int lower_level_new_eob = 0;
|
||||
const int new_eob = si + 1;
|
||||
uint8_t tmp_levels[3];
|
||||
for (int ni = 0; ni < *nz_num; ++ni) {
|
||||
const int last_ci = nz_ci[ni];
|
||||
tmp_levels[ni] = levels[get_padded_idx(last_ci, bwl)];
|
||||
levels[get_padded_idx(last_ci, bwl)] = 0;
|
||||
}
|
||||
|
||||
const int coeff_ctx_new_eob = get_lower_levels_ctx_general(
|
||||
1, si, bwl, height, levels, ci, tx_size, tx_class);
|
||||
const int coeff_ctx_new_eob = get_lower_levels_ctx_eob(bwl, height, si);
|
||||
const int new_eob_cost =
|
||||
get_eob_cost(new_eob, txb_eob_costs, txb_costs, tx_class);
|
||||
int rate_coeff_eob =
|
||||
new_eob_cost + get_coeff_cost_general(1, ci, abs_qc, sign,
|
||||
coeff_ctx_new_eob, dc_sign_ctx,
|
||||
txb_costs, bwl, tx_class, levels);
|
||||
new_eob_cost + get_coeff_cost_eob(ci, abs_qc, sign, coeff_ctx_new_eob,
|
||||
dc_sign_ctx, txb_costs, bwl,
|
||||
tx_class);
|
||||
int64_t dist_new_eob = dist;
|
||||
int64_t rd_new_eob = RDCOST(rdmult, rate_coeff_eob, dist_new_eob);
|
||||
|
||||
if (abs_qc_low > 0) {
|
||||
const int rate_coeff_eob_low =
|
||||
new_eob_cost +
|
||||
get_coeff_cost_general(1, ci, abs_qc_low, sign, coeff_ctx_new_eob,
|
||||
dc_sign_ctx, txb_costs, bwl, tx_class, levels);
|
||||
new_eob_cost + get_coeff_cost_eob(ci, abs_qc_low, sign,
|
||||
coeff_ctx_new_eob, dc_sign_ctx,
|
||||
txb_costs, bwl, tx_class);
|
||||
const int64_t dist_new_eob_low = dist_low;
|
||||
const int64_t rd_new_eob_low =
|
||||
RDCOST(rdmult, rate_coeff_eob_low, dist_new_eob_low);
|
||||
|
|
@ -1526,7 +1575,7 @@ static AOM_FORCE_INLINE void update_coeff_eob(
|
|||
if (sharpness == 0 && rd_new_eob < rd) {
|
||||
for (int ni = 0; ni < *nz_num; ++ni) {
|
||||
int last_ci = nz_ci[ni];
|
||||
// levels[get_padded_idx(last_ci, bwl)] = 0;
|
||||
levels[get_padded_idx(last_ci, bwl)] = 0;
|
||||
qcoeff[last_ci] = 0;
|
||||
dqcoeff[last_ci] = 0;
|
||||
}
|
||||
|
|
@ -1536,10 +1585,6 @@ static AOM_FORCE_INLINE void update_coeff_eob(
|
|||
*accu_dist = dist_new_eob;
|
||||
lower_level = lower_level_new_eob;
|
||||
} else {
|
||||
for (int ni = 0; ni < *nz_num; ++ni) {
|
||||
const int last_ci = nz_ci[ni];
|
||||
levels[get_padded_idx(last_ci, bwl)] = tmp_levels[ni];
|
||||
}
|
||||
*accu_rate += rate;
|
||||
*accu_dist += dist;
|
||||
}
|
||||
|
|
@ -1619,14 +1664,14 @@ int av1_optimize_txb_new(const struct AV1_COMP *cpi, MACROBLOCK *x, int plane,
|
|||
|
||||
uint8_t levels_buf[TX_PAD_2D];
|
||||
uint8_t *const levels = set_levels(levels_buf, width);
|
||||
int eob = p->eobs[block];
|
||||
|
||||
av1_txb_init_levels(qcoeff, width, height, levels);
|
||||
if (eob > 1) av1_txb_init_levels(qcoeff, width, height, levels);
|
||||
|
||||
// TODO(angirbird): check iqmatrix
|
||||
|
||||
const int non_skip_cost = txb_costs->txb_skip_cost[txb_ctx->txb_skip_ctx][0];
|
||||
const int skip_cost = txb_costs->txb_skip_cost[txb_ctx->txb_skip_ctx][1];
|
||||
int eob = p->eobs[block];
|
||||
const int eob_cost = get_eob_cost(eob, txb_eob_costs, txb_costs, tx_class);
|
||||
int accu_rate = eob_cost;
|
||||
int64_t accu_dist = 0;
|
||||
|
|
@ -1646,11 +1691,10 @@ int av1_optimize_txb_new(const struct AV1_COMP *cpi, MACROBLOCK *x, int plane,
|
|||
--si;
|
||||
} else {
|
||||
assert(abs_qc == 1);
|
||||
const int coeff_ctx = get_lower_levels_ctx_general(
|
||||
1, si, bwl, height, levels, ci, tx_size, tx_class);
|
||||
accu_rate += get_coeff_cost_general(1, ci, abs_qc, sign, coeff_ctx,
|
||||
txb_ctx->dc_sign_ctx, txb_costs, bwl,
|
||||
tx_class, levels);
|
||||
const int coeff_ctx = get_lower_levels_ctx_eob(bwl, height, si);
|
||||
accu_rate +=
|
||||
get_coeff_cost_eob(ci, abs_qc, sign, coeff_ctx, txb_ctx->dc_sign_ctx,
|
||||
txb_costs, bwl, tx_class);
|
||||
const tran_low_t tqc = tcoeff[ci];
|
||||
const tran_low_t dqc = dqcoeff[ci];
|
||||
const int64_t dist = get_coeff_dist(tqc, dqc, shift);
|
||||
|
|
@ -1767,10 +1811,9 @@ int av1_optimize_txb(const struct AV1_COMP *cpi, MACROBLOCK *x, int plane,
|
|||
assert(width == (1 << bwl));
|
||||
const int tx_type_cost = get_tx_type_cost(cm, x, xd, plane, tx_size, tx_type);
|
||||
TxbInfo txb_info = {
|
||||
qcoeff, levels, dqcoeff, tcoeff, dequant, shift,
|
||||
tx_size, txs_ctx, tx_type, bwl, width, height,
|
||||
eob, seg_eob, scan_order, txb_ctx, rdmult, &cm->coeff_ctx_table,
|
||||
iqmatrix, tx_type_cost,
|
||||
qcoeff, levels, dqcoeff, tcoeff, dequant, shift, tx_size,
|
||||
txs_ctx, tx_type, bwl, width, height, eob, seg_eob,
|
||||
scan_order, txb_ctx, rdmult, iqmatrix, tx_type_cost,
|
||||
};
|
||||
|
||||
// Hash based trellis (hbt) speed feature: avoid expensive optimize_txb calls
|
||||
|
|
|
|||
8
third_party/aom/av1/encoder/encodetxb.h
vendored
8
third_party/aom/av1/encoder/encodetxb.h
vendored
|
|
@ -42,7 +42,6 @@ typedef struct TxbInfo {
|
|||
const SCAN_ORDER *scan_order;
|
||||
TXB_CTX *txb_ctx;
|
||||
int64_t rdmult;
|
||||
const LV_MAP_CTX_TABLE *coeff_ctx_table;
|
||||
const qm_val_t *iqmatrix;
|
||||
int tx_type_cost;
|
||||
} TxbInfo;
|
||||
|
|
@ -80,6 +79,13 @@ int av1_optimize_txb_new(const struct AV1_COMP *cpi, MACROBLOCK *x, int plane,
|
|||
int block, TX_SIZE tx_size, TX_TYPE tx_type,
|
||||
const TXB_CTX *const txb_ctx, int *rate_cost,
|
||||
int sharpness);
|
||||
|
||||
// These numbers are empirically obtained.
|
||||
static const int plane_rd_mult[REF_TYPES][PLANE_TYPES] = {
|
||||
{ 17, 13 },
|
||||
{ 16, 10 },
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
445
third_party/aom/av1/encoder/ethread.c
vendored
445
third_party/aom/av1/encoder/ethread.c
vendored
|
|
@ -9,9 +9,11 @@
|
|||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include "av1/encoder/av1_multi_thread.h"
|
||||
#include "av1/encoder/encodeframe.h"
|
||||
#include "av1/encoder/encoder.h"
|
||||
#include "av1/encoder/ethread.h"
|
||||
#include "av1/encoder/rdopt.h"
|
||||
#include "aom_dsp/aom_dsp_common.h"
|
||||
|
||||
static void accumulate_rd_opt(ThreadData *td, ThreadData *td_t) {
|
||||
|
|
@ -27,6 +29,318 @@ static void accumulate_rd_opt(ThreadData *td, ThreadData *td_t) {
|
|||
td->rd_counts.skip_mode_used_flag |= td_t->rd_counts.skip_mode_used_flag;
|
||||
}
|
||||
|
||||
static void update_delta_lf_for_row_mt(AV1_COMP *cpi) {
|
||||
AV1_COMMON *cm = &cpi->common;
|
||||
MACROBLOCKD *xd = &cpi->td.mb.e_mbd;
|
||||
const int mib_size = cm->seq_params.mib_size;
|
||||
const int frame_lf_count =
|
||||
av1_num_planes(cm) > 1 ? FRAME_LF_COUNT : FRAME_LF_COUNT - 2;
|
||||
for (int row = 0; row < cm->tile_rows; row++) {
|
||||
for (int col = 0; col < cm->tile_cols; col++) {
|
||||
TileDataEnc *tile_data = &cpi->tile_data[row * cm->tile_cols + col];
|
||||
const TileInfo *const tile_info = &tile_data->tile_info;
|
||||
for (int mi_row = tile_info->mi_row_start; mi_row < tile_info->mi_row_end;
|
||||
mi_row += mib_size) {
|
||||
if (mi_row == tile_info->mi_row_start)
|
||||
av1_reset_loop_filter_delta(xd, av1_num_planes(cm));
|
||||
for (int mi_col = tile_info->mi_col_start;
|
||||
mi_col < tile_info->mi_col_end; mi_col += mib_size) {
|
||||
const int idx_str = cm->mi_stride * mi_row + mi_col;
|
||||
MB_MODE_INFO **mi = cm->mi_grid_visible + idx_str;
|
||||
MB_MODE_INFO *mbmi = mi[0];
|
||||
if (mbmi->skip == 1 && (mbmi->sb_type == cm->seq_params.sb_size)) {
|
||||
for (int lf_id = 0; lf_id < frame_lf_count; ++lf_id)
|
||||
mbmi->delta_lf[lf_id] = xd->delta_lf[lf_id];
|
||||
mbmi->delta_lf_from_base = xd->delta_lf_from_base;
|
||||
} else {
|
||||
if (cm->delta_q_info.delta_lf_multi) {
|
||||
for (int lf_id = 0; lf_id < frame_lf_count; ++lf_id)
|
||||
xd->delta_lf[lf_id] = mbmi->delta_lf[lf_id];
|
||||
} else {
|
||||
xd->delta_lf_from_base = mbmi->delta_lf_from_base;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void av1_row_mt_sync_read_dummy(struct AV1RowMTSyncData *const row_mt_sync,
|
||||
int r, int c) {
|
||||
(void)row_mt_sync;
|
||||
(void)r;
|
||||
(void)c;
|
||||
return;
|
||||
}
|
||||
|
||||
void av1_row_mt_sync_write_dummy(struct AV1RowMTSyncData *const row_mt_sync,
|
||||
int r, int c, const int cols) {
|
||||
(void)row_mt_sync;
|
||||
(void)r;
|
||||
(void)c;
|
||||
(void)cols;
|
||||
return;
|
||||
}
|
||||
|
||||
void av1_row_mt_sync_read(AV1RowMTSync *const row_mt_sync, int r, int c) {
|
||||
#if CONFIG_MULTITHREAD
|
||||
const int nsync = row_mt_sync->sync_range;
|
||||
|
||||
if (r) {
|
||||
pthread_mutex_t *const mutex = &row_mt_sync->mutex_[r - 1];
|
||||
pthread_mutex_lock(mutex);
|
||||
|
||||
while (c > row_mt_sync->cur_col[r - 1] - nsync) {
|
||||
pthread_cond_wait(&row_mt_sync->cond_[r - 1], mutex);
|
||||
}
|
||||
pthread_mutex_unlock(mutex);
|
||||
}
|
||||
#else
|
||||
(void)row_mt_sync;
|
||||
(void)r;
|
||||
(void)c;
|
||||
#endif // CONFIG_MULTITHREAD
|
||||
}
|
||||
|
||||
void av1_row_mt_sync_write(AV1RowMTSync *const row_mt_sync, int r, int c,
|
||||
const int cols) {
|
||||
#if CONFIG_MULTITHREAD
|
||||
const int nsync = row_mt_sync->sync_range;
|
||||
int cur;
|
||||
// Only signal when there are enough encoded blocks for next row to run.
|
||||
int sig = 1;
|
||||
|
||||
if (c < cols - 1) {
|
||||
cur = c;
|
||||
if (c % nsync) sig = 0;
|
||||
} else {
|
||||
cur = cols + nsync;
|
||||
}
|
||||
|
||||
if (sig) {
|
||||
pthread_mutex_lock(&row_mt_sync->mutex_[r]);
|
||||
|
||||
row_mt_sync->cur_col[r] = cur;
|
||||
|
||||
pthread_cond_signal(&row_mt_sync->cond_[r]);
|
||||
pthread_mutex_unlock(&row_mt_sync->mutex_[r]);
|
||||
}
|
||||
#else
|
||||
(void)row_mt_sync;
|
||||
(void)r;
|
||||
(void)c;
|
||||
(void)cols;
|
||||
#endif // CONFIG_MULTITHREAD
|
||||
}
|
||||
|
||||
// Allocate memory for row synchronization
|
||||
void av1_row_mt_sync_mem_alloc(AV1RowMTSync *row_mt_sync, AV1_COMMON *cm,
|
||||
int rows) {
|
||||
row_mt_sync->rows = rows;
|
||||
#if CONFIG_MULTITHREAD
|
||||
{
|
||||
int i;
|
||||
|
||||
CHECK_MEM_ERROR(cm, row_mt_sync->mutex_,
|
||||
aom_malloc(sizeof(*row_mt_sync->mutex_) * rows));
|
||||
if (row_mt_sync->mutex_) {
|
||||
for (i = 0; i < rows; ++i) {
|
||||
pthread_mutex_init(&row_mt_sync->mutex_[i], NULL);
|
||||
}
|
||||
}
|
||||
|
||||
CHECK_MEM_ERROR(cm, row_mt_sync->cond_,
|
||||
aom_malloc(sizeof(*row_mt_sync->cond_) * rows));
|
||||
if (row_mt_sync->cond_) {
|
||||
for (i = 0; i < rows; ++i) {
|
||||
pthread_cond_init(&row_mt_sync->cond_[i], NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // CONFIG_MULTITHREAD
|
||||
|
||||
CHECK_MEM_ERROR(cm, row_mt_sync->cur_col,
|
||||
aom_malloc(sizeof(*row_mt_sync->cur_col) * rows));
|
||||
|
||||
// Set up nsync.
|
||||
row_mt_sync->sync_range = 1;
|
||||
}
|
||||
|
||||
// Deallocate row based multi-threading synchronization related mutex and data
|
||||
void av1_row_mt_sync_mem_dealloc(AV1RowMTSync *row_mt_sync) {
|
||||
if (row_mt_sync != NULL) {
|
||||
#if CONFIG_MULTITHREAD
|
||||
int i;
|
||||
|
||||
if (row_mt_sync->mutex_ != NULL) {
|
||||
for (i = 0; i < row_mt_sync->rows; ++i) {
|
||||
pthread_mutex_destroy(&row_mt_sync->mutex_[i]);
|
||||
}
|
||||
aom_free(row_mt_sync->mutex_);
|
||||
}
|
||||
if (row_mt_sync->cond_ != NULL) {
|
||||
for (i = 0; i < row_mt_sync->rows; ++i) {
|
||||
pthread_cond_destroy(&row_mt_sync->cond_[i]);
|
||||
}
|
||||
aom_free(row_mt_sync->cond_);
|
||||
}
|
||||
#endif // CONFIG_MULTITHREAD
|
||||
aom_free(row_mt_sync->cur_col);
|
||||
// clear the structure as the source of this call may be dynamic change
|
||||
// in tiles in which case this call will be followed by an _alloc()
|
||||
// which may fail.
|
||||
av1_zero(*row_mt_sync);
|
||||
}
|
||||
}
|
||||
|
||||
static void assign_tile_to_thread(MultiThreadHandle *multi_thread_ctxt,
|
||||
int num_tiles, int num_workers) {
|
||||
int tile_id = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_workers; i++) {
|
||||
multi_thread_ctxt->thread_id_to_tile_id[i] = tile_id++;
|
||||
if (tile_id == num_tiles) tile_id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int get_next_job(AV1_COMP *const cpi, int *current_mi_row,
|
||||
int cur_tile_id) {
|
||||
AV1_COMMON *const cm = &cpi->common;
|
||||
TileDataEnc *const this_tile = &cpi->tile_data[cur_tile_id];
|
||||
AV1RowMTInfo *row_mt_info = &this_tile->row_mt_info;
|
||||
|
||||
if (row_mt_info->current_mi_row < this_tile->tile_info.mi_row_end) {
|
||||
*current_mi_row = row_mt_info->current_mi_row;
|
||||
row_mt_info->num_threads_working++;
|
||||
row_mt_info->current_mi_row += cm->seq_params.mib_size;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void switch_tile_and_get_next_job(AV1_COMP *const cpi, int *cur_tile_id,
|
||||
int *current_mi_row,
|
||||
int *end_of_frame) {
|
||||
AV1_COMMON *const cm = &cpi->common;
|
||||
const int tile_cols = cm->tile_cols;
|
||||
const int tile_rows = cm->tile_rows;
|
||||
|
||||
int tile_id = -1; // Stores the tile ID with minimum proc done
|
||||
int max_mis_to_encode = 0;
|
||||
int min_num_threads_working = INT_MAX;
|
||||
|
||||
for (int tile_row = 0; tile_row < tile_rows; tile_row++) {
|
||||
for (int tile_col = 0; tile_col < tile_cols; tile_col++) {
|
||||
int tile_index = tile_row * tile_cols + tile_col;
|
||||
TileDataEnc *this_tile = &cpi->tile_data[tile_index];
|
||||
AV1RowMTInfo *row_mt_info = &this_tile->row_mt_info;
|
||||
int num_mis_to_encode =
|
||||
this_tile->tile_info.mi_row_end - row_mt_info->current_mi_row;
|
||||
|
||||
// Tile to be processed by this thread is selected on the basis of
|
||||
// availability of jobs:
|
||||
// 1) If jobs are available, tile to be processed is chosen on the
|
||||
// basis of minimum number of threads working for that tile. If two or
|
||||
// more tiles have same number of threads working for them, then the tile
|
||||
// with maximum number of jobs available will be chosen.
|
||||
// 2) If no jobs are available, then end_of_frame is reached.
|
||||
if (num_mis_to_encode > 0) {
|
||||
int num_threads_working = row_mt_info->num_threads_working;
|
||||
if (num_threads_working < min_num_threads_working) {
|
||||
min_num_threads_working = num_threads_working;
|
||||
max_mis_to_encode = 0;
|
||||
}
|
||||
if (num_threads_working == min_num_threads_working &&
|
||||
num_mis_to_encode > max_mis_to_encode) {
|
||||
tile_id = tile_index;
|
||||
max_mis_to_encode = num_mis_to_encode;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tile_id == -1) {
|
||||
*end_of_frame = 1;
|
||||
} else {
|
||||
// Update the cur ID to the next tile ID that will be processed,
|
||||
// which will be the least processed tile
|
||||
*cur_tile_id = tile_id;
|
||||
get_next_job(cpi, current_mi_row, *cur_tile_id);
|
||||
}
|
||||
}
|
||||
|
||||
static int enc_row_mt_worker_hook(void *arg1, void *unused) {
|
||||
EncWorkerData *const thread_data = (EncWorkerData *)arg1;
|
||||
AV1_COMP *const cpi = thread_data->cpi;
|
||||
AV1_COMMON *const cm = &cpi->common;
|
||||
|
||||
MultiThreadHandle *multi_thread_ctxt = &cpi->multi_thread_ctxt;
|
||||
int thread_id = thread_data->thread_id;
|
||||
int cur_tile_id = multi_thread_ctxt->thread_id_to_tile_id[thread_id];
|
||||
(void)unused;
|
||||
|
||||
assert(cur_tile_id != -1);
|
||||
|
||||
int end_of_frame = 0;
|
||||
while (1) {
|
||||
int current_mi_row = -1;
|
||||
#if CONFIG_MULTITHREAD
|
||||
pthread_mutex_lock(cpi->row_mt_mutex_);
|
||||
#endif
|
||||
if (!get_next_job(cpi, ¤t_mi_row, cur_tile_id)) {
|
||||
// No jobs are available for the current tile. Query for the status of
|
||||
// other tiles and get the next job if available
|
||||
switch_tile_and_get_next_job(cpi, &cur_tile_id, ¤t_mi_row,
|
||||
&end_of_frame);
|
||||
}
|
||||
#if CONFIG_MULTITHREAD
|
||||
pthread_mutex_unlock(cpi->row_mt_mutex_);
|
||||
#endif
|
||||
if (end_of_frame == 1) break;
|
||||
|
||||
TileDataEnc *const this_tile = &cpi->tile_data[cur_tile_id];
|
||||
int tile_row = this_tile->tile_info.tile_row;
|
||||
int tile_col = this_tile->tile_info.tile_col;
|
||||
|
||||
assert(current_mi_row != -1 &&
|
||||
current_mi_row <= this_tile->tile_info.mi_row_end);
|
||||
|
||||
ThreadData *td = thread_data->td;
|
||||
|
||||
td->mb.e_mbd.tile_ctx = td->tctx;
|
||||
td->mb.tile_pb_ctx = &this_tile->tctx;
|
||||
if (this_tile->allow_update_cdf) {
|
||||
td->mb.row_ctx = this_tile->row_ctx;
|
||||
if (current_mi_row == this_tile->tile_info.mi_row_start)
|
||||
memcpy(td->mb.e_mbd.tile_ctx, &this_tile->tctx, sizeof(FRAME_CONTEXT));
|
||||
} else {
|
||||
memcpy(td->mb.e_mbd.tile_ctx, &this_tile->tctx, sizeof(FRAME_CONTEXT));
|
||||
}
|
||||
|
||||
av1_init_above_context(cm, &td->mb.e_mbd, tile_row);
|
||||
|
||||
// Disable exhaustive search speed features for row based multi-threading of
|
||||
// encoder.
|
||||
td->mb.m_search_count_ptr = NULL;
|
||||
td->mb.ex_search_count_ptr = NULL;
|
||||
|
||||
cfl_init(&td->mb.e_mbd.cfl, &cm->seq_params);
|
||||
av1_crc32c_calculator_init(&td->mb.mb_rd_record.crc_calculator);
|
||||
|
||||
av1_encode_sb_row(cpi, td, tile_row, tile_col, current_mi_row);
|
||||
#if CONFIG_MULTITHREAD
|
||||
pthread_mutex_lock(cpi->row_mt_mutex_);
|
||||
#endif
|
||||
this_tile->row_mt_info.num_threads_working--;
|
||||
#if CONFIG_MULTITHREAD
|
||||
pthread_mutex_unlock(cpi->row_mt_mutex_);
|
||||
#endif
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int enc_worker_hook(void *arg1, void *unused) {
|
||||
EncWorkerData *const thread_data = (EncWorkerData *)arg1;
|
||||
AV1_COMP *const cpi = thread_data->cpi;
|
||||
|
|
@ -42,6 +356,10 @@ static int enc_worker_hook(void *arg1, void *unused) {
|
|||
int tile_row = t / tile_cols;
|
||||
int tile_col = t % tile_cols;
|
||||
|
||||
TileDataEnc *const this_tile =
|
||||
&cpi->tile_data[tile_row * cm->tile_cols + tile_col];
|
||||
thread_data->td->mb.e_mbd.tile_ctx = &this_tile->tctx;
|
||||
thread_data->td->mb.tile_pb_ctx = &this_tile->tctx;
|
||||
av1_encode_tile(cpi, thread_data->td, tile_row, tile_col);
|
||||
}
|
||||
|
||||
|
|
@ -58,16 +376,28 @@ static void create_enc_workers(AV1_COMP *cpi, int num_workers) {
|
|||
CHECK_MEM_ERROR(cm, cpi->tile_thr_data,
|
||||
aom_calloc(num_workers, sizeof(*cpi->tile_thr_data)));
|
||||
|
||||
for (int i = 0; i < num_workers; i++) {
|
||||
#if CONFIG_MULTITHREAD
|
||||
if (cpi->row_mt == 1) {
|
||||
if (cpi->row_mt_mutex_ == NULL) {
|
||||
CHECK_MEM_ERROR(cm, cpi->row_mt_mutex_,
|
||||
aom_malloc(sizeof(*(cpi->row_mt_mutex_))));
|
||||
if (cpi->row_mt_mutex_) pthread_mutex_init(cpi->row_mt_mutex_, NULL);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
for (int i = num_workers - 1; i >= 0; i--) {
|
||||
AVxWorker *const worker = &cpi->workers[i];
|
||||
EncWorkerData *const thread_data = &cpi->tile_thr_data[i];
|
||||
|
||||
++cpi->num_workers;
|
||||
winterface->init(worker);
|
||||
worker->thread_name = "aom enc worker";
|
||||
|
||||
thread_data->cpi = cpi;
|
||||
thread_data->thread_id = i;
|
||||
|
||||
if (i < num_workers - 1) {
|
||||
if (i > 0) {
|
||||
// Allocate thread data.
|
||||
CHECK_MEM_ERROR(cm, thread_data->td,
|
||||
aom_memalign(32, sizeof(*thread_data->td)));
|
||||
|
|
@ -91,6 +421,10 @@ static void create_enc_workers(AV1_COMP *cpi, int num_workers) {
|
|||
(int32_t *)aom_memalign(
|
||||
16, MAX_SB_SQUARE * sizeof(*thread_data->td->wsrc_buf)));
|
||||
|
||||
CHECK_MEM_ERROR(cm, thread_data->td->inter_modes_info,
|
||||
(InterModesInfo *)aom_malloc(
|
||||
sizeof(*thread_data->td->inter_modes_info)));
|
||||
|
||||
for (int x = 0; x < 2; x++)
|
||||
for (int y = 0; y < 2; y++)
|
||||
CHECK_MEM_ERROR(
|
||||
|
|
@ -119,7 +453,7 @@ static void create_enc_workers(AV1_COMP *cpi, int num_workers) {
|
|||
for (int j = 0; j < 2; ++j) {
|
||||
CHECK_MEM_ERROR(
|
||||
cm, thread_data->td->tmp_obmc_bufs[j],
|
||||
aom_memalign(16, 2 * MAX_MB_PLANE * MAX_SB_SQUARE *
|
||||
aom_memalign(32, 2 * MAX_MB_PLANE * MAX_SB_SQUARE *
|
||||
sizeof(*thread_data->td->tmp_obmc_bufs[j])));
|
||||
}
|
||||
|
||||
|
|
@ -131,6 +465,10 @@ static void create_enc_workers(AV1_COMP *cpi, int num_workers) {
|
|||
// Main thread acts as a worker and uses the thread data in cpi.
|
||||
thread_data->td = &cpi->td;
|
||||
}
|
||||
if (cpi->row_mt == 1)
|
||||
CHECK_MEM_ERROR(
|
||||
cm, thread_data->td->tctx,
|
||||
(FRAME_CONTEXT *)aom_memalign(16, sizeof(*thread_data->td->tctx)));
|
||||
winterface->sync(worker);
|
||||
}
|
||||
}
|
||||
|
|
@ -138,14 +476,14 @@ static void create_enc_workers(AV1_COMP *cpi, int num_workers) {
|
|||
static void launch_enc_workers(AV1_COMP *cpi, int num_workers) {
|
||||
const AVxWorkerInterface *const winterface = aom_get_worker_interface();
|
||||
// Encode a frame
|
||||
for (int i = 0; i < num_workers; i++) {
|
||||
for (int i = num_workers - 1; i >= 0; i--) {
|
||||
AVxWorker *const worker = &cpi->workers[i];
|
||||
EncWorkerData *const thread_data = (EncWorkerData *)worker->data1;
|
||||
|
||||
// Set the starting tile for each thread.
|
||||
thread_data->start = i;
|
||||
|
||||
if (i == cpi->num_workers - 1)
|
||||
if (i == 0)
|
||||
winterface->execute(worker);
|
||||
else
|
||||
winterface->launch(worker);
|
||||
|
|
@ -154,31 +492,39 @@ static void launch_enc_workers(AV1_COMP *cpi, int num_workers) {
|
|||
|
||||
static void sync_enc_workers(AV1_COMP *cpi, int num_workers) {
|
||||
const AVxWorkerInterface *const winterface = aom_get_worker_interface();
|
||||
int had_error = 0;
|
||||
|
||||
// Encoding ends.
|
||||
for (int i = 0; i < num_workers; i++) {
|
||||
for (int i = num_workers - 1; i >= 0; i--) {
|
||||
AVxWorker *const worker = &cpi->workers[i];
|
||||
winterface->sync(worker);
|
||||
had_error |= !winterface->sync(worker);
|
||||
}
|
||||
|
||||
if (had_error)
|
||||
aom_internal_error(&cpi->common.error, AOM_CODEC_ERROR,
|
||||
"Failed to encode tile data");
|
||||
}
|
||||
|
||||
static void accumulate_counters_enc_workers(AV1_COMP *cpi, int num_workers) {
|
||||
for (int i = 0; i < num_workers; i++) {
|
||||
for (int i = num_workers - 1; i >= 0; i--) {
|
||||
AVxWorker *const worker = &cpi->workers[i];
|
||||
EncWorkerData *const thread_data = (EncWorkerData *)worker->data1;
|
||||
cpi->intrabc_used |= thread_data->td->intrabc_used_this_tile;
|
||||
cpi->intrabc_used |= thread_data->td->intrabc_used;
|
||||
// Accumulate counters.
|
||||
if (i < cpi->num_workers - 1) {
|
||||
if (i > 0) {
|
||||
av1_accumulate_frame_counts(&cpi->counts, thread_data->td->counts);
|
||||
accumulate_rd_opt(&cpi->td, thread_data->td);
|
||||
cpi->td.mb.txb_split_count += thread_data->td->mb.txb_split_count;
|
||||
#if CONFIG_SPEED_STATS
|
||||
cpi->td.mb.tx_search_count += thread_data->td->mb.tx_search_count;
|
||||
#endif // CONFIG_SPEED_STATS
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void prepare_enc_workers(AV1_COMP *cpi, AVxWorkerHook hook,
|
||||
int num_workers) {
|
||||
for (int i = 0; i < num_workers; i++) {
|
||||
for (int i = num_workers - 1; i >= 0; i--) {
|
||||
AVxWorker *const worker = &cpi->workers[i];
|
||||
EncWorkerData *const thread_data = &cpi->tile_thr_data[i];
|
||||
|
||||
|
|
@ -186,6 +532,8 @@ static void prepare_enc_workers(AV1_COMP *cpi, AVxWorkerHook hook,
|
|||
worker->data1 = thread_data;
|
||||
worker->data2 = NULL;
|
||||
|
||||
thread_data->td->intrabc_used = 0;
|
||||
|
||||
// Before encoding a frame, copy the thread data from cpi.
|
||||
if (thread_data->td != &cpi->td) {
|
||||
thread_data->td->mb = cpi->td.mb;
|
||||
|
|
@ -193,6 +541,8 @@ static void prepare_enc_workers(AV1_COMP *cpi, AVxWorkerHook hook,
|
|||
thread_data->td->mb.above_pred_buf = thread_data->td->above_pred_buf;
|
||||
thread_data->td->mb.left_pred_buf = thread_data->td->left_pred_buf;
|
||||
thread_data->td->mb.wsrc_buf = thread_data->td->wsrc_buf;
|
||||
|
||||
thread_data->td->mb.inter_modes_info = thread_data->td->inter_modes_info;
|
||||
for (int x = 0; x < 2; x++) {
|
||||
for (int y = 0; y < 2; y++) {
|
||||
memcpy(thread_data->td->hash_value_buffer[x][y],
|
||||
|
|
@ -209,7 +559,7 @@ static void prepare_enc_workers(AV1_COMP *cpi, AVxWorkerHook hook,
|
|||
memcpy(thread_data->td->counts, &cpi->counts, sizeof(cpi->counts));
|
||||
}
|
||||
|
||||
if (i < num_workers - 1) {
|
||||
if (i > 0) {
|
||||
thread_data->td->mb.palette_buffer = thread_data->td->palette_buffer;
|
||||
thread_data->td->mb.tmp_conv_dst = thread_data->td->tmp_conv_dst;
|
||||
for (int j = 0; j < 2; ++j) {
|
||||
|
|
@ -259,3 +609,74 @@ void av1_accumulate_frame_counts(FRAME_COUNTS *acc_counts,
|
|||
|
||||
for (unsigned int i = 0; i < n_counts; i++) acc[i] += cnt[i];
|
||||
}
|
||||
|
||||
void av1_encode_tiles_row_mt(AV1_COMP *cpi) {
|
||||
AV1_COMMON *const cm = &cpi->common;
|
||||
const int tile_cols = cm->tile_cols;
|
||||
const int tile_rows = cm->tile_rows;
|
||||
MultiThreadHandle *multi_thread_ctxt = &cpi->multi_thread_ctxt;
|
||||
int num_workers = 0;
|
||||
int total_num_sb_rows = 0;
|
||||
int max_sb_rows = 0;
|
||||
|
||||
if (cpi->tile_data == NULL || cpi->allocated_tiles < tile_cols * tile_rows) {
|
||||
av1_row_mt_mem_dealloc(cpi);
|
||||
av1_alloc_tile_data(cpi);
|
||||
}
|
||||
|
||||
av1_init_tile_data(cpi);
|
||||
|
||||
for (int row = 0; row < tile_rows; row++) {
|
||||
for (int col = 0; col < tile_cols; col++) {
|
||||
TileDataEnc *tile_data = &cpi->tile_data[row * cm->tile_cols + col];
|
||||
int num_sb_rows_in_tile =
|
||||
av1_get_sb_rows_in_tile(cm, tile_data->tile_info);
|
||||
total_num_sb_rows += num_sb_rows_in_tile;
|
||||
max_sb_rows = AOMMAX(max_sb_rows, num_sb_rows_in_tile);
|
||||
}
|
||||
}
|
||||
num_workers = AOMMIN(cpi->oxcf.max_threads, total_num_sb_rows);
|
||||
|
||||
if (multi_thread_ctxt->allocated_tile_cols != tile_cols ||
|
||||
multi_thread_ctxt->allocated_tile_rows != tile_rows ||
|
||||
multi_thread_ctxt->allocated_sb_rows != max_sb_rows) {
|
||||
av1_row_mt_mem_dealloc(cpi);
|
||||
av1_row_mt_mem_alloc(cpi, max_sb_rows);
|
||||
}
|
||||
|
||||
memset(multi_thread_ctxt->thread_id_to_tile_id, -1,
|
||||
sizeof(*multi_thread_ctxt->thread_id_to_tile_id) * MAX_NUM_THREADS);
|
||||
|
||||
for (int tile_row = 0; tile_row < tile_rows; tile_row++) {
|
||||
for (int tile_col = 0; tile_col < tile_cols; tile_col++) {
|
||||
int tile_id = tile_row * tile_cols + tile_col;
|
||||
TileDataEnc *this_tile = &cpi->tile_data[tile_id];
|
||||
|
||||
// Initialize cur_col to -1 for all rows.
|
||||
memset(this_tile->row_mt_sync.cur_col, -1,
|
||||
sizeof(*this_tile->row_mt_sync.cur_col) * max_sb_rows);
|
||||
this_tile->row_mt_info.current_mi_row = this_tile->tile_info.mi_row_start;
|
||||
this_tile->row_mt_info.num_threads_working = 0;
|
||||
|
||||
av1_inter_mode_data_init(this_tile);
|
||||
av1_zero_above_context(cm, &cpi->td.mb.e_mbd,
|
||||
this_tile->tile_info.mi_col_start,
|
||||
this_tile->tile_info.mi_col_end, tile_row);
|
||||
this_tile->m_search_count = 0; // Count of motion search hits.
|
||||
this_tile->ex_search_count = 0; // Exhaustive mesh search hits.
|
||||
}
|
||||
}
|
||||
|
||||
// Only run once to create threads and allocate thread data.
|
||||
if (cpi->num_workers == 0) {
|
||||
create_enc_workers(cpi, num_workers);
|
||||
} else {
|
||||
num_workers = AOMMIN(num_workers, cpi->num_workers);
|
||||
}
|
||||
assign_tile_to_thread(multi_thread_ctxt, tile_cols * tile_rows, num_workers);
|
||||
prepare_enc_workers(cpi, enc_row_mt_worker_hook, num_workers);
|
||||
launch_enc_workers(cpi, num_workers);
|
||||
sync_enc_workers(cpi, num_workers);
|
||||
if (cm->delta_q_info.delta_lf_present_flag) update_delta_lf_for_row_mt(cpi);
|
||||
accumulate_counters_enc_workers(cpi, num_workers);
|
||||
}
|
||||
|
|
|
|||
17
third_party/aom/av1/encoder/ethread.h
vendored
17
third_party/aom/av1/encoder/ethread.h
vendored
|
|
@ -18,14 +18,31 @@ extern "C" {
|
|||
|
||||
struct AV1_COMP;
|
||||
struct ThreadData;
|
||||
struct AV1RowMTSyncData;
|
||||
|
||||
typedef struct EncWorkerData {
|
||||
struct AV1_COMP *cpi;
|
||||
struct ThreadData *td;
|
||||
int start;
|
||||
int thread_id;
|
||||
} EncWorkerData;
|
||||
|
||||
void av1_row_mt_sync_read(AV1RowMTSync *const row_mt_sync, int r, int c);
|
||||
void av1_row_mt_sync_write(AV1RowMTSync *const row_mt_sync, int r, int c,
|
||||
const int cols);
|
||||
|
||||
void av1_row_mt_sync_read_dummy(struct AV1RowMTSyncData *const row_mt_sync,
|
||||
int r, int c);
|
||||
void av1_row_mt_sync_write_dummy(struct AV1RowMTSyncData *const row_mt_sync,
|
||||
int r, int c, const int cols);
|
||||
|
||||
void av1_row_mt_sync_mem_dealloc(AV1RowMTSync *row_mt_sync);
|
||||
// Allocate memory for row based multi-threading synchronization.
|
||||
void av1_row_mt_sync_mem_alloc(AV1RowMTSync *row_mt_sync, struct AV1Common *cm,
|
||||
int rows);
|
||||
|
||||
void av1_encode_tiles_mt(struct AV1_COMP *cpi);
|
||||
void av1_encode_tiles_row_mt(struct AV1_COMP *cpi);
|
||||
|
||||
void av1_accumulate_frame_counts(struct FRAME_COUNTS *acc_counts,
|
||||
const struct FRAME_COUNTS *counts);
|
||||
|
|
|
|||
796
third_party/aom/av1/encoder/firstpass.c
vendored
796
third_party/aom/av1/encoder/firstpass.c
vendored
File diff suppressed because it is too large
Load diff
67
third_party/aom/av1/encoder/firstpass.h
vendored
67
third_party/aom/av1/encoder/firstpass.h
vendored
|
|
@ -86,7 +86,7 @@ typedef struct {
|
|||
double raw_error_stdev;
|
||||
} FIRSTPASS_STATS;
|
||||
|
||||
typedef enum {
|
||||
enum {
|
||||
KF_UPDATE = 0,
|
||||
LF_UPDATE = 1,
|
||||
GF_UPDATE = 2,
|
||||
|
|
@ -98,34 +98,29 @@ typedef enum {
|
|||
INTNL_OVERLAY_UPDATE = 8, // Internal Overlay Frame
|
||||
INTNL_ARF_UPDATE = 9, // Internal Altref Frame (candidate for ALTREF2)
|
||||
FRAME_UPDATE_TYPES = 10
|
||||
} FRAME_UPDATE_TYPE;
|
||||
} UENUM1BYTE(FRAME_UPDATE_TYPE);
|
||||
|
||||
#define FC_ANIMATION_THRESH 0.15
|
||||
typedef enum {
|
||||
enum {
|
||||
FC_NORMAL = 0,
|
||||
FC_GRAPHICS_ANIMATION = 1,
|
||||
FRAME_CONTENT_TYPES = 2
|
||||
} FRAME_CONTENT_TYPE;
|
||||
} UENUM1BYTE(FRAME_CONTENT_TYPE);
|
||||
|
||||
typedef struct {
|
||||
unsigned char index;
|
||||
RATE_FACTOR_LEVEL rf_level[(MAX_LAG_BUFFERS * 2) + 1];
|
||||
FRAME_UPDATE_TYPE update_type[(MAX_LAG_BUFFERS * 2) + 1];
|
||||
unsigned char arf_src_offset[(MAX_LAG_BUFFERS * 2) + 1];
|
||||
unsigned char arf_update_idx[(MAX_LAG_BUFFERS * 2) + 1];
|
||||
unsigned char arf_ref_idx[(MAX_LAG_BUFFERS * 2) + 1];
|
||||
#if USE_SYMM_MULTI_LAYER
|
||||
unsigned char arf_pos_in_gf[(MAX_LAG_BUFFERS * 2) + 1];
|
||||
unsigned char pyramid_level[(MAX_LAG_BUFFERS * 2) + 1];
|
||||
RATE_FACTOR_LEVEL rf_level[MAX_STATIC_GF_GROUP_LENGTH + 1];
|
||||
FRAME_UPDATE_TYPE update_type[MAX_STATIC_GF_GROUP_LENGTH + 1];
|
||||
unsigned char arf_src_offset[MAX_STATIC_GF_GROUP_LENGTH + 1];
|
||||
unsigned char arf_update_idx[MAX_STATIC_GF_GROUP_LENGTH + 1];
|
||||
unsigned char arf_ref_idx[MAX_STATIC_GF_GROUP_LENGTH + 1];
|
||||
unsigned char arf_pos_in_gf[MAX_STATIC_GF_GROUP_LENGTH + 1];
|
||||
unsigned char pyramid_level[MAX_STATIC_GF_GROUP_LENGTH + 1];
|
||||
unsigned char pyramid_height;
|
||||
unsigned char pyramid_lvl_nodes[MAX_PYRAMID_LVL];
|
||||
#endif
|
||||
unsigned char brf_src_offset[(MAX_LAG_BUFFERS * 2) + 1];
|
||||
unsigned char bidir_pred_enabled[(MAX_LAG_BUFFERS * 2) + 1];
|
||||
unsigned char ref_fb_idx_map[(MAX_LAG_BUFFERS * 2) + 1][REF_FRAMES];
|
||||
unsigned char refresh_idx[(MAX_LAG_BUFFERS * 2) + 1];
|
||||
unsigned char refresh_flag[(MAX_LAG_BUFFERS * 2) + 1];
|
||||
int bit_allocation[(MAX_LAG_BUFFERS * 2) + 1];
|
||||
unsigned char brf_src_offset[MAX_STATIC_GF_GROUP_LENGTH + 1];
|
||||
unsigned char bidir_pred_enabled[MAX_STATIC_GF_GROUP_LENGTH + 1];
|
||||
int bit_allocation[MAX_STATIC_GF_GROUP_LENGTH + 1];
|
||||
} GF_GROUP;
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -176,29 +171,37 @@ typedef struct {
|
|||
} TWO_PASS;
|
||||
|
||||
struct AV1_COMP;
|
||||
struct EncodeFrameParams;
|
||||
|
||||
void av1_init_first_pass(struct AV1_COMP *cpi);
|
||||
void av1_rc_get_first_pass_params(struct AV1_COMP *cpi);
|
||||
void av1_first_pass(struct AV1_COMP *cpi, const struct lookahead_entry *source);
|
||||
void av1_first_pass(struct AV1_COMP *cpi, const int64_t ts_duration);
|
||||
void av1_end_first_pass(struct AV1_COMP *cpi);
|
||||
|
||||
void av1_init_second_pass(struct AV1_COMP *cpi);
|
||||
void av1_rc_get_second_pass_params(struct AV1_COMP *cpi);
|
||||
void av1_configure_buffer_updates_firstpass(struct AV1_COMP *cpi,
|
||||
FRAME_UPDATE_TYPE update_type);
|
||||
void av1_rc_get_second_pass_params(
|
||||
struct AV1_COMP *cpi, struct EncodeFrameParams *const frame_params);
|
||||
|
||||
// Post encode update of the rate control parameters for 2-pass
|
||||
void av1_twopass_postencode_update(struct AV1_COMP *cpi);
|
||||
|
||||
static INLINE int get_number_of_extra_arfs(int interval, int arf_pending) {
|
||||
if (arf_pending && MAX_EXT_ARFS > 0)
|
||||
return interval >= MIN_EXT_ARF_INTERVAL * (MAX_EXT_ARFS + 1)
|
||||
? MAX_EXT_ARFS
|
||||
: interval >= MIN_EXT_ARF_INTERVAL * MAX_EXT_ARFS
|
||||
? MAX_EXT_ARFS - 1
|
||||
: 0;
|
||||
else
|
||||
return 0;
|
||||
static INLINE int get_number_of_extra_arfs(int interval, int arf_pending,
|
||||
int max_pyr_height) {
|
||||
// Max extra (internal) alt-refs allowed based on interval.
|
||||
int extra_arfs_from_interval = 0;
|
||||
if (arf_pending && MAX_EXT_ARFS > 0) {
|
||||
extra_arfs_from_interval =
|
||||
(interval >= MIN_EXT_ARF_INTERVAL * (MAX_EXT_ARFS + 1))
|
||||
? MAX_EXT_ARFS
|
||||
: (interval >= MIN_EXT_ARF_INTERVAL * MAX_EXT_ARFS)
|
||||
? MAX_EXT_ARFS - 1
|
||||
: 0;
|
||||
}
|
||||
// Max extra (internal) alt-refs allowed based on max pyramid height.
|
||||
assert(max_pyr_height >= 1);
|
||||
const int ext_arfs_from_max_height = max_pyr_height - 1;
|
||||
// Finally, min of the two above is our actual max allowance.
|
||||
return AOMMIN(extra_arfs_from_interval, ext_arfs_from_max_height);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
|||
623
third_party/aom/av1/encoder/global_motion.c
vendored
623
third_party/aom/av1/encoder/global_motion.c
vendored
|
|
@ -15,8 +15,12 @@
|
|||
#include <math.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "config/aom_dsp_rtcd.h"
|
||||
|
||||
#include "av1/encoder/global_motion.h"
|
||||
|
||||
#include "av1/common/convolve.h"
|
||||
#include "av1/common/resize.h"
|
||||
#include "av1/common/warped_motion.h"
|
||||
|
||||
#include "av1/encoder/segmentation.h"
|
||||
|
|
@ -28,15 +32,45 @@
|
|||
#define MIN_INLIER_PROB 0.1
|
||||
|
||||
#define MIN_TRANS_THRESH (1 * GM_TRANS_DECODE_FACTOR)
|
||||
#define USE_GM_FEATURE_BASED 1
|
||||
|
||||
// Border over which to compute the global motion
|
||||
#define ERRORADV_BORDER 0
|
||||
|
||||
// Number of pyramid levels in disflow computation
|
||||
#define N_LEVELS 2
|
||||
// Size of square patches in the disflow dense grid
|
||||
#define PATCH_SIZE 8
|
||||
// Center point of square patch
|
||||
#define PATCH_CENTER ((PATCH_SIZE + 1) >> 1)
|
||||
// Step size between patches, lower value means greater patch overlap
|
||||
#define PATCH_STEP 1
|
||||
// Minimum size of border padding for disflow
|
||||
#define MIN_PAD 7
|
||||
// Warp error convergence threshold for disflow
|
||||
#define DISFLOW_ERROR_TR 0.01
|
||||
// Max number of iterations if warp convergence is not found
|
||||
#define DISFLOW_MAX_ITR 10
|
||||
|
||||
// Struct for an image pyramid
|
||||
typedef struct {
|
||||
int n_levels;
|
||||
int pad_size;
|
||||
int has_gradient;
|
||||
int widths[N_LEVELS];
|
||||
int heights[N_LEVELS];
|
||||
int strides[N_LEVELS];
|
||||
int level_loc[N_LEVELS];
|
||||
unsigned char *level_buffer;
|
||||
double *level_dx_buffer;
|
||||
double *level_dy_buffer;
|
||||
} ImagePyramid;
|
||||
|
||||
static const double erroradv_tr[] = { 0.65, 0.60, 0.55 };
|
||||
static const double erroradv_prod_tr[] = { 20000, 18000, 16000 };
|
||||
|
||||
int is_enough_erroradvantage(double best_erroradvantage, int params_cost,
|
||||
int erroradv_type) {
|
||||
int av1_is_enough_erroradvantage(double best_erroradvantage, int params_cost,
|
||||
int erroradv_type) {
|
||||
assert(erroradv_type < GM_ERRORADV_TR_TYPES);
|
||||
return best_erroradvantage < erroradv_tr[erroradv_type] &&
|
||||
best_erroradvantage * params_cost < erroradv_prod_tr[erroradv_type];
|
||||
|
|
@ -75,9 +109,10 @@ static void convert_to_params(const double *params, int32_t *model) {
|
|||
}
|
||||
}
|
||||
|
||||
void convert_model_to_params(const double *params, WarpedMotionParams *model) {
|
||||
void av1_convert_model_to_params(const double *params,
|
||||
WarpedMotionParams *model) {
|
||||
convert_to_params(params, model->wmmat);
|
||||
model->wmtype = get_gmtype(model);
|
||||
model->wmtype = get_wmtype(model);
|
||||
model->invalid = 0;
|
||||
}
|
||||
|
||||
|
|
@ -131,12 +166,13 @@ static void force_wmtype(WarpedMotionParams *wm, TransformationType wmtype) {
|
|||
wm->wmtype = wmtype;
|
||||
}
|
||||
|
||||
int64_t refine_integerized_param(WarpedMotionParams *wm,
|
||||
TransformationType wmtype, int use_hbd, int bd,
|
||||
uint8_t *ref, int r_width, int r_height,
|
||||
int r_stride, uint8_t *dst, int d_width,
|
||||
int d_height, int d_stride, int n_refinements,
|
||||
int64_t best_frame_error) {
|
||||
int64_t av1_refine_integerized_param(WarpedMotionParams *wm,
|
||||
TransformationType wmtype, int use_hbd,
|
||||
int bd, uint8_t *ref, int r_width,
|
||||
int r_height, int r_stride, uint8_t *dst,
|
||||
int d_width, int d_height, int d_stride,
|
||||
int n_refinements,
|
||||
int64_t best_frame_error) {
|
||||
static const int max_trans_model_params[TRANS_TYPES] = { 0, 2, 4, 6 };
|
||||
const int border = ERRORADV_BORDER;
|
||||
int i = 0, p;
|
||||
|
|
@ -209,7 +245,7 @@ int64_t refine_integerized_param(WarpedMotionParams *wm,
|
|||
}
|
||||
}
|
||||
force_wmtype(wm, wmtype);
|
||||
wm->wmtype = get_gmtype(wm);
|
||||
wm->wmtype = get_wmtype(wm);
|
||||
return best_error;
|
||||
}
|
||||
|
||||
|
|
@ -240,12 +276,11 @@ static unsigned char *downconvert_frame(YV12_BUFFER_CONFIG *frm,
|
|||
return buf_8bit;
|
||||
}
|
||||
|
||||
int compute_global_motion_feature_based(TransformationType type,
|
||||
YV12_BUFFER_CONFIG *frm,
|
||||
YV12_BUFFER_CONFIG *ref, int bit_depth,
|
||||
int *num_inliers_by_motion,
|
||||
double *params_by_motion,
|
||||
int num_motions) {
|
||||
#if USE_GM_FEATURE_BASED
|
||||
static int compute_global_motion_feature_based(
|
||||
TransformationType type, YV12_BUFFER_CONFIG *frm, YV12_BUFFER_CONFIG *ref,
|
||||
int bit_depth, int *num_inliers_by_motion, double *params_by_motion,
|
||||
int num_motions) {
|
||||
int i;
|
||||
int num_frm_corners, num_ref_corners;
|
||||
int num_correspondences;
|
||||
|
|
@ -296,3 +331,557 @@ int compute_global_motion_feature_based(TransformationType type,
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static INLINE RansacFuncDouble
|
||||
get_ransac_double_prec_type(TransformationType type) {
|
||||
switch (type) {
|
||||
case AFFINE: return ransac_affine_double_prec;
|
||||
case ROTZOOM: return ransac_rotzoom_double_prec;
|
||||
case TRANSLATION: return ransac_translation_double_prec;
|
||||
default: assert(0); return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Don't use points around the frame border since they are less reliable
|
||||
static INLINE int valid_point(int x, int y, int width, int height) {
|
||||
return (x > (PATCH_SIZE + PATCH_CENTER)) &&
|
||||
(x < (width - PATCH_SIZE - PATCH_CENTER)) &&
|
||||
(y > (PATCH_SIZE + PATCH_CENTER)) &&
|
||||
(y < (height - PATCH_SIZE - PATCH_CENTER));
|
||||
}
|
||||
|
||||
static int determine_disflow_correspondence(int *frm_corners,
|
||||
int num_frm_corners, double *flow_u,
|
||||
double *flow_v, int width,
|
||||
int height, int stride,
|
||||
double *correspondences) {
|
||||
int num_correspondences = 0;
|
||||
int x, y;
|
||||
for (int i = 0; i < num_frm_corners; ++i) {
|
||||
x = frm_corners[2 * i];
|
||||
y = frm_corners[2 * i + 1];
|
||||
if (valid_point(x, y, width, height)) {
|
||||
correspondences[4 * num_correspondences] = x;
|
||||
correspondences[4 * num_correspondences + 1] = y;
|
||||
correspondences[4 * num_correspondences + 2] = x + flow_u[y * stride + x];
|
||||
correspondences[4 * num_correspondences + 3] = y + flow_v[y * stride + x];
|
||||
num_correspondences++;
|
||||
}
|
||||
}
|
||||
return num_correspondences;
|
||||
}
|
||||
|
||||
double getCubicValue(double p[4], double x) {
|
||||
return p[1] + 0.5 * x *
|
||||
(p[2] - p[0] +
|
||||
x * (2.0 * p[0] - 5.0 * p[1] + 4.0 * p[2] - p[3] +
|
||||
x * (3.0 * (p[1] - p[2]) + p[3] - p[0])));
|
||||
}
|
||||
|
||||
void get_subcolumn(unsigned char *ref, double col[4], int stride, int x,
|
||||
int y_start) {
|
||||
int i;
|
||||
for (i = 0; i < 4; ++i) {
|
||||
col[i] = ref[(i + y_start) * stride + x];
|
||||
}
|
||||
}
|
||||
|
||||
double bicubic(unsigned char *ref, double x, double y, int stride) {
|
||||
double arr[4];
|
||||
int k;
|
||||
int i = (int)x;
|
||||
int j = (int)y;
|
||||
for (k = 0; k < 4; ++k) {
|
||||
double arr_temp[4];
|
||||
get_subcolumn(ref, arr_temp, stride, i + k - 1, j - 1);
|
||||
arr[k] = getCubicValue(arr_temp, y - j);
|
||||
}
|
||||
return getCubicValue(arr, x - i);
|
||||
}
|
||||
|
||||
// Interpolate a warped block using bicubic interpolation when possible
|
||||
unsigned char interpolate(unsigned char *ref, double x, double y, int width,
|
||||
int height, int stride) {
|
||||
if (x < 0 && y < 0)
|
||||
return ref[0];
|
||||
else if (x < 0 && y > height - 1)
|
||||
return ref[(height - 1) * stride];
|
||||
else if (x > width - 1 && y < 0)
|
||||
return ref[width - 1];
|
||||
else if (x > width - 1 && y > height - 1)
|
||||
return ref[(height - 1) * stride + (width - 1)];
|
||||
else if (x < 0) {
|
||||
int v;
|
||||
int i = (int)y;
|
||||
double a = y - i;
|
||||
if (y > 1 && y < height - 2) {
|
||||
double arr[4];
|
||||
get_subcolumn(ref, arr, stride, 0, i - 1);
|
||||
return clamp((int)(getCubicValue(arr, a) + 0.5), 0, 255);
|
||||
}
|
||||
v = (int)(ref[i * stride] * (1 - a) + ref[(i + 1) * stride] * a + 0.5);
|
||||
return clamp(v, 0, 255);
|
||||
} else if (y < 0) {
|
||||
int v;
|
||||
int j = (int)x;
|
||||
double b = x - j;
|
||||
if (x > 1 && x < width - 2) {
|
||||
double arr[4] = { ref[j - 1], ref[j], ref[j + 1], ref[j + 2] };
|
||||
return clamp((int)(getCubicValue(arr, b) + 0.5), 0, 255);
|
||||
}
|
||||
v = (int)(ref[j] * (1 - b) + ref[j + 1] * b + 0.5);
|
||||
return clamp(v, 0, 255);
|
||||
} else if (x > width - 1) {
|
||||
int v;
|
||||
int i = (int)y;
|
||||
double a = y - i;
|
||||
if (y > 1 && y < height - 2) {
|
||||
double arr[4];
|
||||
get_subcolumn(ref, arr, stride, width - 1, i - 1);
|
||||
return clamp((int)(getCubicValue(arr, a) + 0.5), 0, 255);
|
||||
}
|
||||
v = (int)(ref[i * stride + width - 1] * (1 - a) +
|
||||
ref[(i + 1) * stride + width - 1] * a + 0.5);
|
||||
return clamp(v, 0, 255);
|
||||
} else if (y > height - 1) {
|
||||
int v;
|
||||
int j = (int)x;
|
||||
double b = x - j;
|
||||
if (x > 1 && x < width - 2) {
|
||||
int row = (height - 1) * stride;
|
||||
double arr[4] = { ref[row + j - 1], ref[row + j], ref[row + j + 1],
|
||||
ref[row + j + 2] };
|
||||
return clamp((int)(getCubicValue(arr, b) + 0.5), 0, 255);
|
||||
}
|
||||
v = (int)(ref[(height - 1) * stride + j] * (1 - b) +
|
||||
ref[(height - 1) * stride + j + 1] * b + 0.5);
|
||||
return clamp(v, 0, 255);
|
||||
} else if (x > 1 && y > 1 && x < width - 2 && y < height - 2) {
|
||||
return clamp((int)(bicubic(ref, x, y, stride) + 0.5), 0, 255);
|
||||
} else {
|
||||
int i = (int)y;
|
||||
int j = (int)x;
|
||||
double a = y - i;
|
||||
double b = x - j;
|
||||
int v = (int)(ref[i * stride + j] * (1 - a) * (1 - b) +
|
||||
ref[i * stride + j + 1] * (1 - a) * b +
|
||||
ref[(i + 1) * stride + j] * a * (1 - b) +
|
||||
ref[(i + 1) * stride + j + 1] * a * b);
|
||||
return clamp(v, 0, 255);
|
||||
}
|
||||
}
|
||||
|
||||
// Warps a block using flow vector [u, v] and computes the mse
|
||||
double compute_warp_and_error(unsigned char *ref, unsigned char *frm, int width,
|
||||
int height, int stride, int x, int y, double u,
|
||||
double v, int16_t *dt) {
|
||||
int i, j;
|
||||
unsigned char warped;
|
||||
double x_w, y_w;
|
||||
double mse = 0;
|
||||
int16_t err = 0;
|
||||
for (i = y; i < y + PATCH_SIZE; ++i)
|
||||
for (j = x; j < x + PATCH_SIZE; ++j) {
|
||||
x_w = (double)j + u;
|
||||
y_w = (double)i + v;
|
||||
warped = interpolate(ref, x_w, y_w, width, height, stride);
|
||||
err = warped - frm[j + i * stride];
|
||||
mse += err * err;
|
||||
dt[(i - y) * PATCH_SIZE + (j - x)] = err;
|
||||
}
|
||||
|
||||
mse /= (PATCH_SIZE * PATCH_SIZE);
|
||||
return mse;
|
||||
}
|
||||
|
||||
// Computes the components of the system of equations used to solve for
|
||||
// a flow vector. This includes:
|
||||
// 1.) The hessian matrix for optical flow. This matrix is in the
|
||||
// form of:
|
||||
//
|
||||
// M = |sum(dx * dx) sum(dx * dy)|
|
||||
// |sum(dx * dy) sum(dy * dy)|
|
||||
//
|
||||
// 2.) b = |sum(dx * dt)|
|
||||
// |sum(dy * dt)|
|
||||
// Where the sums are computed over a square window of PATCH_SIZE.
|
||||
static INLINE void compute_flow_system(const double *dx, int dx_stride,
|
||||
const double *dy, int dy_stride,
|
||||
const int16_t *dt, int dt_stride,
|
||||
double *M, double *b) {
|
||||
for (int i = 0; i < PATCH_SIZE; i++) {
|
||||
for (int j = 0; j < PATCH_SIZE; j++) {
|
||||
M[0] += dx[i * dx_stride + j] * dx[i * dx_stride + j];
|
||||
M[1] += dx[i * dx_stride + j] * dy[i * dy_stride + j];
|
||||
M[3] += dy[i * dy_stride + j] * dy[i * dy_stride + j];
|
||||
|
||||
b[0] += dx[i * dx_stride + j] * dt[i * dt_stride + j];
|
||||
b[1] += dy[i * dy_stride + j] * dt[i * dt_stride + j];
|
||||
}
|
||||
}
|
||||
|
||||
M[2] = M[1];
|
||||
}
|
||||
|
||||
// Solves a general Mx = b where M is a 2x2 matrix and b is a 2x1 matrix
|
||||
static INLINE void solve_2x2_system(const double *M, const double *b,
|
||||
double *output_vec) {
|
||||
double M_0 = M[0];
|
||||
double M_3 = M[3];
|
||||
double det = (M_0 * M_3) - (M[1] * M[2]);
|
||||
if (det < 1e-5) {
|
||||
// Handle singular matrix
|
||||
// TODO(sarahparker) compare results using pseudo inverse instead
|
||||
M_0 += 1e-10;
|
||||
M_3 += 1e-10;
|
||||
det = (M_0 * M_3) - (M[1] * M[2]);
|
||||
}
|
||||
const double det_inv = 1 / det;
|
||||
const double mult_b0 = det_inv * b[0];
|
||||
const double mult_b1 = det_inv * b[1];
|
||||
output_vec[0] = M_3 * mult_b0 - M[1] * mult_b1;
|
||||
output_vec[1] = -M[2] * mult_b0 + M_0 * mult_b1;
|
||||
}
|
||||
|
||||
static INLINE void image_difference(const uint8_t *src, int src_stride,
|
||||
const uint8_t *ref, int ref_stride,
|
||||
int16_t *dst, int dst_stride, int height,
|
||||
int width) {
|
||||
const int block_unit = 8;
|
||||
// Take difference in 8x8 blocks to make use of optimized diff function
|
||||
for (int i = 0; i < height; i += block_unit) {
|
||||
for (int j = 0; j < width; j += block_unit) {
|
||||
aom_subtract_block(block_unit, block_unit, dst + i * dst_stride + j,
|
||||
dst_stride, src + i * src_stride + j, src_stride,
|
||||
ref + i * ref_stride + j, ref_stride);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Compute an image gradient using a sobel filter.
|
||||
// If dir == 1, compute the x gradient. If dir == 0, compute y. This function
|
||||
// assumes the images have been padded so that they can be processed in units
|
||||
// of 8.
|
||||
static INLINE void sobel_xy_image_gradient(const uint8_t *src, int src_stride,
|
||||
double *dst, int dst_stride,
|
||||
int height, int width, int dir) {
|
||||
double norm = 1.0;
|
||||
// TODO(sarahparker) experiment with doing this over larger block sizes
|
||||
const int block_unit = 8;
|
||||
// Filter in 8x8 blocks to eventually make use of optimized convolve function
|
||||
for (int i = 0; i < height; i += block_unit) {
|
||||
for (int j = 0; j < width; j += block_unit) {
|
||||
av1_convolve_2d_sobel_y_c(src + i * src_stride + j, src_stride,
|
||||
dst + i * dst_stride + j, dst_stride,
|
||||
block_unit, block_unit, dir, norm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static ImagePyramid *alloc_pyramid(int width, int height, int pad_size,
|
||||
int compute_gradient) {
|
||||
ImagePyramid *pyr = aom_malloc(sizeof(*pyr));
|
||||
pyr->has_gradient = compute_gradient;
|
||||
// 2 * width * height is the upper bound for a buffer that fits
|
||||
// all pyramid levels + padding for each level
|
||||
const int buffer_size = sizeof(*pyr->level_buffer) * 2 * width * height +
|
||||
(width + 2 * pad_size) * 2 * pad_size * N_LEVELS;
|
||||
pyr->level_buffer = aom_malloc(buffer_size);
|
||||
memset(pyr->level_buffer, 0, buffer_size);
|
||||
|
||||
if (compute_gradient) {
|
||||
const int gradient_size =
|
||||
sizeof(*pyr->level_dx_buffer) * 2 * width * height +
|
||||
(width + 2 * pad_size) * 2 * pad_size * N_LEVELS;
|
||||
pyr->level_dx_buffer = aom_malloc(gradient_size);
|
||||
pyr->level_dy_buffer = aom_malloc(gradient_size);
|
||||
memset(pyr->level_dx_buffer, 0, gradient_size);
|
||||
memset(pyr->level_dy_buffer, 0, gradient_size);
|
||||
}
|
||||
return pyr;
|
||||
}
|
||||
|
||||
static void free_pyramid(ImagePyramid *pyr) {
|
||||
aom_free(pyr->level_buffer);
|
||||
if (pyr->has_gradient) {
|
||||
aom_free(pyr->level_dx_buffer);
|
||||
aom_free(pyr->level_dy_buffer);
|
||||
}
|
||||
aom_free(pyr);
|
||||
}
|
||||
|
||||
static INLINE void update_level_dims(ImagePyramid *frm_pyr, int level) {
|
||||
frm_pyr->widths[level] = frm_pyr->widths[level - 1] >> 1;
|
||||
frm_pyr->heights[level] = frm_pyr->heights[level - 1] >> 1;
|
||||
frm_pyr->strides[level] = frm_pyr->widths[level] + 2 * frm_pyr->pad_size;
|
||||
// Point the beginning of the next level buffer to the correct location inside
|
||||
// the padded border
|
||||
frm_pyr->level_loc[level] =
|
||||
frm_pyr->level_loc[level - 1] +
|
||||
frm_pyr->strides[level - 1] *
|
||||
(2 * frm_pyr->pad_size + frm_pyr->heights[level - 1]);
|
||||
}
|
||||
|
||||
// Compute coarse to fine pyramids for a frame
|
||||
static void compute_flow_pyramids(unsigned char *frm, const int frm_width,
|
||||
const int frm_height, const int frm_stride,
|
||||
int n_levels, int pad_size, int compute_grad,
|
||||
ImagePyramid *frm_pyr) {
|
||||
int cur_width, cur_height, cur_stride, cur_loc;
|
||||
assert((frm_width >> n_levels) > 0);
|
||||
assert((frm_height >> n_levels) > 0);
|
||||
|
||||
// Initialize first level
|
||||
frm_pyr->n_levels = n_levels;
|
||||
frm_pyr->pad_size = pad_size;
|
||||
frm_pyr->widths[0] = frm_width;
|
||||
frm_pyr->heights[0] = frm_height;
|
||||
frm_pyr->strides[0] = frm_width + 2 * frm_pyr->pad_size;
|
||||
// Point the beginning of the level buffer to the location inside
|
||||
// the padded border
|
||||
frm_pyr->level_loc[0] =
|
||||
frm_pyr->strides[0] * frm_pyr->pad_size + frm_pyr->pad_size;
|
||||
// This essentially copies the original buffer into the pyramid buffer
|
||||
// without the original padding
|
||||
av1_resize_plane(frm, frm_height, frm_width, frm_stride,
|
||||
frm_pyr->level_buffer + frm_pyr->level_loc[0],
|
||||
frm_pyr->heights[0], frm_pyr->widths[0],
|
||||
frm_pyr->strides[0]);
|
||||
|
||||
if (compute_grad) {
|
||||
cur_width = frm_pyr->widths[0];
|
||||
cur_height = frm_pyr->heights[0];
|
||||
cur_stride = frm_pyr->strides[0];
|
||||
cur_loc = frm_pyr->level_loc[0];
|
||||
assert(frm_pyr->has_gradient && frm_pyr->level_dx_buffer != NULL &&
|
||||
frm_pyr->level_dy_buffer != NULL);
|
||||
// Computation x gradient
|
||||
sobel_xy_image_gradient(frm_pyr->level_buffer + cur_loc, cur_stride,
|
||||
frm_pyr->level_dx_buffer + cur_loc, cur_stride,
|
||||
cur_height, cur_width, 1);
|
||||
|
||||
// Computation y gradient
|
||||
sobel_xy_image_gradient(frm_pyr->level_buffer + cur_loc, cur_stride,
|
||||
frm_pyr->level_dy_buffer + cur_loc, cur_stride,
|
||||
cur_height, cur_width, 0);
|
||||
}
|
||||
|
||||
// Start at the finest level and resize down to the coarsest level
|
||||
for (int level = 1; level < n_levels; ++level) {
|
||||
update_level_dims(frm_pyr, level);
|
||||
cur_width = frm_pyr->widths[level];
|
||||
cur_height = frm_pyr->heights[level];
|
||||
cur_stride = frm_pyr->strides[level];
|
||||
cur_loc = frm_pyr->level_loc[level];
|
||||
|
||||
av1_resize_plane(frm_pyr->level_buffer + frm_pyr->level_loc[level - 1],
|
||||
frm_pyr->heights[level - 1], frm_pyr->widths[level - 1],
|
||||
frm_pyr->strides[level - 1],
|
||||
frm_pyr->level_buffer + cur_loc, cur_height, cur_width,
|
||||
cur_stride);
|
||||
|
||||
if (compute_grad) {
|
||||
assert(frm_pyr->has_gradient && frm_pyr->level_dx_buffer != NULL &&
|
||||
frm_pyr->level_dy_buffer != NULL);
|
||||
// Computation x gradient
|
||||
sobel_xy_image_gradient(frm_pyr->level_buffer + cur_loc, cur_stride,
|
||||
frm_pyr->level_dx_buffer + cur_loc, cur_stride,
|
||||
cur_height, cur_width, 1);
|
||||
|
||||
// Computation y gradient
|
||||
sobel_xy_image_gradient(frm_pyr->level_buffer + cur_loc, cur_stride,
|
||||
frm_pyr->level_dy_buffer + cur_loc, cur_stride,
|
||||
cur_height, cur_width, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static INLINE void compute_flow_at_point(unsigned char *frm, unsigned char *ref,
|
||||
double *dx, double *dy, int x, int y,
|
||||
int width, int height, int stride,
|
||||
double *u, double *v) {
|
||||
double M[4] = { 0 };
|
||||
double b[2] = { 0 };
|
||||
double tmp_output_vec[2] = { 0 };
|
||||
double error = 0;
|
||||
int16_t dt[PATCH_SIZE * PATCH_SIZE];
|
||||
double o_u = *u;
|
||||
double o_v = *v;
|
||||
|
||||
for (int itr = 0; itr < DISFLOW_MAX_ITR; itr++) {
|
||||
error = compute_warp_and_error(ref, frm, width, height, stride, x, y, *u,
|
||||
*v, dt);
|
||||
if (error <= DISFLOW_ERROR_TR) break;
|
||||
compute_flow_system(dx, stride, dy, stride, dt, PATCH_SIZE, M, b);
|
||||
solve_2x2_system(M, b, tmp_output_vec);
|
||||
*u += tmp_output_vec[0];
|
||||
*v += tmp_output_vec[1];
|
||||
}
|
||||
if (fabs(*u - o_u) > PATCH_SIZE || fabs(*v - o_u) > PATCH_SIZE) {
|
||||
*u = o_u;
|
||||
*v = o_v;
|
||||
}
|
||||
}
|
||||
|
||||
// make sure flow_u and flow_v start at 0
|
||||
static void compute_flow_field(ImagePyramid *frm_pyr, ImagePyramid *ref_pyr,
|
||||
double *flow_u, double *flow_v) {
|
||||
int cur_width, cur_height, cur_stride, cur_loc, patch_loc, patch_center;
|
||||
double *u_upscale =
|
||||
aom_malloc(frm_pyr->strides[0] * frm_pyr->heights[0] * sizeof(*flow_u));
|
||||
double *v_upscale =
|
||||
aom_malloc(frm_pyr->strides[0] * frm_pyr->heights[0] * sizeof(*flow_v));
|
||||
|
||||
assert(frm_pyr->n_levels == ref_pyr->n_levels);
|
||||
|
||||
// Compute flow field from coarsest to finest level of the pyramid
|
||||
for (int level = frm_pyr->n_levels - 1; level >= 0; --level) {
|
||||
cur_width = frm_pyr->widths[level];
|
||||
cur_height = frm_pyr->heights[level];
|
||||
cur_stride = frm_pyr->strides[level];
|
||||
cur_loc = frm_pyr->level_loc[level];
|
||||
|
||||
for (int i = PATCH_SIZE; i < cur_height - PATCH_SIZE; i += PATCH_STEP) {
|
||||
for (int j = PATCH_SIZE; j < cur_width - PATCH_SIZE; j += PATCH_STEP) {
|
||||
patch_loc = i * cur_stride + j;
|
||||
patch_center = patch_loc + PATCH_CENTER * cur_stride + PATCH_CENTER;
|
||||
compute_flow_at_point(frm_pyr->level_buffer + cur_loc,
|
||||
ref_pyr->level_buffer + cur_loc,
|
||||
frm_pyr->level_dx_buffer + cur_loc + patch_loc,
|
||||
frm_pyr->level_dy_buffer + cur_loc + patch_loc, j,
|
||||
i, cur_width, cur_height, cur_stride,
|
||||
flow_u + patch_center, flow_v + patch_center);
|
||||
}
|
||||
}
|
||||
// TODO(sarahparker) Replace this with upscale function in resize.c
|
||||
if (level > 0) {
|
||||
int h_upscale = frm_pyr->heights[level - 1];
|
||||
int w_upscale = frm_pyr->widths[level - 1];
|
||||
int s_upscale = frm_pyr->strides[level - 1];
|
||||
for (int i = 0; i < h_upscale; ++i) {
|
||||
for (int j = 0; j < w_upscale; ++j) {
|
||||
u_upscale[j + i * s_upscale] =
|
||||
flow_u[(int)(j >> 1) + (int)(i >> 1) * cur_stride];
|
||||
v_upscale[j + i * s_upscale] =
|
||||
flow_v[(int)(j >> 1) + (int)(i >> 1) * cur_stride];
|
||||
}
|
||||
}
|
||||
memcpy(flow_u, u_upscale,
|
||||
frm_pyr->strides[0] * frm_pyr->heights[0] * sizeof(*flow_u));
|
||||
memcpy(flow_v, v_upscale,
|
||||
frm_pyr->strides[0] * frm_pyr->heights[0] * sizeof(*flow_v));
|
||||
}
|
||||
}
|
||||
aom_free(u_upscale);
|
||||
aom_free(v_upscale);
|
||||
}
|
||||
|
||||
static int compute_global_motion_disflow_based(
|
||||
TransformationType type, YV12_BUFFER_CONFIG *frm, YV12_BUFFER_CONFIG *ref,
|
||||
int bit_depth, int *num_inliers_by_motion, double *params_by_motion,
|
||||
int num_motions) {
|
||||
unsigned char *frm_buffer = frm->y_buffer;
|
||||
unsigned char *ref_buffer = ref->y_buffer;
|
||||
const int frm_width = frm->y_width;
|
||||
const int frm_height = frm->y_height;
|
||||
const int ref_width = ref->y_width;
|
||||
const int ref_height = ref->y_height;
|
||||
const int pad_size = AOMMAX(PATCH_SIZE, MIN_PAD);
|
||||
int num_frm_corners;
|
||||
int num_correspondences;
|
||||
double *correspondences;
|
||||
int frm_corners[2 * MAX_CORNERS];
|
||||
RansacFuncDouble ransac = get_ransac_double_prec_type(type);
|
||||
assert(frm_width == ref_width);
|
||||
assert(frm_height == ref_height);
|
||||
|
||||
// Ensure the number of pyramid levels will work with the frame resolution
|
||||
const int msb =
|
||||
frm_width < frm_height ? get_msb(frm_width) : get_msb(frm_height);
|
||||
const int n_levels = AOMMIN(msb, N_LEVELS);
|
||||
|
||||
if (frm->flags & YV12_FLAG_HIGHBITDEPTH) {
|
||||
// The frame buffer is 16-bit, so we need to convert to 8 bits for the
|
||||
// following code. We cache the result until the frame is released.
|
||||
frm_buffer = downconvert_frame(frm, bit_depth);
|
||||
}
|
||||
if (ref->flags & YV12_FLAG_HIGHBITDEPTH) {
|
||||
ref_buffer = downconvert_frame(ref, bit_depth);
|
||||
}
|
||||
|
||||
// TODO(sarahparker) We will want to do the source pyramid computation
|
||||
// outside of this function so it doesn't get recomputed for every
|
||||
// reference. We also don't need to compute every pyramid level for the
|
||||
// reference in advance, since lower levels can be overwritten once their
|
||||
// flow field is computed and upscaled. I'll add these optimizations
|
||||
// once the full implementation is working.
|
||||
// Allocate frm image pyramids
|
||||
int compute_gradient = 1;
|
||||
ImagePyramid *frm_pyr =
|
||||
alloc_pyramid(frm_width, frm_height, pad_size, compute_gradient);
|
||||
compute_flow_pyramids(frm_buffer, frm_width, frm_height, frm->y_stride,
|
||||
n_levels, pad_size, compute_gradient, frm_pyr);
|
||||
// Allocate ref image pyramids
|
||||
compute_gradient = 0;
|
||||
ImagePyramid *ref_pyr =
|
||||
alloc_pyramid(ref_width, ref_height, pad_size, compute_gradient);
|
||||
compute_flow_pyramids(ref_buffer, ref_width, ref_height, ref->y_stride,
|
||||
n_levels, pad_size, compute_gradient, ref_pyr);
|
||||
|
||||
double *flow_u =
|
||||
aom_malloc(frm_pyr->strides[0] * frm_pyr->heights[0] * sizeof(*flow_u));
|
||||
double *flow_v =
|
||||
aom_malloc(frm_pyr->strides[0] * frm_pyr->heights[0] * sizeof(*flow_v));
|
||||
|
||||
memset(flow_u, 0,
|
||||
frm_pyr->strides[0] * frm_pyr->heights[0] * sizeof(*flow_u));
|
||||
memset(flow_v, 0,
|
||||
frm_pyr->strides[0] * frm_pyr->heights[0] * sizeof(*flow_v));
|
||||
|
||||
compute_flow_field(frm_pyr, ref_pyr, flow_u, flow_v);
|
||||
|
||||
// compute interest points in images using FAST features
|
||||
num_frm_corners = fast_corner_detect(frm_buffer, frm_width, frm_height,
|
||||
frm->y_stride, frm_corners, MAX_CORNERS);
|
||||
// find correspondences between the two images using the flow field
|
||||
correspondences = aom_malloc(num_frm_corners * 4 * sizeof(*correspondences));
|
||||
num_correspondences = determine_disflow_correspondence(
|
||||
frm_corners, num_frm_corners, flow_u, flow_v, frm_width, frm_height,
|
||||
frm_pyr->strides[0], correspondences);
|
||||
ransac(correspondences, num_correspondences, num_inliers_by_motion,
|
||||
params_by_motion, num_motions);
|
||||
|
||||
free_pyramid(frm_pyr);
|
||||
free_pyramid(ref_pyr);
|
||||
aom_free(correspondences);
|
||||
aom_free(flow_u);
|
||||
aom_free(flow_v);
|
||||
// Set num_inliers = 0 for motions with too few inliers so they are ignored.
|
||||
for (int i = 0; i < num_motions; ++i) {
|
||||
if (num_inliers_by_motion[i] < MIN_INLIER_PROB * num_correspondences) {
|
||||
num_inliers_by_motion[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Return true if any one of the motions has inliers.
|
||||
for (int i = 0; i < num_motions; ++i) {
|
||||
if (num_inliers_by_motion[i] > 0) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int av1_compute_global_motion(TransformationType type, YV12_BUFFER_CONFIG *frm,
|
||||
YV12_BUFFER_CONFIG *ref, int bit_depth,
|
||||
int *num_inliers_by_motion,
|
||||
double *params_by_motion, int num_motions) {
|
||||
#if USE_GM_FEATURE_BASED
|
||||
return compute_global_motion_feature_based(type, frm, ref, bit_depth,
|
||||
num_inliers_by_motion,
|
||||
params_by_motion, num_motions);
|
||||
#else
|
||||
return compute_global_motion_disflow_based(type, frm, ref, bit_depth,
|
||||
num_inliers_by_motion,
|
||||
params_by_motion, num_motions);
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
30
third_party/aom/av1/encoder/global_motion.h
vendored
30
third_party/aom/av1/encoder/global_motion.h
vendored
|
|
@ -22,20 +22,22 @@ extern "C" {
|
|||
|
||||
#define RANSAC_NUM_MOTIONS 1
|
||||
|
||||
void convert_model_to_params(const double *params, WarpedMotionParams *model);
|
||||
void av1_convert_model_to_params(const double *params,
|
||||
WarpedMotionParams *model);
|
||||
|
||||
int is_enough_erroradvantage(double best_erroradvantage, int params_cost,
|
||||
int erroradv_type);
|
||||
int av1_is_enough_erroradvantage(double best_erroradvantage, int params_cost,
|
||||
int erroradv_type);
|
||||
|
||||
// Returns the av1_warp_error between "dst" and the result of applying the
|
||||
// motion params that result from fine-tuning "wm" to "ref". Note that "wm" is
|
||||
// modified in place.
|
||||
int64_t refine_integerized_param(WarpedMotionParams *wm,
|
||||
TransformationType wmtype, int use_hbd, int bd,
|
||||
uint8_t *ref, int r_width, int r_height,
|
||||
int r_stride, uint8_t *dst, int d_width,
|
||||
int d_height, int d_stride, int n_refinements,
|
||||
int64_t best_frame_error);
|
||||
int64_t av1_refine_integerized_param(WarpedMotionParams *wm,
|
||||
TransformationType wmtype, int use_hbd,
|
||||
int bd, uint8_t *ref, int r_width,
|
||||
int r_height, int r_stride, uint8_t *dst,
|
||||
int d_width, int d_height, int d_stride,
|
||||
int n_refinements,
|
||||
int64_t best_frame_error);
|
||||
|
||||
/*
|
||||
Computes "num_motions" candidate global motion parameters between two frames.
|
||||
|
|
@ -52,12 +54,10 @@ int64_t refine_integerized_param(WarpedMotionParams *wm,
|
|||
number of inlier feature points for each motion. Params for which the
|
||||
num_inliers entry is 0 should be ignored by the caller.
|
||||
*/
|
||||
int compute_global_motion_feature_based(TransformationType type,
|
||||
YV12_BUFFER_CONFIG *frm,
|
||||
YV12_BUFFER_CONFIG *ref, int bit_depth,
|
||||
int *num_inliers_by_motion,
|
||||
double *params_by_motion,
|
||||
int num_motions);
|
||||
int av1_compute_global_motion(TransformationType type, YV12_BUFFER_CONFIG *frm,
|
||||
YV12_BUFFER_CONFIG *ref, int bit_depth,
|
||||
int *num_inliers_by_motion,
|
||||
double *params_by_motion, int num_motions);
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
|
|
|||
3
third_party/aom/av1/encoder/hash_motion.c
vendored
3
third_party/aom/av1/encoder/hash_motion.c
vendored
|
|
@ -147,7 +147,8 @@ static void hash_table_add_to_table(hash_table *p_hash_table,
|
|||
}
|
||||
}
|
||||
|
||||
int32_t av1_hash_table_count(hash_table *p_hash_table, uint32_t hash_value) {
|
||||
int32_t av1_hash_table_count(const hash_table *p_hash_table,
|
||||
uint32_t hash_value) {
|
||||
if (p_hash_table->p_lookup_table[hash_value] == NULL) {
|
||||
return 0;
|
||||
} else {
|
||||
|
|
|
|||
3
third_party/aom/av1/encoder/hash_motion.h
vendored
3
third_party/aom/av1/encoder/hash_motion.h
vendored
|
|
@ -37,7 +37,8 @@ typedef struct _hash_table {
|
|||
void av1_hash_table_init(hash_table *p_hash_table, struct macroblock *x);
|
||||
void av1_hash_table_destroy(hash_table *p_hash_table);
|
||||
void av1_hash_table_create(hash_table *p_hash_table);
|
||||
int32_t av1_hash_table_count(hash_table *p_hash_table, uint32_t hash_value);
|
||||
int32_t av1_hash_table_count(const hash_table *p_hash_table,
|
||||
uint32_t hash_value);
|
||||
Iterator av1_hash_get_first_iterator(hash_table *p_hash_table,
|
||||
uint32_t hash_value);
|
||||
int32_t av1_has_exact_match(hash_table *p_hash_table, uint32_t hash_value1,
|
||||
|
|
|
|||
138
third_party/aom/av1/encoder/hybrid_fwd_txfm.c
vendored
138
third_party/aom/av1/encoder/hybrid_fwd_txfm.c
vendored
|
|
@ -87,35 +87,21 @@ static void highbd_fwd_txfm_4x4(const int16_t *src_diff, tran_low_t *coeff,
|
|||
av1_highbd_fwht4x4(src_diff, coeff, diff_stride);
|
||||
return;
|
||||
}
|
||||
switch (tx_type) {
|
||||
// use the c version for anything including identity for now
|
||||
case V_DCT:
|
||||
case H_DCT:
|
||||
case V_ADST:
|
||||
case H_ADST:
|
||||
case V_FLIPADST:
|
||||
case H_FLIPADST:
|
||||
case IDTX:
|
||||
av1_fwd_txfm2d_4x4_c(src_diff, dst_coeff, diff_stride, tx_type, bd);
|
||||
break;
|
||||
default:
|
||||
av1_fwd_txfm2d_4x4(src_diff, dst_coeff, diff_stride, tx_type, bd);
|
||||
break;
|
||||
}
|
||||
av1_fwd_txfm2d_4x4(src_diff, dst_coeff, diff_stride, tx_type, bd);
|
||||
}
|
||||
|
||||
static void highbd_fwd_txfm_4x8(const int16_t *src_diff, tran_low_t *coeff,
|
||||
int diff_stride, TxfmParam *txfm_param) {
|
||||
int32_t *dst_coeff = (int32_t *)coeff;
|
||||
av1_fwd_txfm2d_4x8_c(src_diff, dst_coeff, diff_stride, txfm_param->tx_type,
|
||||
txfm_param->bd);
|
||||
av1_fwd_txfm2d_4x8(src_diff, dst_coeff, diff_stride, txfm_param->tx_type,
|
||||
txfm_param->bd);
|
||||
}
|
||||
|
||||
static void highbd_fwd_txfm_8x4(const int16_t *src_diff, tran_low_t *coeff,
|
||||
int diff_stride, TxfmParam *txfm_param) {
|
||||
int32_t *dst_coeff = (int32_t *)coeff;
|
||||
av1_fwd_txfm2d_8x4_c(src_diff, dst_coeff, diff_stride, txfm_param->tx_type,
|
||||
txfm_param->bd);
|
||||
av1_fwd_txfm2d_8x4(src_diff, dst_coeff, diff_stride, txfm_param->tx_type,
|
||||
txfm_param->bd);
|
||||
}
|
||||
|
||||
static void highbd_fwd_txfm_8x16(const int16_t *src_diff, tran_low_t *coeff,
|
||||
|
|
@ -123,21 +109,7 @@ static void highbd_fwd_txfm_8x16(const int16_t *src_diff, tran_low_t *coeff,
|
|||
int32_t *dst_coeff = (int32_t *)coeff;
|
||||
const TX_TYPE tx_type = txfm_param->tx_type;
|
||||
const int bd = txfm_param->bd;
|
||||
switch (tx_type) {
|
||||
// use the c version for anything including identity for now
|
||||
case V_DCT:
|
||||
case H_DCT:
|
||||
case V_ADST:
|
||||
case H_ADST:
|
||||
case V_FLIPADST:
|
||||
case H_FLIPADST:
|
||||
case IDTX:
|
||||
av1_fwd_txfm2d_8x16_c(src_diff, dst_coeff, diff_stride, tx_type, bd);
|
||||
break;
|
||||
default:
|
||||
av1_fwd_txfm2d_8x16(src_diff, dst_coeff, diff_stride, tx_type, bd);
|
||||
break;
|
||||
}
|
||||
av1_fwd_txfm2d_8x16(src_diff, dst_coeff, diff_stride, tx_type, bd);
|
||||
}
|
||||
|
||||
static void highbd_fwd_txfm_16x8(const int16_t *src_diff, tran_low_t *coeff,
|
||||
|
|
@ -145,63 +117,49 @@ static void highbd_fwd_txfm_16x8(const int16_t *src_diff, tran_low_t *coeff,
|
|||
int32_t *dst_coeff = (int32_t *)coeff;
|
||||
const TX_TYPE tx_type = txfm_param->tx_type;
|
||||
const int bd = txfm_param->bd;
|
||||
switch (tx_type) {
|
||||
// use the c version for anything including identity for now
|
||||
case V_DCT:
|
||||
case H_DCT:
|
||||
case V_ADST:
|
||||
case H_ADST:
|
||||
case V_FLIPADST:
|
||||
case H_FLIPADST:
|
||||
case IDTX:
|
||||
av1_fwd_txfm2d_16x8_c(src_diff, dst_coeff, diff_stride, tx_type, bd);
|
||||
break;
|
||||
default:
|
||||
av1_fwd_txfm2d_16x8(src_diff, dst_coeff, diff_stride, tx_type, bd);
|
||||
break;
|
||||
}
|
||||
av1_fwd_txfm2d_16x8(src_diff, dst_coeff, diff_stride, tx_type, bd);
|
||||
}
|
||||
|
||||
static void highbd_fwd_txfm_16x32(const int16_t *src_diff, tran_low_t *coeff,
|
||||
int diff_stride, TxfmParam *txfm_param) {
|
||||
int32_t *dst_coeff = (int32_t *)coeff;
|
||||
av1_fwd_txfm2d_16x32_c(src_diff, dst_coeff, diff_stride, txfm_param->tx_type,
|
||||
txfm_param->bd);
|
||||
av1_fwd_txfm2d_16x32(src_diff, dst_coeff, diff_stride, txfm_param->tx_type,
|
||||
txfm_param->bd);
|
||||
}
|
||||
|
||||
static void highbd_fwd_txfm_32x16(const int16_t *src_diff, tran_low_t *coeff,
|
||||
int diff_stride, TxfmParam *txfm_param) {
|
||||
int32_t *dst_coeff = (int32_t *)coeff;
|
||||
av1_fwd_txfm2d_32x16_c(src_diff, dst_coeff, diff_stride, txfm_param->tx_type,
|
||||
txfm_param->bd);
|
||||
av1_fwd_txfm2d_32x16(src_diff, dst_coeff, diff_stride, txfm_param->tx_type,
|
||||
txfm_param->bd);
|
||||
}
|
||||
|
||||
static void highbd_fwd_txfm_16x4(const int16_t *src_diff, tran_low_t *coeff,
|
||||
int diff_stride, TxfmParam *txfm_param) {
|
||||
int32_t *dst_coeff = (int32_t *)coeff;
|
||||
av1_fwd_txfm2d_16x4_c(src_diff, dst_coeff, diff_stride, txfm_param->tx_type,
|
||||
txfm_param->bd);
|
||||
av1_fwd_txfm2d_16x4(src_diff, dst_coeff, diff_stride, txfm_param->tx_type,
|
||||
txfm_param->bd);
|
||||
}
|
||||
|
||||
static void highbd_fwd_txfm_4x16(const int16_t *src_diff, tran_low_t *coeff,
|
||||
int diff_stride, TxfmParam *txfm_param) {
|
||||
int32_t *dst_coeff = (int32_t *)coeff;
|
||||
av1_fwd_txfm2d_4x16_c(src_diff, dst_coeff, diff_stride, txfm_param->tx_type,
|
||||
txfm_param->bd);
|
||||
av1_fwd_txfm2d_4x16(src_diff, dst_coeff, diff_stride, txfm_param->tx_type,
|
||||
txfm_param->bd);
|
||||
}
|
||||
|
||||
static void highbd_fwd_txfm_32x8(const int16_t *src_diff, tran_low_t *coeff,
|
||||
int diff_stride, TxfmParam *txfm_param) {
|
||||
int32_t *dst_coeff = (int32_t *)coeff;
|
||||
av1_fwd_txfm2d_32x8_c(src_diff, dst_coeff, diff_stride, txfm_param->tx_type,
|
||||
txfm_param->bd);
|
||||
av1_fwd_txfm2d_32x8(src_diff, dst_coeff, diff_stride, txfm_param->tx_type,
|
||||
txfm_param->bd);
|
||||
}
|
||||
|
||||
static void highbd_fwd_txfm_8x32(const int16_t *src_diff, tran_low_t *coeff,
|
||||
int diff_stride, TxfmParam *txfm_param) {
|
||||
int32_t *dst_coeff = (int32_t *)coeff;
|
||||
av1_fwd_txfm2d_8x32_c(src_diff, dst_coeff, diff_stride, txfm_param->tx_type,
|
||||
txfm_param->bd);
|
||||
av1_fwd_txfm2d_8x32(src_diff, dst_coeff, diff_stride, txfm_param->tx_type,
|
||||
txfm_param->bd);
|
||||
}
|
||||
|
||||
static void highbd_fwd_txfm_8x8(const int16_t *src_diff, tran_low_t *coeff,
|
||||
|
|
@ -209,21 +167,7 @@ static void highbd_fwd_txfm_8x8(const int16_t *src_diff, tran_low_t *coeff,
|
|||
int32_t *dst_coeff = (int32_t *)coeff;
|
||||
const TX_TYPE tx_type = txfm_param->tx_type;
|
||||
const int bd = txfm_param->bd;
|
||||
switch (tx_type) {
|
||||
// use the c version for anything including identity for now
|
||||
case V_DCT:
|
||||
case H_DCT:
|
||||
case V_ADST:
|
||||
case H_ADST:
|
||||
case V_FLIPADST:
|
||||
case H_FLIPADST:
|
||||
case IDTX:
|
||||
av1_fwd_txfm2d_8x8_c(src_diff, dst_coeff, diff_stride, tx_type, bd);
|
||||
break;
|
||||
default:
|
||||
av1_fwd_txfm2d_8x8(src_diff, dst_coeff, diff_stride, tx_type, bd);
|
||||
break;
|
||||
}
|
||||
av1_fwd_txfm2d_8x8(src_diff, dst_coeff, diff_stride, tx_type, bd);
|
||||
}
|
||||
|
||||
static void highbd_fwd_txfm_16x16(const int16_t *src_diff, tran_low_t *coeff,
|
||||
|
|
@ -231,21 +175,7 @@ static void highbd_fwd_txfm_16x16(const int16_t *src_diff, tran_low_t *coeff,
|
|||
int32_t *dst_coeff = (int32_t *)coeff;
|
||||
const TX_TYPE tx_type = txfm_param->tx_type;
|
||||
const int bd = txfm_param->bd;
|
||||
switch (tx_type) {
|
||||
// use the c version for anything including identity for now
|
||||
case V_DCT:
|
||||
case H_DCT:
|
||||
case V_ADST:
|
||||
case H_ADST:
|
||||
case V_FLIPADST:
|
||||
case H_FLIPADST:
|
||||
case IDTX:
|
||||
av1_fwd_txfm2d_16x16_c(src_diff, dst_coeff, diff_stride, tx_type, bd);
|
||||
break;
|
||||
default:
|
||||
av1_fwd_txfm2d_16x16(src_diff, dst_coeff, diff_stride, tx_type, bd);
|
||||
break;
|
||||
}
|
||||
av1_fwd_txfm2d_16x16(src_diff, dst_coeff, diff_stride, tx_type, bd);
|
||||
}
|
||||
|
||||
static void highbd_fwd_txfm_32x32(const int16_t *src_diff, tran_low_t *coeff,
|
||||
|
|
@ -253,21 +183,7 @@ static void highbd_fwd_txfm_32x32(const int16_t *src_diff, tran_low_t *coeff,
|
|||
int32_t *dst_coeff = (int32_t *)coeff;
|
||||
const TX_TYPE tx_type = txfm_param->tx_type;
|
||||
const int bd = txfm_param->bd;
|
||||
switch (tx_type) {
|
||||
// use the c version for anything including identity for now
|
||||
case V_DCT:
|
||||
case H_DCT:
|
||||
case V_ADST:
|
||||
case H_ADST:
|
||||
case V_FLIPADST:
|
||||
case H_FLIPADST:
|
||||
case IDTX:
|
||||
av1_fwd_txfm2d_32x32_c(src_diff, dst_coeff, diff_stride, tx_type, bd);
|
||||
break;
|
||||
default:
|
||||
av1_fwd_txfm2d_32x32(src_diff, dst_coeff, diff_stride, tx_type, bd);
|
||||
break;
|
||||
}
|
||||
av1_fwd_txfm2d_32x32(src_diff, dst_coeff, diff_stride, tx_type, bd);
|
||||
}
|
||||
|
||||
static void highbd_fwd_txfm_32x64(const int16_t *src_diff, tran_low_t *coeff,
|
||||
|
|
@ -275,7 +191,8 @@ static void highbd_fwd_txfm_32x64(const int16_t *src_diff, tran_low_t *coeff,
|
|||
assert(txfm_param->tx_type == DCT_DCT);
|
||||
int32_t *dst_coeff = (int32_t *)coeff;
|
||||
const int bd = txfm_param->bd;
|
||||
av1_fwd_txfm2d_32x64_c(src_diff, dst_coeff, diff_stride, DCT_DCT, bd);
|
||||
av1_fwd_txfm2d_32x64(src_diff, dst_coeff, diff_stride, txfm_param->tx_type,
|
||||
bd);
|
||||
}
|
||||
|
||||
static void highbd_fwd_txfm_64x32(const int16_t *src_diff, tran_low_t *coeff,
|
||||
|
|
@ -283,7 +200,8 @@ static void highbd_fwd_txfm_64x32(const int16_t *src_diff, tran_low_t *coeff,
|
|||
assert(txfm_param->tx_type == DCT_DCT);
|
||||
int32_t *dst_coeff = (int32_t *)coeff;
|
||||
const int bd = txfm_param->bd;
|
||||
av1_fwd_txfm2d_64x32_c(src_diff, dst_coeff, diff_stride, DCT_DCT, bd);
|
||||
av1_fwd_txfm2d_64x32(src_diff, dst_coeff, diff_stride, txfm_param->tx_type,
|
||||
bd);
|
||||
}
|
||||
|
||||
static void highbd_fwd_txfm_16x64(const int16_t *src_diff, tran_low_t *coeff,
|
||||
|
|
@ -291,7 +209,7 @@ static void highbd_fwd_txfm_16x64(const int16_t *src_diff, tran_low_t *coeff,
|
|||
assert(txfm_param->tx_type == DCT_DCT);
|
||||
int32_t *dst_coeff = (int32_t *)coeff;
|
||||
const int bd = txfm_param->bd;
|
||||
av1_fwd_txfm2d_16x64_c(src_diff, dst_coeff, diff_stride, DCT_DCT, bd);
|
||||
av1_fwd_txfm2d_16x64(src_diff, dst_coeff, diff_stride, DCT_DCT, bd);
|
||||
}
|
||||
|
||||
static void highbd_fwd_txfm_64x16(const int16_t *src_diff, tran_low_t *coeff,
|
||||
|
|
@ -299,7 +217,7 @@ static void highbd_fwd_txfm_64x16(const int16_t *src_diff, tran_low_t *coeff,
|
|||
assert(txfm_param->tx_type == DCT_DCT);
|
||||
int32_t *dst_coeff = (int32_t *)coeff;
|
||||
const int bd = txfm_param->bd;
|
||||
av1_fwd_txfm2d_64x16_c(src_diff, dst_coeff, diff_stride, DCT_DCT, bd);
|
||||
av1_fwd_txfm2d_64x16(src_diff, dst_coeff, diff_stride, DCT_DCT, bd);
|
||||
}
|
||||
|
||||
static void highbd_fwd_txfm_64x64(const int16_t *src_diff, tran_low_t *coeff,
|
||||
|
|
|
|||
5
third_party/aom/av1/encoder/lookahead.c
vendored
5
third_party/aom/av1/encoder/lookahead.c
vendored
|
|
@ -43,7 +43,8 @@ void av1_lookahead_destroy(struct lookahead_ctx *ctx) {
|
|||
|
||||
struct lookahead_ctx *av1_lookahead_init(
|
||||
unsigned int width, unsigned int height, unsigned int subsampling_x,
|
||||
unsigned int subsampling_y, int use_highbitdepth, unsigned int depth) {
|
||||
unsigned int subsampling_y, int use_highbitdepth, unsigned int depth,
|
||||
const int border_in_pixels) {
|
||||
struct lookahead_ctx *ctx = NULL;
|
||||
|
||||
// Clamp the lookahead queue depth
|
||||
|
|
@ -63,7 +64,7 @@ struct lookahead_ctx *av1_lookahead_init(
|
|||
for (i = 0; i < depth; i++)
|
||||
if (aom_alloc_frame_buffer(&ctx->buf[i].img, width, height, subsampling_x,
|
||||
subsampling_y, use_highbitdepth,
|
||||
AOM_BORDER_IN_PIXELS, legacy_byte_alignment))
|
||||
border_in_pixels, legacy_byte_alignment))
|
||||
goto bail;
|
||||
}
|
||||
return ctx;
|
||||
|
|
|
|||
3
third_party/aom/av1/encoder/lookahead.h
vendored
3
third_party/aom/av1/encoder/lookahead.h
vendored
|
|
@ -46,7 +46,8 @@ struct lookahead_ctx {
|
|||
*/
|
||||
struct lookahead_ctx *av1_lookahead_init(
|
||||
unsigned int width, unsigned int height, unsigned int subsampling_x,
|
||||
unsigned int subsampling_y, int use_highbitdepth, unsigned int depth);
|
||||
unsigned int subsampling_y, int use_highbitdepth, unsigned int depth,
|
||||
const int border_in_pixels);
|
||||
|
||||
/**\brief Destroys the lookahead stage
|
||||
*/
|
||||
|
|
|
|||
12
third_party/aom/av1/encoder/mbgraph.c
vendored
12
third_party/aom/av1/encoder/mbgraph.c
vendored
|
|
@ -60,7 +60,7 @@ static unsigned int do_16x16_motion_iteration(AV1_COMP *cpi, const MV *ref_mv,
|
|||
x, &cpi->common, mb_row, mb_col, ref_mv,
|
||||
cpi->common.allow_high_precision_mv, x->errorperbit, &v_fn_ptr, 0,
|
||||
mv_sf->subpel_iters_per_step, cond_cost_list(cpi, cost_list), NULL,
|
||||
NULL, &distortion, &sse, NULL, NULL, 0, 0, 0, 0, 0);
|
||||
NULL, &distortion, &sse, NULL, NULL, 0, 0, 0, 0, 0, 1);
|
||||
}
|
||||
|
||||
if (has_second_ref(xd->mi[0]))
|
||||
|
|
@ -71,8 +71,8 @@ static unsigned int do_16x16_motion_iteration(AV1_COMP *cpi, const MV *ref_mv,
|
|||
xd->mi[0]->mv[0] = x->best_mv;
|
||||
xd->mi[0]->ref_frame[1] = NONE_FRAME;
|
||||
|
||||
av1_build_inter_predictors_sby(&cpi->common, xd, mb_row, mb_col, NULL,
|
||||
BLOCK_16X16);
|
||||
av1_enc_build_inter_predictor(&cpi->common, xd, mb_row, mb_col, NULL,
|
||||
BLOCK_16X16, AOM_PLANE_Y, AOM_PLANE_Y);
|
||||
|
||||
/* restore UMV window */
|
||||
x->mv_limits = tmp_mv_limits;
|
||||
|
|
@ -179,8 +179,8 @@ static void update_mbgraph_mb_stats(AV1_COMP *cpi, MBGRAPH_MB_STATS *stats,
|
|||
x->plane[0].src.buf = buf->y_buffer + mb_y_offset;
|
||||
x->plane[0].src.stride = buf->y_stride;
|
||||
|
||||
xd->plane[0].dst.buf = get_frame_new_buffer(cm)->y_buffer + mb_y_offset;
|
||||
xd->plane[0].dst.stride = get_frame_new_buffer(cm)->y_stride;
|
||||
xd->plane[0].dst.buf = cm->cur_frame->buf.y_buffer + mb_y_offset;
|
||||
xd->plane[0].dst.stride = cm->cur_frame->buf.y_stride;
|
||||
|
||||
// do intra 16x16 prediction
|
||||
intra_error = find_best_16x16_intra(cpi, &stats->ref[INTRA_FRAME].m.mode);
|
||||
|
|
@ -364,7 +364,7 @@ static void separate_arf_mbs(AV1_COMP *cpi) {
|
|||
void av1_update_mbgraph_stats(AV1_COMP *cpi) {
|
||||
AV1_COMMON *const cm = &cpi->common;
|
||||
int i, n_frames = av1_lookahead_depth(cpi->lookahead);
|
||||
YV12_BUFFER_CONFIG *golden_ref = get_ref_frame_buffer(cpi, GOLDEN_FRAME);
|
||||
YV12_BUFFER_CONFIG *golden_ref = &get_ref_frame_buf(cm, GOLDEN_FRAME)->buf;
|
||||
|
||||
assert(golden_ref != NULL);
|
||||
|
||||
|
|
|
|||
306
third_party/aom/av1/encoder/mcomp.c
vendored
306
third_party/aom/av1/encoder/mcomp.c
vendored
|
|
@ -112,7 +112,7 @@ static int mvsad_err_cost(const MACROBLOCK *x, const MV *mv, const MV *ref,
|
|||
int sad_per_bit) {
|
||||
const MV diff = { (mv->row - ref->row) * 8, (mv->col - ref->col) * 8 };
|
||||
return ROUND_POWER_OF_TWO(
|
||||
(unsigned)mv_cost(&diff, x->nmvjointcost, x->mvcost) * sad_per_bit,
|
||||
(unsigned)mv_cost(&diff, x->nmv_vec_cost, x->mv_cost_stack) * sad_per_bit,
|
||||
AV1_PROB_COST_SHIFT);
|
||||
}
|
||||
|
||||
|
|
@ -179,36 +179,31 @@ static INLINE const uint8_t *pre(const uint8_t *buf, int stride, int r, int c) {
|
|||
}
|
||||
|
||||
/* checks if (r, c) has better score than previous best */
|
||||
#define CHECK_BETTER(v, r, c) \
|
||||
if (c >= minc && c <= maxc && r >= minr && r <= maxr) { \
|
||||
MV this_mv = { r, c }; \
|
||||
v = mv_err_cost(&this_mv, ref_mv, mvjcost, mvcost, error_per_bit); \
|
||||
if (second_pred == NULL) { \
|
||||
thismse = vfp->svf(pre(y, y_stride, r, c), y_stride, sp(c), sp(r), \
|
||||
src_address, src_stride, &sse); \
|
||||
} else if (mask) { \
|
||||
thismse = vfp->msvf(pre(y, y_stride, r, c), y_stride, sp(c), sp(r), \
|
||||
src_address, src_stride, second_pred, mask, \
|
||||
mask_stride, invert_mask, &sse); \
|
||||
} else { \
|
||||
if (xd->jcp_param.use_jnt_comp_avg) \
|
||||
thismse = vfp->jsvaf(pre(y, y_stride, r, c), y_stride, sp(c), sp(r), \
|
||||
src_address, src_stride, &sse, second_pred, \
|
||||
&xd->jcp_param); \
|
||||
else \
|
||||
thismse = vfp->svaf(pre(y, y_stride, r, c), y_stride, sp(c), sp(r), \
|
||||
src_address, src_stride, &sse, second_pred); \
|
||||
} \
|
||||
v += thismse; \
|
||||
if (v < besterr) { \
|
||||
besterr = v; \
|
||||
br = r; \
|
||||
bc = c; \
|
||||
*distortion = thismse; \
|
||||
*sse1 = sse; \
|
||||
} \
|
||||
} else { \
|
||||
v = INT_MAX; \
|
||||
#define CHECK_BETTER(v, r, c) \
|
||||
if (c >= minc && c <= maxc && r >= minr && r <= maxr) { \
|
||||
MV this_mv = { r, c }; \
|
||||
v = mv_err_cost(&this_mv, ref_mv, mvjcost, mvcost, error_per_bit); \
|
||||
if (second_pred == NULL) { \
|
||||
thismse = vfp->svf(pre(y, y_stride, r, c), y_stride, sp(c), sp(r), \
|
||||
src_address, src_stride, &sse); \
|
||||
} else if (mask) { \
|
||||
thismse = vfp->msvf(pre(y, y_stride, r, c), y_stride, sp(c), sp(r), \
|
||||
src_address, src_stride, second_pred, mask, \
|
||||
mask_stride, invert_mask, &sse); \
|
||||
} else { \
|
||||
thismse = vfp->svaf(pre(y, y_stride, r, c), y_stride, sp(c), sp(r), \
|
||||
src_address, src_stride, &sse, second_pred); \
|
||||
} \
|
||||
v += thismse; \
|
||||
if (v < besterr) { \
|
||||
besterr = v; \
|
||||
br = r; \
|
||||
bc = c; \
|
||||
*distortion = thismse; \
|
||||
*sse1 = sse; \
|
||||
} \
|
||||
} else { \
|
||||
v = INT_MAX; \
|
||||
}
|
||||
|
||||
#define CHECK_BETTER0(v, r, c) CHECK_BETTER(v, r, c)
|
||||
|
|
@ -341,19 +336,15 @@ static unsigned int setup_center_error(
|
|||
int *mvcost[2], unsigned int *sse1, int *distortion) {
|
||||
unsigned int besterr;
|
||||
if (second_pred != NULL) {
|
||||
if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) {
|
||||
if (is_cur_buf_hbd(xd)) {
|
||||
DECLARE_ALIGNED(16, uint16_t, comp_pred16[MAX_SB_SQUARE]);
|
||||
uint8_t *comp_pred = CONVERT_TO_BYTEPTR(comp_pred16);
|
||||
if (mask) {
|
||||
aom_highbd_comp_mask_pred(comp_pred, second_pred, w, h, y + offset,
|
||||
y_stride, mask, mask_stride, invert_mask);
|
||||
} else {
|
||||
if (xd->jcp_param.use_jnt_comp_avg)
|
||||
aom_highbd_jnt_comp_avg_pred(comp_pred, second_pred, w, h, y + offset,
|
||||
y_stride, &xd->jcp_param);
|
||||
else
|
||||
aom_highbd_comp_avg_pred(comp_pred, second_pred, w, h, y + offset,
|
||||
y_stride);
|
||||
aom_highbd_comp_avg_pred(comp_pred, second_pred, w, h, y + offset,
|
||||
y_stride);
|
||||
}
|
||||
besterr = vfp->vf(comp_pred, w, src, src_stride, sse1);
|
||||
} else {
|
||||
|
|
@ -362,11 +353,7 @@ static unsigned int setup_center_error(
|
|||
aom_comp_mask_pred(comp_pred, second_pred, w, h, y + offset, y_stride,
|
||||
mask, mask_stride, invert_mask);
|
||||
} else {
|
||||
if (xd->jcp_param.use_jnt_comp_avg)
|
||||
aom_jnt_comp_avg_pred(comp_pred, second_pred, w, h, y + offset,
|
||||
y_stride, &xd->jcp_param);
|
||||
else
|
||||
aom_comp_avg_pred(comp_pred, second_pred, w, h, y + offset, y_stride);
|
||||
aom_comp_avg_pred(comp_pred, second_pred, w, h, y + offset, y_stride);
|
||||
}
|
||||
besterr = vfp->vf(comp_pred, w, src, src_stride, sse1);
|
||||
}
|
||||
|
|
@ -409,7 +396,7 @@ int av1_find_best_sub_pixel_tree_pruned_evenmore(
|
|||
int *cost_list, int *mvjcost, int *mvcost[2], int *distortion,
|
||||
unsigned int *sse1, const uint8_t *second_pred, const uint8_t *mask,
|
||||
int mask_stride, int invert_mask, int w, int h,
|
||||
int use_accurate_subpel_search) {
|
||||
int use_accurate_subpel_search, const int do_reset_fractional_mv) {
|
||||
SETUP_SUBPEL_SEARCH;
|
||||
besterr = setup_center_error(xd, bestmv, ref_mv, error_per_bit, vfp,
|
||||
src_address, src_stride, y, y_stride,
|
||||
|
|
@ -426,6 +413,7 @@ int av1_find_best_sub_pixel_tree_pruned_evenmore(
|
|||
(void)cm;
|
||||
(void)mi_row;
|
||||
(void)mi_col;
|
||||
(void)do_reset_fractional_mv;
|
||||
|
||||
if (cost_list && cost_list[0] != INT_MAX && cost_list[1] != INT_MAX &&
|
||||
cost_list[2] != INT_MAX && cost_list[3] != INT_MAX &&
|
||||
|
|
@ -481,12 +469,13 @@ int av1_find_best_sub_pixel_tree_pruned_more(
|
|||
int *cost_list, int *mvjcost, int *mvcost[2], int *distortion,
|
||||
unsigned int *sse1, const uint8_t *second_pred, const uint8_t *mask,
|
||||
int mask_stride, int invert_mask, int w, int h,
|
||||
int use_accurate_subpel_search) {
|
||||
int use_accurate_subpel_search, const int do_reset_fractional_mv) {
|
||||
SETUP_SUBPEL_SEARCH;
|
||||
(void)use_accurate_subpel_search;
|
||||
(void)cm;
|
||||
(void)mi_row;
|
||||
(void)mi_col;
|
||||
(void)do_reset_fractional_mv;
|
||||
|
||||
besterr = setup_center_error(xd, bestmv, ref_mv, error_per_bit, vfp,
|
||||
src_address, src_stride, y, y_stride,
|
||||
|
|
@ -549,12 +538,13 @@ int av1_find_best_sub_pixel_tree_pruned(
|
|||
int *cost_list, int *mvjcost, int *mvcost[2], int *distortion,
|
||||
unsigned int *sse1, const uint8_t *second_pred, const uint8_t *mask,
|
||||
int mask_stride, int invert_mask, int w, int h,
|
||||
int use_accurate_subpel_search) {
|
||||
int use_accurate_subpel_search, const int do_reset_fractional_mv) {
|
||||
SETUP_SUBPEL_SEARCH;
|
||||
(void)use_accurate_subpel_search;
|
||||
(void)cm;
|
||||
(void)mi_row;
|
||||
(void)mi_col;
|
||||
(void)do_reset_fractional_mv;
|
||||
|
||||
besterr = setup_center_error(xd, bestmv, ref_mv, error_per_bit, vfp,
|
||||
src_address, src_stride, y, y_stride,
|
||||
|
|
@ -651,7 +641,7 @@ static int upsampled_pref_error(MACROBLOCKD *xd, const AV1_COMMON *const cm,
|
|||
int mask_stride, int invert_mask, int w, int h,
|
||||
unsigned int *sse, int subpel_search) {
|
||||
unsigned int besterr;
|
||||
if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) {
|
||||
if (is_cur_buf_hbd(xd)) {
|
||||
DECLARE_ALIGNED(16, uint16_t, pred16[MAX_SB_SQUARE]);
|
||||
uint8_t *pred8 = CONVERT_TO_BYTEPTR(pred16);
|
||||
if (second_pred != NULL) {
|
||||
|
|
@ -661,14 +651,9 @@ static int upsampled_pref_error(MACROBLOCKD *xd, const AV1_COMMON *const cm,
|
|||
subpel_y_q3, y, y_stride, mask, mask_stride, invert_mask, xd->bd,
|
||||
subpel_search);
|
||||
} else {
|
||||
if (xd->jcp_param.use_jnt_comp_avg)
|
||||
aom_highbd_jnt_comp_avg_upsampled_pred(
|
||||
xd, cm, mi_row, mi_col, mv, pred8, second_pred, w, h, subpel_x_q3,
|
||||
subpel_y_q3, y, y_stride, xd->bd, &xd->jcp_param, subpel_search);
|
||||
else
|
||||
aom_highbd_comp_avg_upsampled_pred(
|
||||
xd, cm, mi_row, mi_col, mv, pred8, second_pred, w, h, subpel_x_q3,
|
||||
subpel_y_q3, y, y_stride, xd->bd, subpel_search);
|
||||
aom_highbd_comp_avg_upsampled_pred(
|
||||
xd, cm, mi_row, mi_col, mv, pred8, second_pred, w, h, subpel_x_q3,
|
||||
subpel_y_q3, y, y_stride, xd->bd, subpel_search);
|
||||
}
|
||||
} else {
|
||||
aom_highbd_upsampled_pred(xd, cm, mi_row, mi_col, mv, pred8, w, h,
|
||||
|
|
@ -685,14 +670,9 @@ static int upsampled_pref_error(MACROBLOCKD *xd, const AV1_COMMON *const cm,
|
|||
subpel_y_q3, y, y_stride, mask,
|
||||
mask_stride, invert_mask, subpel_search);
|
||||
} else {
|
||||
if (xd->jcp_param.use_jnt_comp_avg)
|
||||
aom_jnt_comp_avg_upsampled_pred(
|
||||
xd, cm, mi_row, mi_col, mv, pred, second_pred, w, h, subpel_x_q3,
|
||||
subpel_y_q3, y, y_stride, &xd->jcp_param, subpel_search);
|
||||
else
|
||||
aom_comp_avg_upsampled_pred(xd, cm, mi_row, mi_col, mv, pred,
|
||||
second_pred, w, h, subpel_x_q3,
|
||||
subpel_y_q3, y, y_stride, subpel_search);
|
||||
aom_comp_avg_upsampled_pred(xd, cm, mi_row, mi_col, mv, pred,
|
||||
second_pred, w, h, subpel_x_q3, subpel_y_q3,
|
||||
y, y_stride, subpel_search);
|
||||
}
|
||||
} else {
|
||||
aom_upsampled_pred(xd, cm, mi_row, mi_col, mv, pred, w, h, subpel_x_q3,
|
||||
|
|
@ -723,7 +703,7 @@ static unsigned int upsampled_setup_center_error(
|
|||
|
||||
// when use_accurate_subpel_search == 0
|
||||
static INLINE unsigned int estimate_upsampled_pref_error(
|
||||
MACROBLOCKD *xd, const aom_variance_fn_ptr_t *vfp, const uint8_t *const src,
|
||||
const aom_variance_fn_ptr_t *vfp, const uint8_t *const src,
|
||||
const int src_stride, const uint8_t *const pre, int y_stride,
|
||||
int subpel_x_q3, int subpel_y_q3, const uint8_t *second_pred,
|
||||
const uint8_t *mask, int mask_stride, int invert_mask, unsigned int *sse) {
|
||||
|
|
@ -734,12 +714,8 @@ static INLINE unsigned int estimate_upsampled_pref_error(
|
|||
return vfp->msvf(pre, y_stride, subpel_x_q3, subpel_y_q3, src, src_stride,
|
||||
second_pred, mask, mask_stride, invert_mask, sse);
|
||||
} else {
|
||||
if (xd->jcp_param.use_jnt_comp_avg)
|
||||
return vfp->jsvaf(pre, y_stride, subpel_x_q3, subpel_y_q3, src,
|
||||
src_stride, sse, second_pred, &xd->jcp_param);
|
||||
else
|
||||
return vfp->svaf(pre, y_stride, subpel_x_q3, subpel_y_q3, src, src_stride,
|
||||
sse, second_pred);
|
||||
return vfp->svaf(pre, y_stride, subpel_x_q3, subpel_y_q3, src, src_stride,
|
||||
sse, second_pred);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -750,7 +726,7 @@ int av1_find_best_sub_pixel_tree(
|
|||
int *cost_list, int *mvjcost, int *mvcost[2], int *distortion,
|
||||
unsigned int *sse1, const uint8_t *second_pred, const uint8_t *mask,
|
||||
int mask_stride, int invert_mask, int w, int h,
|
||||
int use_accurate_subpel_search) {
|
||||
int use_accurate_subpel_search, const int do_reset_fractional_mv) {
|
||||
const uint8_t *const src_address = x->plane[0].src.buf;
|
||||
const int src_stride = x->plane[0].src.stride;
|
||||
MACROBLOCKD *xd = &x->e_mbd;
|
||||
|
|
@ -796,7 +772,16 @@ int av1_find_best_sub_pixel_tree(
|
|||
|
||||
(void)cost_list; // to silence compiler warning
|
||||
|
||||
if (do_reset_fractional_mv) {
|
||||
av1_set_fractional_mv(x->fractional_best_mv);
|
||||
}
|
||||
|
||||
for (iter = 0; iter < round; ++iter) {
|
||||
if ((x->fractional_best_mv[iter].as_mv.row == br) &&
|
||||
(x->fractional_best_mv[iter].as_mv.col == bc))
|
||||
return INT_MAX;
|
||||
x->fractional_best_mv[iter].as_mv.row = br;
|
||||
x->fractional_best_mv[iter].as_mv.col = bc;
|
||||
// Check vertical and horizontal sub-pixel positions.
|
||||
for (idx = 0; idx < 4; ++idx) {
|
||||
tr = br + search_step[idx].row;
|
||||
|
|
@ -812,9 +797,9 @@ int av1_find_best_sub_pixel_tree(
|
|||
use_accurate_subpel_search);
|
||||
} else {
|
||||
thismse = estimate_upsampled_pref_error(
|
||||
xd, vfp, src_address, src_stride, pre(y, y_stride, tr, tc),
|
||||
y_stride, sp(tc), sp(tr), second_pred, mask, mask_stride,
|
||||
invert_mask, &sse);
|
||||
vfp, src_address, src_stride, pre(y, y_stride, tr, tc), y_stride,
|
||||
sp(tc), sp(tr), second_pred, mask, mask_stride, invert_mask,
|
||||
&sse);
|
||||
}
|
||||
|
||||
cost_array[idx] = thismse + mv_err_cost(&this_mv, ref_mv, mvjcost,
|
||||
|
|
@ -848,9 +833,8 @@ int av1_find_best_sub_pixel_tree(
|
|||
use_accurate_subpel_search);
|
||||
} else {
|
||||
thismse = estimate_upsampled_pref_error(
|
||||
xd, vfp, src_address, src_stride, pre(y, y_stride, tr, tc),
|
||||
y_stride, sp(tc), sp(tr), second_pred, mask, mask_stride,
|
||||
invert_mask, &sse);
|
||||
vfp, src_address, src_stride, pre(y, y_stride, tr, tc), y_stride,
|
||||
sp(tc), sp(tr), second_pred, mask, mask_stride, invert_mask, &sse);
|
||||
}
|
||||
|
||||
cost_array[4] = thismse + mv_err_cost(&this_mv, ref_mv, mvjcost, mvcost,
|
||||
|
|
@ -915,9 +899,10 @@ unsigned int av1_compute_motion_cost(const AV1_COMP *cpi, MACROBLOCK *const x,
|
|||
unsigned int mse;
|
||||
unsigned int sse;
|
||||
|
||||
av1_build_inter_predictors_sby(cm, xd, mi_row, mi_col, NULL, bsize);
|
||||
av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, NULL, bsize,
|
||||
AOM_PLANE_Y, AOM_PLANE_Y);
|
||||
mse = vfp->vf(dst, dst_stride, src, src_stride, &sse);
|
||||
mse += mv_err_cost(this_mv, &ref_mv.as_mv, x->nmvjointcost, x->mvcost,
|
||||
mse += mv_err_cost(this_mv, &ref_mv.as_mv, x->nmv_vec_cost, x->mv_cost_stack,
|
||||
x->errorperbit);
|
||||
return mse;
|
||||
}
|
||||
|
|
@ -1057,8 +1042,8 @@ static INLINE void calc_int_cost_list(const MACROBLOCK *x,
|
|||
cost_list[i + 1] = fn_ptr->vf(what->buf, what->stride,
|
||||
get_buf_from_mv(in_what, &neighbor_mv),
|
||||
in_what->stride, &sse) +
|
||||
mv_err_cost(&neighbor_mv, &fcenter_mv, x->nmvjointcost,
|
||||
x->mvcost, x->errorperbit);
|
||||
mv_err_cost(&neighbor_mv, &fcenter_mv, x->nmv_vec_cost,
|
||||
x->mv_cost_stack, x->errorperbit);
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < 4; i++) {
|
||||
|
|
@ -1070,8 +1055,8 @@ static INLINE void calc_int_cost_list(const MACROBLOCK *x,
|
|||
fn_ptr->vf(what->buf, what->stride,
|
||||
get_buf_from_mv(in_what, &neighbor_mv), in_what->stride,
|
||||
&sse) +
|
||||
mv_err_cost(&neighbor_mv, &fcenter_mv, x->nmvjointcost, x->mvcost,
|
||||
x->errorperbit);
|
||||
mv_err_cost(&neighbor_mv, &fcenter_mv, x->nmv_vec_cost,
|
||||
x->mv_cost_stack, x->errorperbit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1393,8 +1378,8 @@ int av1_get_mvpred_var(const MACROBLOCK *x, const MV *best_mv,
|
|||
|
||||
return vfp->vf(what->buf, what->stride, get_buf_from_mv(in_what, best_mv),
|
||||
in_what->stride, &unused) +
|
||||
(use_mvcost ? mv_err_cost(&mv, center_mv, x->nmvjointcost, x->mvcost,
|
||||
x->errorperbit)
|
||||
(use_mvcost ? mv_err_cost(&mv, center_mv, x->nmv_vec_cost,
|
||||
x->mv_cost_stack, x->errorperbit)
|
||||
: 0);
|
||||
}
|
||||
|
||||
|
|
@ -1407,19 +1392,11 @@ int av1_get_mvpred_av_var(const MACROBLOCK *x, const MV *best_mv,
|
|||
const MV mv = { best_mv->row * 8, best_mv->col * 8 };
|
||||
unsigned int unused;
|
||||
|
||||
if (xd->jcp_param.use_jnt_comp_avg)
|
||||
return vfp->jsvaf(get_buf_from_mv(in_what, best_mv), in_what->stride, 0, 0,
|
||||
what->buf, what->stride, &unused, second_pred,
|
||||
&xd->jcp_param) +
|
||||
(use_mvcost ? mv_err_cost(&mv, center_mv, x->nmvjointcost, x->mvcost,
|
||||
x->errorperbit)
|
||||
: 0);
|
||||
else
|
||||
return vfp->svaf(get_buf_from_mv(in_what, best_mv), in_what->stride, 0, 0,
|
||||
what->buf, what->stride, &unused, second_pred) +
|
||||
(use_mvcost ? mv_err_cost(&mv, center_mv, x->nmvjointcost, x->mvcost,
|
||||
x->errorperbit)
|
||||
: 0);
|
||||
return vfp->svaf(get_buf_from_mv(in_what, best_mv), in_what->stride, 0, 0,
|
||||
what->buf, what->stride, &unused, second_pred) +
|
||||
(use_mvcost ? mv_err_cost(&mv, center_mv, x->nmv_vec_cost,
|
||||
x->mv_cost_stack, x->errorperbit)
|
||||
: 0);
|
||||
}
|
||||
|
||||
int av1_get_mvpred_mask_var(const MACROBLOCK *x, const MV *best_mv,
|
||||
|
|
@ -1436,8 +1413,8 @@ int av1_get_mvpred_mask_var(const MACROBLOCK *x, const MV *best_mv,
|
|||
return vfp->msvf(what->buf, what->stride, 0, 0,
|
||||
get_buf_from_mv(in_what, best_mv), in_what->stride,
|
||||
second_pred, mask, mask_stride, invert_mask, &unused) +
|
||||
(use_mvcost ? mv_err_cost(&mv, center_mv, x->nmvjointcost, x->mvcost,
|
||||
x->errorperbit)
|
||||
(use_mvcost ? mv_err_cost(&mv, center_mv, x->nmv_vec_cost,
|
||||
x->mv_cost_stack, x->errorperbit)
|
||||
: 0);
|
||||
}
|
||||
|
||||
|
|
@ -1897,7 +1874,7 @@ static int full_pixel_exhaustive(const AV1_COMP *const cpi, MACROBLOCK *x,
|
|||
int baseline_interval_divisor;
|
||||
|
||||
// Keep track of number of exhaustive calls (this frame in this thread).
|
||||
++(*x->ex_search_count_ptr);
|
||||
if (x->ex_search_count_ptr != NULL) ++(*x->ex_search_count_ptr);
|
||||
|
||||
// Trap illegal values for interval and range for this function.
|
||||
if ((range < MIN_RANGE) || (range > MAX_RANGE) || (interval < MIN_INTERVAL) ||
|
||||
|
|
@ -2051,16 +2028,10 @@ int av1_refining_search_8p_c(MACROBLOCK *x, int error_per_bit, int search_range,
|
|||
second_pred, mask, mask_stride, invert_mask) +
|
||||
mvsad_err_cost(x, best_mv, &fcenter_mv, error_per_bit);
|
||||
} else {
|
||||
if (xd->jcp_param.use_jnt_comp_avg)
|
||||
best_sad = fn_ptr->jsdaf(what->buf, what->stride,
|
||||
get_buf_from_mv(in_what, best_mv),
|
||||
in_what->stride, second_pred, &xd->jcp_param) +
|
||||
mvsad_err_cost(x, best_mv, &fcenter_mv, error_per_bit);
|
||||
else
|
||||
best_sad = fn_ptr->sdaf(what->buf, what->stride,
|
||||
get_buf_from_mv(in_what, best_mv),
|
||||
in_what->stride, second_pred) +
|
||||
mvsad_err_cost(x, best_mv, &fcenter_mv, error_per_bit);
|
||||
best_sad =
|
||||
fn_ptr->sdaf(what->buf, what->stride, get_buf_from_mv(in_what, best_mv),
|
||||
in_what->stride, second_pred) +
|
||||
mvsad_err_cost(x, best_mv, &fcenter_mv, error_per_bit);
|
||||
}
|
||||
|
||||
do_refine_search_grid[grid_coord] = 1;
|
||||
|
|
@ -2084,14 +2055,9 @@ int av1_refining_search_8p_c(MACROBLOCK *x, int error_per_bit, int search_range,
|
|||
get_buf_from_mv(in_what, &mv), in_what->stride,
|
||||
second_pred, mask, mask_stride, invert_mask);
|
||||
} else {
|
||||
if (xd->jcp_param.use_jnt_comp_avg)
|
||||
sad = fn_ptr->jsdaf(what->buf, what->stride,
|
||||
get_buf_from_mv(in_what, &mv), in_what->stride,
|
||||
second_pred, &xd->jcp_param);
|
||||
else
|
||||
sad = fn_ptr->sdaf(what->buf, what->stride,
|
||||
get_buf_from_mv(in_what, &mv), in_what->stride,
|
||||
second_pred);
|
||||
sad = fn_ptr->sdaf(what->buf, what->stride,
|
||||
get_buf_from_mv(in_what, &mv), in_what->stride,
|
||||
second_pred);
|
||||
}
|
||||
if (sad < best_sad) {
|
||||
sad += mvsad_err_cost(x, &mv, &fcenter_mv, error_per_bit);
|
||||
|
|
@ -2117,13 +2083,16 @@ int av1_refining_search_8p_c(MACROBLOCK *x, int error_per_bit, int search_range,
|
|||
#define MIN_EX_SEARCH_LIMIT 128
|
||||
static int is_exhaustive_allowed(const AV1_COMP *const cpi, MACROBLOCK *x) {
|
||||
const SPEED_FEATURES *const sf = &cpi->sf;
|
||||
const int max_ex =
|
||||
AOMMAX(MIN_EX_SEARCH_LIMIT,
|
||||
(*x->m_search_count_ptr * sf->max_exaustive_pct) / 100);
|
||||
|
||||
return sf->allow_exhaustive_searches &&
|
||||
(sf->exhaustive_searches_thresh < INT_MAX) &&
|
||||
(*x->ex_search_count_ptr <= max_ex) && !cpi->rc.is_src_frame_alt_ref;
|
||||
int is_allowed = sf->allow_exhaustive_searches &&
|
||||
(sf->exhaustive_searches_thresh < INT_MAX) &&
|
||||
!cpi->rc.is_src_frame_alt_ref;
|
||||
if (x->m_search_count_ptr != NULL && x->ex_search_count_ptr != NULL) {
|
||||
const int max_ex =
|
||||
AOMMAX(MIN_EX_SEARCH_LIMIT,
|
||||
(*x->m_search_count_ptr * sf->max_exaustive_pct) / 100);
|
||||
is_allowed = *x->ex_search_count_ptr <= max_ex && is_allowed;
|
||||
}
|
||||
return is_allowed;
|
||||
}
|
||||
|
||||
int av1_full_pixel_search(const AV1_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bsize,
|
||||
|
|
@ -2144,7 +2113,7 @@ int av1_full_pixel_search(const AV1_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bsize,
|
|||
}
|
||||
|
||||
// Keep track of number of searches (this frame in this thread).
|
||||
++(*x->m_search_count_ptr);
|
||||
if (x->m_search_count_ptr != NULL) ++(*x->m_search_count_ptr);
|
||||
|
||||
switch (method) {
|
||||
case FAST_DIAMOND:
|
||||
|
|
@ -2241,13 +2210,12 @@ int av1_full_pixel_search(const AV1_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bsize,
|
|||
|
||||
// for the hashMap
|
||||
hash_table *ref_frame_hash =
|
||||
intra
|
||||
? &cpi->common.cur_frame->hash_table
|
||||
: av1_get_ref_frame_hash_map(cpi, x->e_mbd.mi[0]->ref_frame[0]);
|
||||
intra ? &cpi->common.cur_frame->hash_table
|
||||
: av1_get_ref_frame_hash_map(&cpi->common,
|
||||
x->e_mbd.mi[0]->ref_frame[0]);
|
||||
|
||||
av1_get_block_hash_value(
|
||||
what, what_stride, block_width, &hash_value1, &hash_value2,
|
||||
x->e_mbd.cur_buf->flags & YV12_FLAG_HIGHBITDEPTH, x);
|
||||
av1_get_block_hash_value(what, what_stride, block_width, &hash_value1,
|
||||
&hash_value2, is_cur_buf_hbd(&x->e_mbd), x);
|
||||
|
||||
const int count = av1_hash_table_count(ref_frame_hash, hash_value1);
|
||||
// for intra, at lest one matching can be found, itself.
|
||||
|
|
@ -2333,8 +2301,9 @@ int av1_full_pixel_search(const AV1_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bsize,
|
|||
mask, vfp, z, pre(y, y_stride, r, c), \
|
||||
y_stride, sp(c), sp(r), w, h, &sse, \
|
||||
use_accurate_subpel_search); \
|
||||
if ((v = MVC(r, c) + thismse) < besterr) { \
|
||||
besterr = v; \
|
||||
v = mv_err_cost(&this_mv, ref_mv, mvjcost, mvcost, error_per_bit); \
|
||||
if ((v + thismse) < besterr) { \
|
||||
besterr = v + thismse; \
|
||||
br = r; \
|
||||
bc = c; \
|
||||
*distortion = thismse; \
|
||||
|
|
@ -2365,7 +2334,7 @@ static int upsampled_obmc_pref_error(
|
|||
unsigned int besterr;
|
||||
|
||||
DECLARE_ALIGNED(16, uint8_t, pred[2 * MAX_SB_SQUARE]);
|
||||
if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) {
|
||||
if (is_cur_buf_hbd(xd)) {
|
||||
uint8_t *pred8 = CONVERT_TO_BYTEPTR(pred);
|
||||
aom_highbd_upsampled_pred(xd, cm, mi_row, mi_col, mv, pred8, w, h,
|
||||
subpel_x_q3, subpel_y_q3, y, y_stride, xd->bd,
|
||||
|
|
@ -2568,16 +2537,16 @@ static int get_obmc_mvpred_var(const MACROBLOCK *x, const int32_t *wsrc,
|
|||
|
||||
return vfp->ovf(get_buf_from_mv(in_what, best_mv), in_what->stride, wsrc,
|
||||
mask, &unused) +
|
||||
(use_mvcost ? mv_err_cost(&mv, center_mv, x->nmvjointcost, x->mvcost,
|
||||
x->errorperbit)
|
||||
(use_mvcost ? mv_err_cost(&mv, center_mv, x->nmv_vec_cost,
|
||||
x->mv_cost_stack, x->errorperbit)
|
||||
: 0);
|
||||
}
|
||||
|
||||
int obmc_refining_search_sad(const MACROBLOCK *x, const int32_t *wsrc,
|
||||
const int32_t *mask, MV *ref_mv, int error_per_bit,
|
||||
int search_range,
|
||||
const aom_variance_fn_ptr_t *fn_ptr,
|
||||
const MV *center_mv, int is_second) {
|
||||
static int obmc_refining_search_sad(const MACROBLOCK *x, const int32_t *wsrc,
|
||||
const int32_t *mask, MV *ref_mv,
|
||||
int error_per_bit, int search_range,
|
||||
const aom_variance_fn_ptr_t *fn_ptr,
|
||||
const MV *center_mv, int is_second) {
|
||||
const MV neighbors[4] = { { -1, 0 }, { 0, -1 }, { 0, 1 }, { 1, 0 } };
|
||||
const MACROBLOCKD *const xd = &x->e_mbd;
|
||||
const struct buf_2d *const in_what = &xd->plane[0].pre[is_second];
|
||||
|
|
@ -2616,12 +2585,13 @@ int obmc_refining_search_sad(const MACROBLOCK *x, const int32_t *wsrc,
|
|||
return best_sad;
|
||||
}
|
||||
|
||||
int obmc_diamond_search_sad(const MACROBLOCK *x, const search_site_config *cfg,
|
||||
const int32_t *wsrc, const int32_t *mask,
|
||||
MV *ref_mv, MV *best_mv, int search_param,
|
||||
int sad_per_bit, int *num00,
|
||||
const aom_variance_fn_ptr_t *fn_ptr,
|
||||
const MV *center_mv, int is_second) {
|
||||
static int obmc_diamond_search_sad(const MACROBLOCK *x,
|
||||
const search_site_config *cfg,
|
||||
const int32_t *wsrc, const int32_t *mask,
|
||||
MV *ref_mv, MV *best_mv, int search_param,
|
||||
int sad_per_bit, int *num00,
|
||||
const aom_variance_fn_ptr_t *fn_ptr,
|
||||
const MV *center_mv, int is_second) {
|
||||
const MACROBLOCKD *const xd = &x->e_mbd;
|
||||
const struct buf_2d *const in_what = &xd->plane[0].pre[is_second];
|
||||
// search_param determines the length of the initial step and hence the number
|
||||
|
|
@ -2824,16 +2794,14 @@ int av1_obmc_full_pixel_search(const AV1_COMP *cpi, MACROBLOCK *x, MV *mvp_full,
|
|||
(void)thismse; \
|
||||
(void)cost_list;
|
||||
// Return the maximum MV.
|
||||
int av1_return_max_sub_pixel_mv(MACROBLOCK *x, const AV1_COMMON *const cm,
|
||||
int mi_row, int mi_col, const MV *ref_mv,
|
||||
int allow_hp, int error_per_bit,
|
||||
const aom_variance_fn_ptr_t *vfp,
|
||||
int forced_stop, int iters_per_step,
|
||||
int *cost_list, int *mvjcost, int *mvcost[2],
|
||||
int *distortion, unsigned int *sse1,
|
||||
const uint8_t *second_pred, const uint8_t *mask,
|
||||
int mask_stride, int invert_mask, int w, int h,
|
||||
int use_accurate_subpel_search) {
|
||||
int av1_return_max_sub_pixel_mv(
|
||||
MACROBLOCK *x, const AV1_COMMON *const cm, int mi_row, int mi_col,
|
||||
const MV *ref_mv, int allow_hp, int error_per_bit,
|
||||
const aom_variance_fn_ptr_t *vfp, int forced_stop, int iters_per_step,
|
||||
int *cost_list, int *mvjcost, int *mvcost[2], int *distortion,
|
||||
unsigned int *sse1, const uint8_t *second_pred, const uint8_t *mask,
|
||||
int mask_stride, int invert_mask, int w, int h,
|
||||
int use_accurate_subpel_search, const int do_reset_fractional_mv) {
|
||||
COMMON_MV_TEST;
|
||||
(void)mask;
|
||||
(void)mask_stride;
|
||||
|
|
@ -2844,6 +2812,7 @@ int av1_return_max_sub_pixel_mv(MACROBLOCK *x, const AV1_COMMON *const cm,
|
|||
(void)cm;
|
||||
(void)mi_row;
|
||||
(void)mi_col;
|
||||
(void)do_reset_fractional_mv;
|
||||
|
||||
bestmv->row = maxr;
|
||||
bestmv->col = maxc;
|
||||
|
|
@ -2854,16 +2823,14 @@ int av1_return_max_sub_pixel_mv(MACROBLOCK *x, const AV1_COMMON *const cm,
|
|||
return besterr;
|
||||
}
|
||||
// Return the minimum MV.
|
||||
int av1_return_min_sub_pixel_mv(MACROBLOCK *x, const AV1_COMMON *const cm,
|
||||
int mi_row, int mi_col, const MV *ref_mv,
|
||||
int allow_hp, int error_per_bit,
|
||||
const aom_variance_fn_ptr_t *vfp,
|
||||
int forced_stop, int iters_per_step,
|
||||
int *cost_list, int *mvjcost, int *mvcost[2],
|
||||
int *distortion, unsigned int *sse1,
|
||||
const uint8_t *second_pred, const uint8_t *mask,
|
||||
int mask_stride, int invert_mask, int w, int h,
|
||||
int use_accurate_subpel_search) {
|
||||
int av1_return_min_sub_pixel_mv(
|
||||
MACROBLOCK *x, const AV1_COMMON *const cm, int mi_row, int mi_col,
|
||||
const MV *ref_mv, int allow_hp, int error_per_bit,
|
||||
const aom_variance_fn_ptr_t *vfp, int forced_stop, int iters_per_step,
|
||||
int *cost_list, int *mvjcost, int *mvcost[2], int *distortion,
|
||||
unsigned int *sse1, const uint8_t *second_pred, const uint8_t *mask,
|
||||
int mask_stride, int invert_mask, int w, int h,
|
||||
int use_accurate_subpel_search, const int do_reset_fractional_mv) {
|
||||
COMMON_MV_TEST;
|
||||
(void)maxr;
|
||||
(void)maxc;
|
||||
|
|
@ -2874,6 +2841,7 @@ int av1_return_min_sub_pixel_mv(MACROBLOCK *x, const AV1_COMMON *const cm,
|
|||
(void)cm;
|
||||
(void)mi_row;
|
||||
(void)mi_col;
|
||||
(void)do_reset_fractional_mv;
|
||||
|
||||
bestmv->row = minr;
|
||||
bestmv->col = minc;
|
||||
|
|
|
|||
8
third_party/aom/av1/encoder/mcomp.h
vendored
8
third_party/aom/av1/encoder/mcomp.h
vendored
|
|
@ -103,7 +103,7 @@ typedef int(fractional_mv_step_fp)(
|
|||
int iters_per_step, int *cost_list, int *mvjcost, int *mvcost[2],
|
||||
int *distortion, unsigned int *sse1, const uint8_t *second_pred,
|
||||
const uint8_t *mask, int mask_stride, int invert_mask, int w, int h,
|
||||
int use_accurate_subpel_search);
|
||||
int use_accurate_subpel_search, const int do_reset_fractional_mv);
|
||||
|
||||
extern fractional_mv_step_fp av1_find_best_sub_pixel_tree;
|
||||
extern fractional_mv_step_fp av1_find_best_sub_pixel_tree_pruned;
|
||||
|
|
@ -154,6 +154,12 @@ unsigned int av1_refine_warped_mv(const struct AV1_COMP *cpi,
|
|||
int mi_row, int mi_col, int *pts0,
|
||||
int *pts_inref0, int total_samples);
|
||||
|
||||
static INLINE void av1_set_fractional_mv(int_mv *fractional_best_mv) {
|
||||
for (int z = 0; z < 3; z++) {
|
||||
fractional_best_mv[z].as_int = INVALID_MV;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -267,6 +267,7 @@ static void temporal_filter_apply_16size_msa(uint8_t *frm1_ptr, uint32_t stride,
|
|||
}
|
||||
}
|
||||
|
||||
// TODO(yunqing) The following optimization is not used since c code changes.
|
||||
void av1_temporal_filter_apply_msa(uint8_t *frame1_ptr, uint32_t stride,
|
||||
uint8_t *frame2_ptr, uint32_t blk_w,
|
||||
uint32_t blk_h, int32_t strength,
|
||||
|
|
|
|||
33
third_party/aom/av1/encoder/ml.c
vendored
33
third_party/aom/av1/encoder/ml.c
vendored
|
|
@ -15,31 +15,31 @@
|
|||
#include "aom_dsp/aom_dsp_common.h"
|
||||
#include "av1/encoder/ml.h"
|
||||
|
||||
void av1_nn_predict(const float *features, const NN_CONFIG *nn_config,
|
||||
float *output) {
|
||||
// Calculate prediction based on the given input features and neural net config.
|
||||
// Assume there are no more than NN_MAX_NODES_PER_LAYER nodes in each hidden
|
||||
// layer.
|
||||
void av1_nn_predict_c(const float *input_nodes,
|
||||
const NN_CONFIG *const nn_config, float *const output) {
|
||||
int num_input_nodes = nn_config->num_inputs;
|
||||
int buf_index = 0;
|
||||
float buf[2][NN_MAX_NODES_PER_LAYER];
|
||||
const float *input_nodes = features;
|
||||
|
||||
// Propagate hidden layers.
|
||||
const int num_layers = nn_config->num_hidden_layers;
|
||||
assert(num_layers <= NN_MAX_HIDDEN_LAYERS);
|
||||
for (int layer = 0; layer < num_layers; ++layer) {
|
||||
const float *weights = nn_config->weights[layer];
|
||||
const float *bias = nn_config->bias[layer];
|
||||
const float *layer_weights = nn_config->weights[layer];
|
||||
const float *layer_bias = nn_config->bias[layer];
|
||||
float *output_nodes = buf[buf_index];
|
||||
const int num_output_nodes = nn_config->num_hidden_nodes[layer];
|
||||
assert(num_output_nodes < NN_MAX_NODES_PER_LAYER);
|
||||
for (int node = 0; node < num_output_nodes; ++node) {
|
||||
float val = 0.0f;
|
||||
float val = layer_bias[node];
|
||||
for (int i = 0; i < num_input_nodes; ++i)
|
||||
val += weights[i] * input_nodes[i];
|
||||
val += bias[node];
|
||||
val += layer_weights[node * num_input_nodes + i] * input_nodes[i];
|
||||
// ReLU as activation function.
|
||||
val = val > 0.0f ? val : 0.0f; // Could use AOMMAX().
|
||||
output_nodes[node] = val;
|
||||
weights += num_input_nodes;
|
||||
}
|
||||
num_input_nodes = num_output_nodes;
|
||||
input_nodes = output_nodes;
|
||||
|
|
@ -47,14 +47,13 @@ void av1_nn_predict(const float *features, const NN_CONFIG *nn_config,
|
|||
}
|
||||
|
||||
// Final output layer.
|
||||
const float *weights = nn_config->weights[num_layers];
|
||||
const float *layer_weights = nn_config->weights[num_layers];
|
||||
const float *layer_bias = nn_config->bias[num_layers];
|
||||
for (int node = 0; node < nn_config->num_outputs; ++node) {
|
||||
const float *bias = nn_config->bias[num_layers];
|
||||
float val = 0.0f;
|
||||
float val = layer_bias[node];
|
||||
for (int i = 0; i < num_input_nodes; ++i)
|
||||
val += weights[i] * input_nodes[i];
|
||||
output[node] = val + bias[node];
|
||||
weights += num_input_nodes;
|
||||
val += layer_weights[node * num_input_nodes + i] * input_nodes[i];
|
||||
output[node] = val;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -66,7 +65,9 @@ void av1_nn_softmax(const float *input, float *output, int n) {
|
|||
for (int i = 1; i < n; i++) max_inp = AOMMAX(max_inp, input[i]);
|
||||
float sum_out = 0.0f;
|
||||
for (int i = 0; i < n; i++) {
|
||||
output[i] = (float)exp(input[i] - max_inp);
|
||||
// Clamp to range [-10.0, 0.0] to prevent FE_UNDERFLOW errors.
|
||||
const float normalized_input = AOMMAX(input[i] - max_inp, -10.0f);
|
||||
output[i] = (float)exp(normalized_input);
|
||||
sum_out += output[i];
|
||||
}
|
||||
for (int i = 0; i < n; i++) output[i] /= sum_out;
|
||||
|
|
|
|||
13
third_party/aom/av1/encoder/ml.h
vendored
13
third_party/aom/av1/encoder/ml.h
vendored
|
|
@ -16,10 +16,12 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "config/av1_rtcd.h"
|
||||
|
||||
#define NN_MAX_HIDDEN_LAYERS 10
|
||||
#define NN_MAX_NODES_PER_LAYER 128
|
||||
|
||||
typedef struct {
|
||||
struct NN_CONFIG {
|
||||
int num_inputs; // Number of input nodes, i.e. features.
|
||||
int num_outputs; // Number of output nodes.
|
||||
int num_hidden_layers; // Number of hidden layers, maximum 10.
|
||||
|
|
@ -29,13 +31,8 @@ typedef struct {
|
|||
const float *weights[NN_MAX_HIDDEN_LAYERS + 1];
|
||||
// Bias parameters, indexed by layer.
|
||||
const float *bias[NN_MAX_HIDDEN_LAYERS + 1];
|
||||
} NN_CONFIG;
|
||||
|
||||
// Calculate prediction based on the given input features and neural net config.
|
||||
// Assume there are no more than NN_MAX_NODES_PER_LAYER nodes in each hidden
|
||||
// layer.
|
||||
void av1_nn_predict(const float *features, const NN_CONFIG *nn_config,
|
||||
float *output);
|
||||
};
|
||||
// Typedef from struct NN_CONFIG to NN_CONFIG is in rtcd_defs
|
||||
|
||||
// Applies the softmax normalization function to the input
|
||||
// to get a valid probability distribution in the output:
|
||||
|
|
|
|||
1414
third_party/aom/av1/encoder/partition_model_weights.h
vendored
1414
third_party/aom/av1/encoder/partition_model_weights.h
vendored
File diff suppressed because it is too large
Load diff
31
third_party/aom/av1/encoder/pickcdef.c
vendored
31
third_party/aom/av1/encoder/pickcdef.c
vendored
|
|
@ -281,6 +281,7 @@ uint64_t compute_cdef_dist(uint16_t *dst, int dstride, uint16_t *src,
|
|||
|
||||
void av1_cdef_search(YV12_BUFFER_CONFIG *frame, const YV12_BUFFER_CONFIG *ref,
|
||||
AV1_COMMON *cm, MACROBLOCKD *xd, int fast) {
|
||||
CdefInfo *const cdef_info = &cm->cdef_info;
|
||||
int r, c;
|
||||
int fbr, fbc;
|
||||
uint16_t *src[3];
|
||||
|
|
@ -475,23 +476,23 @@ void av1_cdef_search(YV12_BUFFER_CONFIG *frame, const YV12_BUFFER_CONFIG *ref,
|
|||
best_tot_mse = tot_mse;
|
||||
nb_strength_bits = i;
|
||||
for (j = 0; j < 1 << nb_strength_bits; j++) {
|
||||
cm->cdef_strengths[j] = best_lev0[j];
|
||||
cm->cdef_uv_strengths[j] = best_lev1[j];
|
||||
cdef_info->cdef_strengths[j] = best_lev0[j];
|
||||
cdef_info->cdef_uv_strengths[j] = best_lev1[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
nb_strengths = 1 << nb_strength_bits;
|
||||
|
||||
cm->cdef_bits = nb_strength_bits;
|
||||
cm->nb_cdef_strengths = nb_strengths;
|
||||
cdef_info->cdef_bits = nb_strength_bits;
|
||||
cdef_info->nb_cdef_strengths = nb_strengths;
|
||||
for (i = 0; i < sb_count; i++) {
|
||||
int gi;
|
||||
int best_gi;
|
||||
uint64_t best_mse = (uint64_t)1 << 63;
|
||||
best_gi = 0;
|
||||
for (gi = 0; gi < cm->nb_cdef_strengths; gi++) {
|
||||
uint64_t curr = mse[0][i][cm->cdef_strengths[gi]];
|
||||
if (num_planes >= 3) curr += mse[1][i][cm->cdef_uv_strengths[gi]];
|
||||
for (gi = 0; gi < cdef_info->nb_cdef_strengths; gi++) {
|
||||
uint64_t curr = mse[0][i][cdef_info->cdef_strengths[gi]];
|
||||
if (num_planes >= 3) curr += mse[1][i][cdef_info->cdef_uv_strengths[gi]];
|
||||
if (curr < best_mse) {
|
||||
best_gi = gi;
|
||||
best_mse = curr;
|
||||
|
|
@ -503,18 +504,18 @@ void av1_cdef_search(YV12_BUFFER_CONFIG *frame, const YV12_BUFFER_CONFIG *ref,
|
|||
|
||||
if (fast) {
|
||||
for (int j = 0; j < nb_strengths; j++) {
|
||||
cm->cdef_strengths[j] =
|
||||
priconv[cm->cdef_strengths[j] / CDEF_SEC_STRENGTHS] *
|
||||
cdef_info->cdef_strengths[j] =
|
||||
priconv[cm->cdef_info.cdef_strengths[j] / CDEF_SEC_STRENGTHS] *
|
||||
CDEF_SEC_STRENGTHS +
|
||||
(cm->cdef_strengths[j] % CDEF_SEC_STRENGTHS);
|
||||
cm->cdef_uv_strengths[j] =
|
||||
priconv[cm->cdef_uv_strengths[j] / CDEF_SEC_STRENGTHS] *
|
||||
(cdef_info->cdef_strengths[j] % CDEF_SEC_STRENGTHS);
|
||||
cdef_info->cdef_uv_strengths[j] =
|
||||
priconv[cdef_info->cdef_uv_strengths[j] / CDEF_SEC_STRENGTHS] *
|
||||
CDEF_SEC_STRENGTHS +
|
||||
(cm->cdef_uv_strengths[j] % CDEF_SEC_STRENGTHS);
|
||||
(cdef_info->cdef_uv_strengths[j] % CDEF_SEC_STRENGTHS);
|
||||
}
|
||||
}
|
||||
cm->cdef_pri_damping = pri_damping;
|
||||
cm->cdef_sec_damping = sec_damping;
|
||||
cdef_info->cdef_pri_damping = pri_damping;
|
||||
cdef_info->cdef_sec_damping = sec_damping;
|
||||
aom_free(mse[0]);
|
||||
aom_free(mse[1]);
|
||||
for (pli = 0; pli < num_planes; pli++) {
|
||||
|
|
|
|||
48
third_party/aom/av1/encoder/picklpf.c
vendored
48
third_party/aom/av1/encoder/picklpf.c
vendored
|
|
@ -67,26 +67,27 @@ static int64_t try_filter_frame(const YV12_BUFFER_CONFIG *sd,
|
|||
case 2: cm->lf.filter_level_v = filter_level[0]; break;
|
||||
}
|
||||
|
||||
// TODO(any): please enable multi-thread and remove the flag when loop
|
||||
// filter mask is compatible with multi-thread.
|
||||
#if LOOP_FILTER_BITMASK
|
||||
av1_loop_filter_frame(cm->frame_to_show, cm, &cpi->td.mb.e_mbd, 0, plane,
|
||||
plane + 1, partial_frame);
|
||||
#else
|
||||
// TODO(any): please enable multi-thread and remove the flag when loop
|
||||
// filter mask is compatible with multi-thread.
|
||||
if (cpi->num_workers > 1)
|
||||
av1_loop_filter_frame_mt(cm->frame_to_show, cm, &cpi->td.mb.e_mbd, plane,
|
||||
plane + 1, partial_frame, cpi->workers,
|
||||
cpi->num_workers, &cpi->lf_row_sync);
|
||||
else
|
||||
av1_loop_filter_frame(cm->frame_to_show, cm, &cpi->td.mb.e_mbd, plane,
|
||||
plane + 1, partial_frame);
|
||||
av1_loop_filter_frame_mt(&cm->cur_frame->buf, cm, &cpi->td.mb.e_mbd, plane,
|
||||
plane + 1, partial_frame,
|
||||
#if LOOP_FILTER_BITMASK
|
||||
0,
|
||||
#endif
|
||||
cpi->workers, cpi->num_workers, &cpi->lf_row_sync);
|
||||
else
|
||||
av1_loop_filter_frame(&cm->cur_frame->buf, cm, &cpi->td.mb.e_mbd,
|
||||
#if LOOP_FILTER_BITMASK
|
||||
0,
|
||||
#endif
|
||||
plane, plane + 1, partial_frame);
|
||||
|
||||
filt_err = aom_get_sse_plane(sd, cm->frame_to_show, plane,
|
||||
filt_err = aom_get_sse_plane(sd, &cm->cur_frame->buf, plane,
|
||||
cm->seq_params.use_highbitdepth);
|
||||
|
||||
// Re-instate the unfiltered frame
|
||||
yv12_copy_plane(&cpi->last_frame_uf, cm->frame_to_show, plane);
|
||||
yv12_copy_plane(&cpi->last_frame_uf, &cm->cur_frame->buf, plane);
|
||||
|
||||
return filt_err;
|
||||
}
|
||||
|
|
@ -107,7 +108,17 @@ static int search_filter_level(const YV12_BUFFER_CONFIG *sd, AV1_COMP *cpi,
|
|||
// range.
|
||||
int lvl;
|
||||
switch (plane) {
|
||||
case 0: lvl = last_frame_filter_level[dir]; break;
|
||||
case 0:
|
||||
switch (dir) {
|
||||
case 2:
|
||||
lvl = (last_frame_filter_level[0] + last_frame_filter_level[1] + 1) >>
|
||||
1;
|
||||
break;
|
||||
case 0:
|
||||
case 1: lvl = last_frame_filter_level[dir]; break;
|
||||
default: assert(dir >= 0 && dir <= 2); return 0;
|
||||
}
|
||||
break;
|
||||
case 1: lvl = last_frame_filter_level[2]; break;
|
||||
case 2: lvl = last_frame_filter_level[3]; break;
|
||||
default: assert(plane >= 0 && plane <= 2); return 0;
|
||||
|
|
@ -119,7 +130,7 @@ static int search_filter_level(const YV12_BUFFER_CONFIG *sd, AV1_COMP *cpi,
|
|||
|
||||
// Set each entry to -1
|
||||
memset(ss_err, 0xFF, sizeof(ss_err));
|
||||
yv12_copy_plane(cm->frame_to_show, &cpi->last_frame_uf, plane);
|
||||
yv12_copy_plane(&cm->cur_frame->buf, &cpi->last_frame_uf, plane);
|
||||
best_err = try_filter_frame(sd, cpi, filt_mid, partial_frame, plane, dir);
|
||||
filt_best = filt_mid;
|
||||
ss_err[filt_mid] = best_err;
|
||||
|
|
@ -212,7 +223,7 @@ void av1_pick_filter_level(const YV12_BUFFER_CONFIG *sd, AV1_COMP *cpi,
|
|||
int filt_guess;
|
||||
switch (cm->seq_params.bit_depth) {
|
||||
case AOM_BITS_8:
|
||||
filt_guess = (cm->frame_type == KEY_FRAME)
|
||||
filt_guess = (cm->current_frame.frame_type == KEY_FRAME)
|
||||
? ROUND_POWER_OF_TWO(q * 17563 - 421574, 18)
|
||||
: ROUND_POWER_OF_TWO(q * 6017 + 650707, 18);
|
||||
break;
|
||||
|
|
@ -228,7 +239,8 @@ void av1_pick_filter_level(const YV12_BUFFER_CONFIG *sd, AV1_COMP *cpi,
|
|||
"or AOM_BITS_12");
|
||||
return;
|
||||
}
|
||||
if (cm->seq_params.bit_depth != AOM_BITS_8 && cm->frame_type == KEY_FRAME)
|
||||
if (cm->seq_params.bit_depth != AOM_BITS_8 &&
|
||||
cm->current_frame.frame_type == KEY_FRAME)
|
||||
filt_guess -= 4;
|
||||
// TODO(chengchen): retrain the model for Y, U, V filter levels
|
||||
lf->filter_level[0] = clamp(filt_guess, min_filter_level, max_filter_level);
|
||||
|
|
|
|||
531
third_party/aom/av1/encoder/pickrst.c
vendored
531
third_party/aom/av1/encoder/pickrst.c
vendored
|
|
@ -43,6 +43,9 @@ static const RestorationType force_restore_type = RESTORE_TYPES;
|
|||
// Penalty factor for use of dual sgr
|
||||
#define DUAL_SGR_PENALTY_MULT 0.01
|
||||
|
||||
// Working precision for Wiener filter coefficients
|
||||
#define WIENER_TAP_SCALE_FACTOR ((int64_t)1 << 16)
|
||||
|
||||
const int frame_level_restore_bits[RESTORE_TYPES] = { 2, 2, 2, 2 };
|
||||
|
||||
typedef int64_t (*sse_extractor_type)(const YV12_BUFFER_CONFIG *a,
|
||||
|
|
@ -113,15 +116,11 @@ typedef struct {
|
|||
AV1PixelRect tile_rect;
|
||||
} RestSearchCtxt;
|
||||
|
||||
static void rsc_on_tile(int tile_row, int tile_col, void *priv) {
|
||||
(void)tile_col;
|
||||
|
||||
static void rsc_on_tile(void *priv) {
|
||||
RestSearchCtxt *rsc = (RestSearchCtxt *)priv;
|
||||
set_default_sgrproj(&rsc->sgrproj);
|
||||
set_default_wiener(&rsc->wiener);
|
||||
|
||||
rsc->tile_stripe0 =
|
||||
(tile_row == 0) ? 0 : rsc->cm->rst_end_stripe[tile_row - 1];
|
||||
rsc->tile_stripe0 = 0;
|
||||
}
|
||||
|
||||
static void reset_rsc(RestSearchCtxt *rsc) {
|
||||
|
|
@ -141,7 +140,7 @@ static void init_rsc(const YV12_BUFFER_CONFIG *src, const AV1_COMMON *cm,
|
|||
rsc->rusi = rusi;
|
||||
rsc->sf = sf;
|
||||
|
||||
const YV12_BUFFER_CONFIG *dgd = cm->frame_to_show;
|
||||
const YV12_BUFFER_CONFIG *dgd = &cm->cur_frame->buf;
|
||||
const int is_uv = plane != AOM_PLANE_Y;
|
||||
rsc->plane_width = src->crop_widths[is_uv];
|
||||
rsc->plane_height = src->crop_heights[is_uv];
|
||||
|
|
@ -166,7 +165,7 @@ static int64_t try_restoration_unit(const RestSearchCtxt *rsc,
|
|||
const int bit_depth = cm->seq_params.bit_depth;
|
||||
const int highbd = cm->seq_params.use_highbitdepth;
|
||||
|
||||
const YV12_BUFFER_CONFIG *fts = cm->frame_to_show;
|
||||
const YV12_BUFFER_CONFIG *fts = &cm->cur_frame->buf;
|
||||
// TODO(yunqing): For now, only use optimized LR filter in decoder. Can be
|
||||
// also used in encoder.
|
||||
const int optimized_lr = 0;
|
||||
|
|
@ -201,7 +200,7 @@ int64_t av1_lowbd_pixel_proj_error_c(const uint8_t *src8, int width, int height,
|
|||
v += xq[0] * (flt0[j] - u) + xq[1] * (flt1[j] - u);
|
||||
const int32_t e =
|
||||
ROUND_POWER_OF_TWO(v, SGRPROJ_RST_BITS + SGRPROJ_PRJ_BITS) - src[j];
|
||||
err += e * e;
|
||||
err += ((int64_t)e * e);
|
||||
}
|
||||
dat += dat_stride;
|
||||
src += src_stride;
|
||||
|
|
@ -217,7 +216,7 @@ int64_t av1_lowbd_pixel_proj_error_c(const uint8_t *src8, int width, int height,
|
|||
v += xq[0] * (flt0[j] - u);
|
||||
const int32_t e =
|
||||
ROUND_POWER_OF_TWO(v, SGRPROJ_RST_BITS + SGRPROJ_PRJ_BITS) - src[j];
|
||||
err += e * e;
|
||||
err += ((int64_t)e * e);
|
||||
}
|
||||
dat += dat_stride;
|
||||
src += src_stride;
|
||||
|
|
@ -232,7 +231,7 @@ int64_t av1_lowbd_pixel_proj_error_c(const uint8_t *src8, int width, int height,
|
|||
v += xq[1] * (flt1[j] - u);
|
||||
const int32_t e =
|
||||
ROUND_POWER_OF_TWO(v, SGRPROJ_RST_BITS + SGRPROJ_PRJ_BITS) - src[j];
|
||||
err += e * e;
|
||||
err += ((int64_t)e * e);
|
||||
}
|
||||
dat += dat_stride;
|
||||
src += src_stride;
|
||||
|
|
@ -242,7 +241,7 @@ int64_t av1_lowbd_pixel_proj_error_c(const uint8_t *src8, int width, int height,
|
|||
for (i = 0; i < height; ++i) {
|
||||
for (j = 0; j < width; ++j) {
|
||||
const int32_t e = (int32_t)(dat[j]) - src[j];
|
||||
err += e * e;
|
||||
err += ((int64_t)e * e);
|
||||
}
|
||||
dat += dat_stride;
|
||||
src += src_stride;
|
||||
|
|
@ -252,88 +251,97 @@ int64_t av1_lowbd_pixel_proj_error_c(const uint8_t *src8, int width, int height,
|
|||
return err;
|
||||
}
|
||||
|
||||
int64_t av1_highbd_pixel_proj_error_c(const uint8_t *src8, int width,
|
||||
int height, int src_stride,
|
||||
const uint8_t *dat8, int dat_stride,
|
||||
int32_t *flt0, int flt0_stride,
|
||||
int32_t *flt1, int flt1_stride, int xq[2],
|
||||
const sgr_params_type *params) {
|
||||
const uint16_t *src = CONVERT_TO_SHORTPTR(src8);
|
||||
const uint16_t *dat = CONVERT_TO_SHORTPTR(dat8);
|
||||
int i, j;
|
||||
int64_t err = 0;
|
||||
const int32_t half = 1 << (SGRPROJ_RST_BITS + SGRPROJ_PRJ_BITS - 1);
|
||||
if (params->r[0] > 0 && params->r[1] > 0) {
|
||||
int xq0 = xq[0];
|
||||
int xq1 = xq[1];
|
||||
for (i = 0; i < height; ++i) {
|
||||
for (j = 0; j < width; ++j) {
|
||||
const int32_t d = dat[j];
|
||||
const int32_t s = src[j];
|
||||
const int32_t u = (int32_t)(d << SGRPROJ_RST_BITS);
|
||||
int32_t v0 = flt0[j] - u;
|
||||
int32_t v1 = flt1[j] - u;
|
||||
int32_t v = half;
|
||||
v += xq0 * v0;
|
||||
v += xq1 * v1;
|
||||
const int32_t e = (v >> (SGRPROJ_RST_BITS + SGRPROJ_PRJ_BITS)) + d - s;
|
||||
err += ((int64_t)e * e);
|
||||
}
|
||||
dat += dat_stride;
|
||||
flt0 += flt0_stride;
|
||||
flt1 += flt1_stride;
|
||||
src += src_stride;
|
||||
}
|
||||
} else if (params->r[0] > 0 || params->r[1] > 0) {
|
||||
int exq;
|
||||
int32_t *flt;
|
||||
int flt_stride;
|
||||
if (params->r[0] > 0) {
|
||||
exq = xq[0];
|
||||
flt = flt0;
|
||||
flt_stride = flt0_stride;
|
||||
} else {
|
||||
exq = xq[1];
|
||||
flt = flt1;
|
||||
flt_stride = flt1_stride;
|
||||
}
|
||||
for (i = 0; i < height; ++i) {
|
||||
for (j = 0; j < width; ++j) {
|
||||
const int32_t d = dat[j];
|
||||
const int32_t s = src[j];
|
||||
const int32_t u = (int32_t)(d << SGRPROJ_RST_BITS);
|
||||
int32_t v = half;
|
||||
v += exq * (flt[j] - u);
|
||||
const int32_t e = (v >> (SGRPROJ_RST_BITS + SGRPROJ_PRJ_BITS)) + d - s;
|
||||
err += ((int64_t)e * e);
|
||||
}
|
||||
dat += dat_stride;
|
||||
flt += flt_stride;
|
||||
src += src_stride;
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < height; ++i) {
|
||||
for (j = 0; j < width; ++j) {
|
||||
const int32_t d = dat[j];
|
||||
const int32_t s = src[j];
|
||||
const int32_t e = d - s;
|
||||
err += ((int64_t)e * e);
|
||||
}
|
||||
dat += dat_stride;
|
||||
src += src_stride;
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int64_t get_pixel_proj_error(const uint8_t *src8, int width, int height,
|
||||
int src_stride, const uint8_t *dat8,
|
||||
int dat_stride, int use_highbitdepth,
|
||||
int32_t *flt0, int flt0_stride,
|
||||
int32_t *flt1, int flt1_stride, int *xqd,
|
||||
const sgr_params_type *params) {
|
||||
int i, j;
|
||||
int64_t err = 0;
|
||||
int xq[2];
|
||||
decode_xq(xqd, xq, params);
|
||||
if (!use_highbitdepth) {
|
||||
err = av1_lowbd_pixel_proj_error(src8, width, height, src_stride, dat8,
|
||||
dat_stride, flt0, flt0_stride, flt1,
|
||||
flt1_stride, xq, params);
|
||||
return av1_lowbd_pixel_proj_error(src8, width, height, src_stride, dat8,
|
||||
dat_stride, flt0, flt0_stride, flt1,
|
||||
flt1_stride, xq, params);
|
||||
} else {
|
||||
const uint16_t *src = CONVERT_TO_SHORTPTR(src8);
|
||||
const uint16_t *dat = CONVERT_TO_SHORTPTR(dat8);
|
||||
const int32_t half = 1 << (SGRPROJ_RST_BITS + SGRPROJ_PRJ_BITS - 1);
|
||||
if (params->r[0] > 0 && params->r[1] > 0) {
|
||||
int xq0 = xq[0];
|
||||
int xq1 = xq[1];
|
||||
for (i = 0; i < height; ++i) {
|
||||
for (j = 0; j < width; ++j) {
|
||||
const int32_t d = dat[j];
|
||||
const int32_t s = src[j];
|
||||
const int32_t u = (int32_t)(d << SGRPROJ_RST_BITS);
|
||||
int32_t v0 = flt0[j] - u;
|
||||
int32_t v1 = flt1[j] - u;
|
||||
int32_t v = half;
|
||||
v += xq0 * v0;
|
||||
v += xq1 * v1;
|
||||
const int32_t e =
|
||||
(v >> (SGRPROJ_RST_BITS + SGRPROJ_PRJ_BITS)) + d - s;
|
||||
err += e * e;
|
||||
}
|
||||
dat += dat_stride;
|
||||
flt0 += flt0_stride;
|
||||
flt1 += flt1_stride;
|
||||
src += src_stride;
|
||||
}
|
||||
} else if (params->r[0] > 0 || params->r[1] > 0) {
|
||||
int exq;
|
||||
int32_t *flt;
|
||||
int flt_stride;
|
||||
if (params->r[0] > 0) {
|
||||
exq = xq[0];
|
||||
flt = flt0;
|
||||
flt_stride = flt0_stride;
|
||||
} else {
|
||||
exq = xq[1];
|
||||
flt = flt1;
|
||||
flt_stride = flt1_stride;
|
||||
}
|
||||
for (i = 0; i < height; ++i) {
|
||||
for (j = 0; j < width; ++j) {
|
||||
const int32_t d = dat[j];
|
||||
const int32_t s = src[j];
|
||||
const int32_t u = (int32_t)(d << SGRPROJ_RST_BITS);
|
||||
int32_t v = half;
|
||||
v += exq * (flt[j] - u);
|
||||
const int32_t e =
|
||||
(v >> (SGRPROJ_RST_BITS + SGRPROJ_PRJ_BITS)) + d - s;
|
||||
err += e * e;
|
||||
}
|
||||
dat += dat_stride;
|
||||
flt += flt_stride;
|
||||
src += src_stride;
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < height; ++i) {
|
||||
for (j = 0; j < width; ++j) {
|
||||
const int32_t d = dat[j];
|
||||
const int32_t s = src[j];
|
||||
const int32_t e = d - s;
|
||||
err += e * e;
|
||||
}
|
||||
dat += dat_stride;
|
||||
src += src_stride;
|
||||
}
|
||||
}
|
||||
return av1_highbd_pixel_proj_error(src8, width, height, src_stride, dat8,
|
||||
dat_stride, flt0, flt0_stride, flt1,
|
||||
flt1_stride, xq, params);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
#define USE_SGRPROJ_REFINEMENT_SEARCH 1
|
||||
|
|
@ -398,6 +406,13 @@ static int64_t finer_search_pixel_proj_error(
|
|||
return err;
|
||||
}
|
||||
|
||||
static int64_t signed_rounded_divide(int64_t dividend, int64_t divisor) {
|
||||
if (dividend < 0)
|
||||
return (dividend - divisor / 2) / divisor;
|
||||
else
|
||||
return (dividend + divisor / 2) / divisor;
|
||||
}
|
||||
|
||||
static void get_proj_subspace(const uint8_t *src8, int width, int height,
|
||||
int src_stride, const uint8_t *dat8,
|
||||
int dat_stride, int use_highbitdepth,
|
||||
|
|
@ -405,34 +420,32 @@ static void get_proj_subspace(const uint8_t *src8, int width, int height,
|
|||
int flt1_stride, int *xq,
|
||||
const sgr_params_type *params) {
|
||||
int i, j;
|
||||
double H[2][2] = { { 0, 0 }, { 0, 0 } };
|
||||
double C[2] = { 0, 0 };
|
||||
double Det;
|
||||
double x[2];
|
||||
int64_t H[2][2] = { { 0, 0 }, { 0, 0 } };
|
||||
int64_t C[2] = { 0, 0 };
|
||||
const int size = width * height;
|
||||
|
||||
aom_clear_system_state();
|
||||
|
||||
// Default
|
||||
// Default values to be returned if the problem becomes ill-posed
|
||||
xq[0] = 0;
|
||||
xq[1] = 0;
|
||||
|
||||
if (!use_highbitdepth) {
|
||||
const uint8_t *src = src8;
|
||||
const uint8_t *dat = dat8;
|
||||
for (i = 0; i < height; ++i) {
|
||||
for (j = 0; j < width; ++j) {
|
||||
const double u = (double)(dat[i * dat_stride + j] << SGRPROJ_RST_BITS);
|
||||
const double s =
|
||||
(double)(src[i * src_stride + j] << SGRPROJ_RST_BITS) - u;
|
||||
const double f1 =
|
||||
(params->r[0] > 0) ? (double)flt0[i * flt0_stride + j] - u : 0;
|
||||
const double f2 =
|
||||
(params->r[1] > 0) ? (double)flt1[i * flt1_stride + j] - u : 0;
|
||||
H[0][0] += f1 * f1;
|
||||
H[1][1] += f2 * f2;
|
||||
H[0][1] += f1 * f2;
|
||||
C[0] += f1 * s;
|
||||
C[1] += f2 * s;
|
||||
const int32_t u =
|
||||
(int32_t)(dat[i * dat_stride + j] << SGRPROJ_RST_BITS);
|
||||
const int32_t s =
|
||||
(int32_t)(src[i * src_stride + j] << SGRPROJ_RST_BITS) - u;
|
||||
const int32_t f1 =
|
||||
(params->r[0] > 0) ? (int32_t)flt0[i * flt0_stride + j] - u : 0;
|
||||
const int32_t f2 =
|
||||
(params->r[1] > 0) ? (int32_t)flt1[i * flt1_stride + j] - u : 0;
|
||||
H[0][0] += (int64_t)f1 * f1;
|
||||
H[1][1] += (int64_t)f2 * f2;
|
||||
H[0][1] += (int64_t)f1 * f2;
|
||||
C[0] += (int64_t)f1 * s;
|
||||
C[1] += (int64_t)f2 * s;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
@ -440,18 +453,19 @@ static void get_proj_subspace(const uint8_t *src8, int width, int height,
|
|||
const uint16_t *dat = CONVERT_TO_SHORTPTR(dat8);
|
||||
for (i = 0; i < height; ++i) {
|
||||
for (j = 0; j < width; ++j) {
|
||||
const double u = (double)(dat[i * dat_stride + j] << SGRPROJ_RST_BITS);
|
||||
const double s =
|
||||
(double)(src[i * src_stride + j] << SGRPROJ_RST_BITS) - u;
|
||||
const double f1 =
|
||||
(params->r[0] > 0) ? (double)flt0[i * flt0_stride + j] - u : 0;
|
||||
const double f2 =
|
||||
(params->r[1] > 0) ? (double)flt1[i * flt1_stride + j] - u : 0;
|
||||
H[0][0] += f1 * f1;
|
||||
H[1][1] += f2 * f2;
|
||||
H[0][1] += f1 * f2;
|
||||
C[0] += f1 * s;
|
||||
C[1] += f2 * s;
|
||||
const int32_t u =
|
||||
(int32_t)(dat[i * dat_stride + j] << SGRPROJ_RST_BITS);
|
||||
const int32_t s =
|
||||
(int32_t)(src[i * src_stride + j] << SGRPROJ_RST_BITS) - u;
|
||||
const int32_t f1 =
|
||||
(params->r[0] > 0) ? (int32_t)flt0[i * flt0_stride + j] - u : 0;
|
||||
const int32_t f2 =
|
||||
(params->r[1] > 0) ? (int32_t)flt1[i * flt1_stride + j] - u : 0;
|
||||
H[0][0] += (int64_t)f1 * f1;
|
||||
H[1][1] += (int64_t)f2 * f2;
|
||||
H[0][1] += (int64_t)f1 * f2;
|
||||
C[0] += (int64_t)f1 * s;
|
||||
C[1] += (int64_t)f2 * s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -464,35 +478,39 @@ static void get_proj_subspace(const uint8_t *src8, int width, int height,
|
|||
if (params->r[0] == 0) {
|
||||
// H matrix is now only the scalar H[1][1]
|
||||
// C vector is now only the scalar C[1]
|
||||
Det = H[1][1];
|
||||
if (Det < 1e-8) return; // ill-posed, return default values
|
||||
x[0] = 0;
|
||||
x[1] = C[1] / Det;
|
||||
|
||||
const int64_t Det = H[1][1];
|
||||
if (Det == 0) return; // ill-posed, return default values
|
||||
xq[0] = 0;
|
||||
xq[1] = (int)rint(x[1] * (1 << SGRPROJ_PRJ_BITS));
|
||||
xq[1] = (int)signed_rounded_divide(C[1] * (1 << SGRPROJ_PRJ_BITS), Det);
|
||||
} else if (params->r[1] == 0) {
|
||||
// H matrix is now only the scalar H[0][0]
|
||||
// C vector is now only the scalar C[0]
|
||||
Det = H[0][0];
|
||||
if (Det < 1e-8) return; // ill-posed, return default values
|
||||
x[0] = C[0] / Det;
|
||||
x[1] = 0;
|
||||
|
||||
xq[0] = (int)rint(x[0] * (1 << SGRPROJ_PRJ_BITS));
|
||||
const int64_t Det = H[0][0];
|
||||
if (Det == 0) return; // ill-posed, return default values
|
||||
xq[0] = (int)signed_rounded_divide(C[0] * (1 << SGRPROJ_PRJ_BITS), Det);
|
||||
xq[1] = 0;
|
||||
} else {
|
||||
Det = (H[0][0] * H[1][1] - H[0][1] * H[1][0]);
|
||||
if (Det < 1e-8) return; // ill-posed, return default values
|
||||
x[0] = (H[1][1] * C[0] - H[0][1] * C[1]) / Det;
|
||||
x[1] = (H[0][0] * C[1] - H[1][0] * C[0]) / Det;
|
||||
const int64_t Det = H[0][0] * H[1][1] - H[0][1] * H[1][0];
|
||||
if (Det == 0) return; // ill-posed, return default values
|
||||
|
||||
xq[0] = (int)rint(x[0] * (1 << SGRPROJ_PRJ_BITS));
|
||||
xq[1] = (int)rint(x[1] * (1 << SGRPROJ_PRJ_BITS));
|
||||
// If scaling up dividend would overflow, instead scale down the divisor
|
||||
const int64_t div1 = H[1][1] * C[0] - H[0][1] * C[1];
|
||||
if ((div1 > 0 && INT64_MAX / (1 << SGRPROJ_PRJ_BITS) < div1) ||
|
||||
(div1 < 0 && INT64_MIN / (1 << SGRPROJ_PRJ_BITS) > div1))
|
||||
xq[0] = (int)signed_rounded_divide(div1, Det / (1 << SGRPROJ_PRJ_BITS));
|
||||
else
|
||||
xq[0] = (int)signed_rounded_divide(div1 * (1 << SGRPROJ_PRJ_BITS), Det);
|
||||
|
||||
const int64_t div2 = H[0][0] * C[1] - H[1][0] * C[0];
|
||||
if ((div2 > 0 && INT64_MAX / (1 << SGRPROJ_PRJ_BITS) < div2) ||
|
||||
(div2 < 0 && INT64_MIN / (1 << SGRPROJ_PRJ_BITS) > div2))
|
||||
xq[1] = (int)signed_rounded_divide(div2, Det / (1 << SGRPROJ_PRJ_BITS));
|
||||
else
|
||||
xq[1] = (int)signed_rounded_divide(div2 * (1 << SGRPROJ_PRJ_BITS), Det);
|
||||
}
|
||||
}
|
||||
|
||||
void encode_xq(int *xq, int *xqd, const sgr_params_type *params) {
|
||||
static void encode_xq(int *xq, int *xqd, const sgr_params_type *params) {
|
||||
if (params->r[0] == 0) {
|
||||
xqd[0] = 0;
|
||||
xqd[1] = clamp((1 << SGRPROJ_PRJ_BITS) - xq[1], SGRPROJ_PRJ_MIN1,
|
||||
|
|
@ -651,34 +669,34 @@ static void search_sgrproj(const RestorationTileLimits *limits,
|
|||
|
||||
void av1_compute_stats_c(int wiener_win, const uint8_t *dgd, const uint8_t *src,
|
||||
int h_start, int h_end, int v_start, int v_end,
|
||||
int dgd_stride, int src_stride, double *M, double *H) {
|
||||
int dgd_stride, int src_stride, int64_t *M,
|
||||
int64_t *H) {
|
||||
int i, j, k, l;
|
||||
double Y[WIENER_WIN2];
|
||||
int16_t Y[WIENER_WIN2];
|
||||
const int wiener_win2 = wiener_win * wiener_win;
|
||||
const int wiener_halfwin = (wiener_win >> 1);
|
||||
const double avg =
|
||||
find_average(dgd, h_start, h_end, v_start, v_end, dgd_stride);
|
||||
uint8_t avg = find_average(dgd, h_start, h_end, v_start, v_end, dgd_stride);
|
||||
|
||||
memset(M, 0, sizeof(*M) * wiener_win2);
|
||||
memset(H, 0, sizeof(*H) * wiener_win2 * wiener_win2);
|
||||
for (i = v_start; i < v_end; i++) {
|
||||
for (j = h_start; j < h_end; j++) {
|
||||
const double X = (double)src[i * src_stride + j] - avg;
|
||||
const int16_t X = (int16_t)src[i * src_stride + j] - (int16_t)avg;
|
||||
int idx = 0;
|
||||
for (k = -wiener_halfwin; k <= wiener_halfwin; k++) {
|
||||
for (l = -wiener_halfwin; l <= wiener_halfwin; l++) {
|
||||
Y[idx] = (double)dgd[(i + l) * dgd_stride + (j + k)] - avg;
|
||||
Y[idx] = (int16_t)dgd[(i + l) * dgd_stride + (j + k)] - (int16_t)avg;
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
assert(idx == wiener_win2);
|
||||
for (k = 0; k < wiener_win2; ++k) {
|
||||
M[k] += Y[k] * X;
|
||||
M[k] += (int32_t)Y[k] * X;
|
||||
for (l = k; l < wiener_win2; ++l) {
|
||||
// H is a symmetric matrix, so we only need to fill out the upper
|
||||
// triangle here. We can copy it down to the lower triangle outside
|
||||
// the (i, j) loops.
|
||||
H[k * wiener_win2 + l] += Y[k] * Y[l];
|
||||
H[k * wiener_win2 + l] += (int32_t)Y[k] * Y[l];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -690,60 +708,55 @@ void av1_compute_stats_c(int wiener_win, const uint8_t *dgd, const uint8_t *src,
|
|||
}
|
||||
}
|
||||
|
||||
static double find_average_highbd(const uint16_t *src, int h_start, int h_end,
|
||||
int v_start, int v_end, int stride) {
|
||||
uint64_t sum = 0;
|
||||
double avg = 0;
|
||||
int i, j;
|
||||
aom_clear_system_state();
|
||||
for (i = v_start; i < v_end; i++)
|
||||
for (j = h_start; j < h_end; j++) sum += src[i * stride + j];
|
||||
avg = (double)sum / ((v_end - v_start) * (h_end - h_start));
|
||||
return avg;
|
||||
}
|
||||
|
||||
static AOM_FORCE_INLINE void compute_stats_highbd(
|
||||
int wiener_win, const uint8_t *dgd8, const uint8_t *src8, int h_start,
|
||||
int h_end, int v_start, int v_end, int dgd_stride, int src_stride,
|
||||
double *M, double *H) {
|
||||
void av1_compute_stats_highbd_c(int wiener_win, const uint8_t *dgd8,
|
||||
const uint8_t *src8, int h_start, int h_end,
|
||||
int v_start, int v_end, int dgd_stride,
|
||||
int src_stride, int64_t *M, int64_t *H,
|
||||
aom_bit_depth_t bit_depth) {
|
||||
int i, j, k, l;
|
||||
double Y[WIENER_WIN2];
|
||||
int32_t Y[WIENER_WIN2];
|
||||
const int wiener_win2 = wiener_win * wiener_win;
|
||||
const int wiener_halfwin = (wiener_win >> 1);
|
||||
const uint16_t *src = CONVERT_TO_SHORTPTR(src8);
|
||||
const uint16_t *dgd = CONVERT_TO_SHORTPTR(dgd8);
|
||||
const double avg =
|
||||
uint16_t avg =
|
||||
find_average_highbd(dgd, h_start, h_end, v_start, v_end, dgd_stride);
|
||||
|
||||
uint8_t bit_depth_divider = 1;
|
||||
if (bit_depth == AOM_BITS_12)
|
||||
bit_depth_divider = 16;
|
||||
else if (bit_depth == AOM_BITS_10)
|
||||
bit_depth_divider = 4;
|
||||
|
||||
memset(M, 0, sizeof(*M) * wiener_win2);
|
||||
memset(H, 0, sizeof(*H) * wiener_win2 * wiener_win2);
|
||||
for (i = v_start; i < v_end; i++) {
|
||||
for (j = h_start; j < h_end; j++) {
|
||||
const double X = (double)src[i * src_stride + j] - avg;
|
||||
const int32_t X = (int32_t)src[i * src_stride + j] - (int32_t)avg;
|
||||
int idx = 0;
|
||||
for (k = -wiener_halfwin; k <= wiener_halfwin; k++) {
|
||||
for (l = -wiener_halfwin; l <= wiener_halfwin; l++) {
|
||||
Y[idx] = (double)dgd[(i + l) * dgd_stride + (j + k)] - avg;
|
||||
Y[idx] = (int32_t)dgd[(i + l) * dgd_stride + (j + k)] - (int32_t)avg;
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
assert(idx == wiener_win2);
|
||||
for (k = 0; k < wiener_win2; ++k) {
|
||||
double Yk = Y[k];
|
||||
M[k] += Yk * X;
|
||||
double *H2 = &H[k * wiener_win2];
|
||||
H2[k] += Yk * Yk;
|
||||
for (l = k + 1; l < wiener_win2; ++l) {
|
||||
M[k] += (int64_t)Y[k] * X;
|
||||
for (l = k; l < wiener_win2; ++l) {
|
||||
// H is a symmetric matrix, so we only need to fill out the upper
|
||||
// triangle here. We can copy it down to the lower triangle outside
|
||||
// the (i, j) loops.
|
||||
H2[l] += Yk * Y[l];
|
||||
H[k * wiener_win2 + l] += (int64_t)Y[k] * Y[l];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (k = 0; k < wiener_win2; ++k) {
|
||||
M[k] /= bit_depth_divider;
|
||||
H[k * wiener_win2 + k] /= bit_depth_divider;
|
||||
for (l = k + 1; l < wiener_win2; ++l) {
|
||||
H[k * wiener_win2 + l] /= bit_depth_divider;
|
||||
H[l * wiener_win2 + k] = H[k * wiener_win2 + l];
|
||||
}
|
||||
}
|
||||
|
|
@ -754,12 +767,56 @@ static INLINE int wrap_index(int i, int wiener_win) {
|
|||
return (i >= wiener_halfwin1 ? wiener_win - 1 - i : i);
|
||||
}
|
||||
|
||||
// Solve linear equations to find Wiener filter tap values
|
||||
// Taps are output scaled by WIENER_FILT_STEP
|
||||
static int linsolve_wiener(int n, int64_t *A, int stride, int64_t *b,
|
||||
int32_t *x) {
|
||||
for (int k = 0; k < n - 1; k++) {
|
||||
// Partial pivoting: bring the row with the largest pivot to the top
|
||||
for (int i = n - 1; i > k; i--) {
|
||||
// If row i has a better (bigger) pivot than row (i-1), swap them
|
||||
if (llabs(A[(i - 1) * stride + k]) < llabs(A[i * stride + k])) {
|
||||
for (int j = 0; j < n; j++) {
|
||||
const int64_t c = A[i * stride + j];
|
||||
A[i * stride + j] = A[(i - 1) * stride + j];
|
||||
A[(i - 1) * stride + j] = c;
|
||||
}
|
||||
const int64_t c = b[i];
|
||||
b[i] = b[i - 1];
|
||||
b[i - 1] = c;
|
||||
}
|
||||
}
|
||||
// Forward elimination (convert A to row-echelon form)
|
||||
for (int i = k; i < n - 1; i++) {
|
||||
if (A[k * stride + k] == 0) return 0;
|
||||
const int64_t c = A[(i + 1) * stride + k];
|
||||
const int64_t cd = A[k * stride + k];
|
||||
for (int j = 0; j < n; j++) {
|
||||
A[(i + 1) * stride + j] -= c / 256 * A[k * stride + j] / cd * 256;
|
||||
}
|
||||
b[i + 1] -= c * b[k] / cd;
|
||||
}
|
||||
}
|
||||
// Back-substitution
|
||||
for (int i = n - 1; i >= 0; i--) {
|
||||
if (A[i * stride + i] == 0) return 0;
|
||||
int64_t c = 0;
|
||||
for (int j = i + 1; j <= n - 1; j++) {
|
||||
c += A[i * stride + j] * x[j] / WIENER_TAP_SCALE_FACTOR;
|
||||
}
|
||||
// Store filter taps x in scaled form.
|
||||
x[i] = (int32_t)(WIENER_TAP_SCALE_FACTOR * (b[i] - c) / A[i * stride + i]);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Fix vector b, update vector a
|
||||
static void update_a_sep_sym(int wiener_win, double **Mc, double **Hc,
|
||||
double *a, double *b) {
|
||||
static void update_a_sep_sym(int wiener_win, int64_t **Mc, int64_t **Hc,
|
||||
int32_t *a, int32_t *b) {
|
||||
int i, j;
|
||||
double S[WIENER_WIN];
|
||||
double A[WIENER_HALFWIN1], B[WIENER_HALFWIN1 * WIENER_HALFWIN1];
|
||||
int32_t S[WIENER_WIN];
|
||||
int64_t A[WIENER_HALFWIN1], B[WIENER_HALFWIN1 * WIENER_HALFWIN1];
|
||||
const int wiener_win2 = wiener_win * wiener_win;
|
||||
const int wiener_halfwin1 = (wiener_win >> 1) + 1;
|
||||
memset(A, 0, sizeof(A));
|
||||
|
|
@ -767,36 +824,41 @@ static void update_a_sep_sym(int wiener_win, double **Mc, double **Hc,
|
|||
for (i = 0; i < wiener_win; i++) {
|
||||
for (j = 0; j < wiener_win; ++j) {
|
||||
const int jj = wrap_index(j, wiener_win);
|
||||
A[jj] += Mc[i][j] * b[i];
|
||||
A[jj] += Mc[i][j] * b[i] / WIENER_TAP_SCALE_FACTOR;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < wiener_win; i++) {
|
||||
for (j = 0; j < wiener_win; j++) {
|
||||
int k, l;
|
||||
for (k = 0; k < wiener_win; ++k)
|
||||
for (k = 0; k < wiener_win; ++k) {
|
||||
for (l = 0; l < wiener_win; ++l) {
|
||||
const int kk = wrap_index(k, wiener_win);
|
||||
const int ll = wrap_index(l, wiener_win);
|
||||
B[ll * wiener_halfwin1 + kk] +=
|
||||
Hc[j * wiener_win + i][k * wiener_win2 + l] * b[i] * b[j];
|
||||
Hc[j * wiener_win + i][k * wiener_win2 + l] * b[i] /
|
||||
WIENER_TAP_SCALE_FACTOR * b[j] / WIENER_TAP_SCALE_FACTOR;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Normalization enforcement in the system of equations itself
|
||||
for (i = 0; i < wiener_halfwin1 - 1; ++i)
|
||||
for (i = 0; i < wiener_halfwin1 - 1; ++i) {
|
||||
A[i] -=
|
||||
A[wiener_halfwin1 - 1] * 2 +
|
||||
B[i * wiener_halfwin1 + wiener_halfwin1 - 1] -
|
||||
2 * B[(wiener_halfwin1 - 1) * wiener_halfwin1 + (wiener_halfwin1 - 1)];
|
||||
for (i = 0; i < wiener_halfwin1 - 1; ++i)
|
||||
for (j = 0; j < wiener_halfwin1 - 1; ++j)
|
||||
}
|
||||
for (i = 0; i < wiener_halfwin1 - 1; ++i) {
|
||||
for (j = 0; j < wiener_halfwin1 - 1; ++j) {
|
||||
B[i * wiener_halfwin1 + j] -=
|
||||
2 * (B[i * wiener_halfwin1 + (wiener_halfwin1 - 1)] +
|
||||
B[(wiener_halfwin1 - 1) * wiener_halfwin1 + j] -
|
||||
2 * B[(wiener_halfwin1 - 1) * wiener_halfwin1 +
|
||||
(wiener_halfwin1 - 1)]);
|
||||
if (linsolve(wiener_halfwin1 - 1, B, wiener_halfwin1, A, S)) {
|
||||
S[wiener_halfwin1 - 1] = 1.0;
|
||||
}
|
||||
}
|
||||
if (linsolve_wiener(wiener_halfwin1 - 1, B, wiener_halfwin1, A, S)) {
|
||||
S[wiener_halfwin1 - 1] = WIENER_TAP_SCALE_FACTOR;
|
||||
for (i = wiener_halfwin1; i < wiener_win; ++i) {
|
||||
S[i] = S[wiener_win - 1 - i];
|
||||
S[wiener_halfwin1 - 1] -= 2 * S[i];
|
||||
|
|
@ -806,18 +868,20 @@ static void update_a_sep_sym(int wiener_win, double **Mc, double **Hc,
|
|||
}
|
||||
|
||||
// Fix vector a, update vector b
|
||||
static void update_b_sep_sym(int wiener_win, double **Mc, double **Hc,
|
||||
double *a, double *b) {
|
||||
static void update_b_sep_sym(int wiener_win, int64_t **Mc, int64_t **Hc,
|
||||
int32_t *a, int32_t *b) {
|
||||
int i, j;
|
||||
double S[WIENER_WIN];
|
||||
double A[WIENER_HALFWIN1], B[WIENER_HALFWIN1 * WIENER_HALFWIN1];
|
||||
int32_t S[WIENER_WIN];
|
||||
int64_t A[WIENER_HALFWIN1], B[WIENER_HALFWIN1 * WIENER_HALFWIN1];
|
||||
const int wiener_win2 = wiener_win * wiener_win;
|
||||
const int wiener_halfwin1 = (wiener_win >> 1) + 1;
|
||||
memset(A, 0, sizeof(A));
|
||||
memset(B, 0, sizeof(B));
|
||||
for (i = 0; i < wiener_win; i++) {
|
||||
const int ii = wrap_index(i, wiener_win);
|
||||
for (j = 0; j < wiener_win; j++) A[ii] += Mc[i][j] * a[j];
|
||||
for (j = 0; j < wiener_win; j++) {
|
||||
A[ii] += Mc[i][j] * a[j] / WIENER_TAP_SCALE_FACTOR;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < wiener_win; i++) {
|
||||
|
|
@ -825,27 +889,33 @@ static void update_b_sep_sym(int wiener_win, double **Mc, double **Hc,
|
|||
const int ii = wrap_index(i, wiener_win);
|
||||
const int jj = wrap_index(j, wiener_win);
|
||||
int k, l;
|
||||
for (k = 0; k < wiener_win; ++k)
|
||||
for (l = 0; l < wiener_win; ++l)
|
||||
for (k = 0; k < wiener_win; ++k) {
|
||||
for (l = 0; l < wiener_win; ++l) {
|
||||
B[jj * wiener_halfwin1 + ii] +=
|
||||
Hc[i * wiener_win + j][k * wiener_win2 + l] * a[k] * a[l];
|
||||
Hc[i * wiener_win + j][k * wiener_win2 + l] * a[k] /
|
||||
WIENER_TAP_SCALE_FACTOR * a[l] / WIENER_TAP_SCALE_FACTOR;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Normalization enforcement in the system of equations itself
|
||||
for (i = 0; i < wiener_halfwin1 - 1; ++i)
|
||||
for (i = 0; i < wiener_halfwin1 - 1; ++i) {
|
||||
A[i] -=
|
||||
A[wiener_halfwin1 - 1] * 2 +
|
||||
B[i * wiener_halfwin1 + wiener_halfwin1 - 1] -
|
||||
2 * B[(wiener_halfwin1 - 1) * wiener_halfwin1 + (wiener_halfwin1 - 1)];
|
||||
for (i = 0; i < wiener_halfwin1 - 1; ++i)
|
||||
for (j = 0; j < wiener_halfwin1 - 1; ++j)
|
||||
}
|
||||
for (i = 0; i < wiener_halfwin1 - 1; ++i) {
|
||||
for (j = 0; j < wiener_halfwin1 - 1; ++j) {
|
||||
B[i * wiener_halfwin1 + j] -=
|
||||
2 * (B[i * wiener_halfwin1 + (wiener_halfwin1 - 1)] +
|
||||
B[(wiener_halfwin1 - 1) * wiener_halfwin1 + j] -
|
||||
2 * B[(wiener_halfwin1 - 1) * wiener_halfwin1 +
|
||||
(wiener_halfwin1 - 1)]);
|
||||
if (linsolve(wiener_halfwin1 - 1, B, wiener_halfwin1, A, S)) {
|
||||
S[wiener_halfwin1 - 1] = 1.0;
|
||||
}
|
||||
}
|
||||
if (linsolve_wiener(wiener_halfwin1 - 1, B, wiener_halfwin1, A, S)) {
|
||||
S[wiener_halfwin1 - 1] = WIENER_TAP_SCALE_FACTOR;
|
||||
for (i = wiener_halfwin1; i < wiener_win; ++i) {
|
||||
S[i] = S[wiener_win - 1 - i];
|
||||
S[wiener_halfwin1 - 1] -= 2 * S[i];
|
||||
|
|
@ -854,20 +924,21 @@ static void update_b_sep_sym(int wiener_win, double **Mc, double **Hc,
|
|||
}
|
||||
}
|
||||
|
||||
static int wiener_decompose_sep_sym(int wiener_win, double *M, double *H,
|
||||
double *a, double *b) {
|
||||
static const int init_filt[WIENER_WIN] = {
|
||||
static int wiener_decompose_sep_sym(int wiener_win, int64_t *M, int64_t *H,
|
||||
int32_t *a, int32_t *b) {
|
||||
static const int32_t init_filt[WIENER_WIN] = {
|
||||
WIENER_FILT_TAP0_MIDV, WIENER_FILT_TAP1_MIDV, WIENER_FILT_TAP2_MIDV,
|
||||
WIENER_FILT_TAP3_MIDV, WIENER_FILT_TAP2_MIDV, WIENER_FILT_TAP1_MIDV,
|
||||
WIENER_FILT_TAP0_MIDV,
|
||||
};
|
||||
double *Hc[WIENER_WIN2];
|
||||
double *Mc[WIENER_WIN];
|
||||
int64_t *Hc[WIENER_WIN2];
|
||||
int64_t *Mc[WIENER_WIN];
|
||||
int i, j, iter;
|
||||
const int plane_off = (WIENER_WIN - wiener_win) >> 1;
|
||||
const int wiener_win2 = wiener_win * wiener_win;
|
||||
for (i = 0; i < wiener_win; i++) {
|
||||
a[i] = b[i] = (double)init_filt[i + plane_off] / WIENER_FILT_STEP;
|
||||
a[i] = b[i] =
|
||||
WIENER_TAP_SCALE_FACTOR / WIENER_FILT_STEP * init_filt[i + plane_off];
|
||||
}
|
||||
for (i = 0; i < wiener_win; i++) {
|
||||
Mc[i] = M + i * wiener_win;
|
||||
|
|
@ -889,23 +960,23 @@ static int wiener_decompose_sep_sym(int wiener_win, double *M, double *H,
|
|||
// Computes the function x'*H*x - x'*M for the learned 2D filter x, and compares
|
||||
// against identity filters; Final score is defined as the difference between
|
||||
// the function values
|
||||
static double compute_score(int wiener_win, double *M, double *H,
|
||||
InterpKernel vfilt, InterpKernel hfilt) {
|
||||
double ab[WIENER_WIN * WIENER_WIN];
|
||||
static int64_t compute_score(int wiener_win, int64_t *M, int64_t *H,
|
||||
InterpKernel vfilt, InterpKernel hfilt) {
|
||||
int32_t ab[WIENER_WIN * WIENER_WIN];
|
||||
int16_t a[WIENER_WIN], b[WIENER_WIN];
|
||||
int64_t P = 0, Q = 0;
|
||||
int64_t iP = 0, iQ = 0;
|
||||
int64_t Score, iScore;
|
||||
int i, k, l;
|
||||
double P = 0, Q = 0;
|
||||
double iP = 0, iQ = 0;
|
||||
double Score, iScore;
|
||||
double a[WIENER_WIN], b[WIENER_WIN];
|
||||
const int plane_off = (WIENER_WIN - wiener_win) >> 1;
|
||||
const int wiener_win2 = wiener_win * wiener_win;
|
||||
|
||||
aom_clear_system_state();
|
||||
|
||||
a[WIENER_HALFWIN] = b[WIENER_HALFWIN] = 1.0;
|
||||
a[WIENER_HALFWIN] = b[WIENER_HALFWIN] = WIENER_FILT_STEP;
|
||||
for (i = 0; i < WIENER_HALFWIN; ++i) {
|
||||
a[i] = a[WIENER_WIN - i - 1] = (double)vfilt[i] / WIENER_FILT_STEP;
|
||||
b[i] = b[WIENER_WIN - i - 1] = (double)hfilt[i] / WIENER_FILT_STEP;
|
||||
a[i] = a[WIENER_WIN - i - 1] = vfilt[i];
|
||||
b[i] = b[WIENER_WIN - i - 1] = hfilt[i];
|
||||
a[WIENER_HALFWIN] -= 2 * a[i];
|
||||
b[WIENER_HALFWIN] -= 2 * b[i];
|
||||
}
|
||||
|
|
@ -915,9 +986,11 @@ static double compute_score(int wiener_win, double *M, double *H,
|
|||
ab[k * wiener_win + l] = a[l + plane_off] * b[k + plane_off];
|
||||
}
|
||||
for (k = 0; k < wiener_win2; ++k) {
|
||||
P += ab[k] * M[k];
|
||||
for (l = 0; l < wiener_win2; ++l)
|
||||
Q += ab[k] * H[k * wiener_win2 + l] * ab[l];
|
||||
P += ab[k] * M[k] / WIENER_FILT_STEP / WIENER_FILT_STEP;
|
||||
for (l = 0; l < wiener_win2; ++l) {
|
||||
Q += ab[k] * H[k * wiener_win2 + l] * ab[l] / WIENER_FILT_STEP /
|
||||
WIENER_FILT_STEP / WIENER_FILT_STEP / WIENER_FILT_STEP;
|
||||
}
|
||||
}
|
||||
Score = Q - 2 * P;
|
||||
|
||||
|
|
@ -928,11 +1001,19 @@ static double compute_score(int wiener_win, double *M, double *H,
|
|||
return Score - iScore;
|
||||
}
|
||||
|
||||
static void quantize_sym_filter(int wiener_win, double *f, InterpKernel fi) {
|
||||
static void finalize_sym_filter(int wiener_win, int32_t *f, InterpKernel fi) {
|
||||
int i;
|
||||
const int wiener_halfwin = (wiener_win >> 1);
|
||||
|
||||
for (i = 0; i < wiener_halfwin; ++i) {
|
||||
fi[i] = RINT(f[i] * WIENER_FILT_STEP);
|
||||
const int64_t dividend = f[i] * WIENER_FILT_STEP;
|
||||
const int64_t divisor = WIENER_TAP_SCALE_FACTOR;
|
||||
// Perform this division with proper rounding rather than truncation
|
||||
if (dividend < 0) {
|
||||
fi[i] = (int16_t)((dividend - (divisor / 2)) / divisor);
|
||||
} else {
|
||||
fi[i] = (int16_t)((dividend + (divisor / 2)) / divisor);
|
||||
}
|
||||
}
|
||||
// Specialize for 7-tap filter
|
||||
if (wiener_win == WIENER_WIN) {
|
||||
|
|
@ -1110,15 +1191,16 @@ static void search_wiener(const RestorationTileLimits *limits,
|
|||
const int wiener_win =
|
||||
(rsc->plane == AOM_PLANE_Y) ? WIENER_WIN : WIENER_WIN_CHROMA;
|
||||
|
||||
double M[WIENER_WIN2];
|
||||
double H[WIENER_WIN2 * WIENER_WIN2];
|
||||
double vfilterd[WIENER_WIN], hfilterd[WIENER_WIN];
|
||||
int64_t M[WIENER_WIN2];
|
||||
int64_t H[WIENER_WIN2 * WIENER_WIN2];
|
||||
int32_t vfilter[WIENER_WIN], hfilter[WIENER_WIN];
|
||||
|
||||
const AV1_COMMON *const cm = rsc->cm;
|
||||
if (cm->seq_params.use_highbitdepth) {
|
||||
compute_stats_highbd(wiener_win, rsc->dgd_buffer, rsc->src_buffer,
|
||||
limits->h_start, limits->h_end, limits->v_start,
|
||||
limits->v_end, rsc->dgd_stride, rsc->src_stride, M, H);
|
||||
av1_compute_stats_highbd(wiener_win, rsc->dgd_buffer, rsc->src_buffer,
|
||||
limits->h_start, limits->h_end, limits->v_start,
|
||||
limits->v_end, rsc->dgd_stride, rsc->src_stride, M,
|
||||
H, cm->seq_params.bit_depth);
|
||||
} else {
|
||||
av1_compute_stats(wiener_win, rsc->dgd_buffer, rsc->src_buffer,
|
||||
limits->h_start, limits->h_end, limits->v_start,
|
||||
|
|
@ -1128,7 +1210,7 @@ static void search_wiener(const RestorationTileLimits *limits,
|
|||
const MACROBLOCK *const x = rsc->x;
|
||||
const int64_t bits_none = x->wiener_restore_cost[0];
|
||||
|
||||
if (!wiener_decompose_sep_sym(wiener_win, M, H, vfilterd, hfilterd)) {
|
||||
if (!wiener_decompose_sep_sym(wiener_win, M, H, vfilter, hfilter)) {
|
||||
rsc->bits += bits_none;
|
||||
rsc->sse += rusi->sse[RESTORE_NONE];
|
||||
rusi->best_rtype[RESTORE_WIENER - 1] = RESTORE_NONE;
|
||||
|
|
@ -1139,8 +1221,8 @@ static void search_wiener(const RestorationTileLimits *limits,
|
|||
RestorationUnitInfo rui;
|
||||
memset(&rui, 0, sizeof(rui));
|
||||
rui.restoration_type = RESTORE_WIENER;
|
||||
quantize_sym_filter(wiener_win, vfilterd, rui.wiener_info.vfilter);
|
||||
quantize_sym_filter(wiener_win, hfilterd, rui.wiener_info.hfilter);
|
||||
finalize_sym_filter(wiener_win, vfilter, rui.wiener_info.vfilter);
|
||||
finalize_sym_filter(wiener_win, hfilter, rui.wiener_info.hfilter);
|
||||
|
||||
// Filter score computes the value of the function x'*A*x - x'*b for the
|
||||
// learned filter and compares it against identity filer. If there is no
|
||||
|
|
@ -1199,7 +1281,7 @@ static void search_norestore(const RestorationTileLimits *limits,
|
|||
|
||||
const int highbd = rsc->cm->seq_params.use_highbitdepth;
|
||||
rusi->sse[RESTORE_NONE] = sse_restoration_unit(
|
||||
limits, rsc->src, rsc->cm->frame_to_show, rsc->plane, highbd);
|
||||
limits, rsc->src, &rsc->cm->cur_frame->buf, rsc->plane, highbd);
|
||||
|
||||
rsc->sse += rusi->sse[RESTORE_NONE];
|
||||
}
|
||||
|
|
@ -1283,7 +1365,8 @@ static double search_rest_type(RestSearchCtxt *rsc, RestorationType rtype) {
|
|||
};
|
||||
|
||||
reset_rsc(rsc);
|
||||
rsc_on_tile(LR_TILE_ROW, LR_TILE_COL, rsc);
|
||||
rsc_on_tile(rsc);
|
||||
|
||||
av1_foreach_rest_unit_in_plane(rsc->cm, rsc->plane, funs[rtype], rsc,
|
||||
&rsc->tile_rect, rsc->cm->rst_tmpbuf, NULL);
|
||||
return RDCOST_DBL(rsc->x->rdmult, rsc->bits >> 4, rsc->sse);
|
||||
|
|
|
|||
36
third_party/aom/av1/encoder/pickrst.h
vendored
36
third_party/aom/av1/encoder/pickrst.h
vendored
|
|
@ -25,16 +25,34 @@ static const uint8_t g_shuffle_stats_data[16] = {
|
|||
0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8,
|
||||
};
|
||||
|
||||
static INLINE double find_average(const uint8_t *src, int h_start, int h_end,
|
||||
int v_start, int v_end, int stride) {
|
||||
static const uint8_t g_shuffle_stats_highbd_data[32] = {
|
||||
0, 1, 2, 3, 2, 3, 4, 5, 4, 5, 6, 7, 6, 7, 8, 9,
|
||||
0, 1, 2, 3, 2, 3, 4, 5, 4, 5, 6, 7, 6, 7, 8, 9,
|
||||
};
|
||||
|
||||
static INLINE uint8_t find_average(const uint8_t *src, int h_start, int h_end,
|
||||
int v_start, int v_end, int stride) {
|
||||
uint64_t sum = 0;
|
||||
double avg = 0;
|
||||
int i, j;
|
||||
aom_clear_system_state();
|
||||
for (i = v_start; i < v_end; i++)
|
||||
for (j = h_start; j < h_end; j++) sum += src[i * stride + j];
|
||||
avg = (double)sum / ((v_end - v_start) * (h_end - h_start));
|
||||
return avg;
|
||||
for (int i = v_start; i < v_end; i++) {
|
||||
for (int j = h_start; j < h_end; j++) {
|
||||
sum += src[i * stride + j];
|
||||
}
|
||||
}
|
||||
uint64_t avg = sum / ((v_end - v_start) * (h_end - h_start));
|
||||
return (uint8_t)avg;
|
||||
}
|
||||
|
||||
static INLINE uint16_t find_average_highbd(const uint16_t *src, int h_start,
|
||||
int h_end, int v_start, int v_end,
|
||||
int stride) {
|
||||
uint64_t sum = 0;
|
||||
for (int i = v_start; i < v_end; i++) {
|
||||
for (int j = h_start; j < h_end; j++) {
|
||||
sum += src[i * stride + j];
|
||||
}
|
||||
}
|
||||
uint64_t avg = sum / ((v_end - v_start) * (h_end - h_start));
|
||||
return (uint16_t)avg;
|
||||
}
|
||||
|
||||
void av1_pick_filter_restoration(const YV12_BUFFER_CONFIG *sd, AV1_COMP *cpi);
|
||||
|
|
|
|||
228
third_party/aom/av1/encoder/ransac.c
vendored
228
third_party/aom/av1/encoder/ransac.c
vendored
|
|
@ -23,7 +23,7 @@
|
|||
#define MAX_DEGENERATE_ITER 10
|
||||
#define MINPTS_MULTIPLIER 5
|
||||
|
||||
#define INLIER_THRESHOLD 1.0
|
||||
#define INLIER_THRESHOLD 1.25
|
||||
#define MIN_TRIALS 20
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -376,10 +376,7 @@ static int ransac(const int *matched_points, int npoints,
|
|||
IsDegenerateFunc is_degenerate,
|
||||
FindTransformationFunc find_transformation,
|
||||
ProjectPointsDoubleFunc projectpoints) {
|
||||
static const double PROBABILITY_REQUIRED = 0.9;
|
||||
static const double EPS = 1e-12;
|
||||
|
||||
int N = 10000, trial_count = 0;
|
||||
int trial_count = 0;
|
||||
int i = 0;
|
||||
int ret_val = 0;
|
||||
|
||||
|
|
@ -444,7 +441,7 @@ static int ransac(const int *matched_points, int npoints,
|
|||
*(cnp2++) = *(matched_points++);
|
||||
}
|
||||
|
||||
while (N > trial_count) {
|
||||
while (MIN_TRIALS > trial_count) {
|
||||
double sum_distance = 0.0;
|
||||
double sum_distance_squared = 0.0;
|
||||
|
||||
|
|
@ -491,8 +488,7 @@ static int ransac(const int *matched_points, int npoints,
|
|||
|
||||
if (current_motion.num_inliers >= worst_kept_motion->num_inliers &&
|
||||
current_motion.num_inliers > 1) {
|
||||
int temp;
|
||||
double fracinliers, pNoOutliers, mean_distance, dtemp;
|
||||
double mean_distance;
|
||||
mean_distance = sum_distance / ((double)current_motion.num_inliers);
|
||||
current_motion.variance =
|
||||
sum_distance_squared / ((double)current_motion.num_inliers - 1.0) -
|
||||
|
|
@ -506,21 +502,183 @@ static int ransac(const int *matched_points, int npoints,
|
|||
worst_kept_motion->variance = current_motion.variance;
|
||||
memcpy(worst_kept_motion->inlier_indices, current_motion.inlier_indices,
|
||||
sizeof(*current_motion.inlier_indices) * npoints);
|
||||
|
||||
assert(npoints > 0);
|
||||
fracinliers = (double)current_motion.num_inliers / (double)npoints;
|
||||
pNoOutliers = 1 - pow(fracinliers, minpts);
|
||||
pNoOutliers = fmax(EPS, pNoOutliers);
|
||||
pNoOutliers = fmin(1 - EPS, pNoOutliers);
|
||||
dtemp = log(1.0 - PROBABILITY_REQUIRED) / log(pNoOutliers);
|
||||
temp = (dtemp > (double)INT32_MAX)
|
||||
? INT32_MAX
|
||||
: dtemp < (double)INT32_MIN ? INT32_MIN : (int)dtemp;
|
||||
|
||||
if (temp > 0 && temp < N) {
|
||||
N = AOMMAX(temp, MIN_TRIALS);
|
||||
// Determine the new worst kept motion and its num_inliers and variance.
|
||||
for (i = 0; i < num_desired_motions; ++i) {
|
||||
if (is_better_motion(worst_kept_motion, &motions[i])) {
|
||||
worst_kept_motion = &motions[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
trial_count++;
|
||||
}
|
||||
|
||||
// Sort the motions, best first.
|
||||
qsort(motions, num_desired_motions, sizeof(RANSAC_MOTION), compare_motions);
|
||||
|
||||
// Recompute the motions using only the inliers.
|
||||
for (i = 0; i < num_desired_motions; ++i) {
|
||||
if (motions[i].num_inliers >= minpts) {
|
||||
copy_points_at_indices(points1, corners1, motions[i].inlier_indices,
|
||||
motions[i].num_inliers);
|
||||
copy_points_at_indices(points2, corners2, motions[i].inlier_indices,
|
||||
motions[i].num_inliers);
|
||||
|
||||
find_transformation(motions[i].num_inliers, points1, points2,
|
||||
params_by_motion + (MAX_PARAMDIM - 1) * i);
|
||||
}
|
||||
num_inliers_by_motion[i] = motions[i].num_inliers;
|
||||
}
|
||||
|
||||
finish_ransac:
|
||||
aom_free(points1);
|
||||
aom_free(points2);
|
||||
aom_free(corners1);
|
||||
aom_free(corners2);
|
||||
aom_free(image1_coord);
|
||||
aom_free(current_motion.inlier_indices);
|
||||
for (i = 0; i < num_desired_motions; ++i) {
|
||||
aom_free(motions[i].inlier_indices);
|
||||
}
|
||||
aom_free(motions);
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
static int ransac_double_prec(const double *matched_points, int npoints,
|
||||
int *num_inliers_by_motion,
|
||||
double *params_by_motion, int num_desired_motions,
|
||||
const int minpts, IsDegenerateFunc is_degenerate,
|
||||
FindTransformationFunc find_transformation,
|
||||
ProjectPointsDoubleFunc projectpoints) {
|
||||
int trial_count = 0;
|
||||
int i = 0;
|
||||
int ret_val = 0;
|
||||
|
||||
unsigned int seed = (unsigned int)npoints;
|
||||
|
||||
int indices[MAX_MINPTS] = { 0 };
|
||||
|
||||
double *points1, *points2;
|
||||
double *corners1, *corners2;
|
||||
double *image1_coord;
|
||||
|
||||
// Store information for the num_desired_motions best transformations found
|
||||
// and the worst motion among them, as well as the motion currently under
|
||||
// consideration.
|
||||
RANSAC_MOTION *motions, *worst_kept_motion = NULL;
|
||||
RANSAC_MOTION current_motion;
|
||||
|
||||
// Store the parameters and the indices of the inlier points for the motion
|
||||
// currently under consideration.
|
||||
double params_this_motion[MAX_PARAMDIM];
|
||||
|
||||
double *cnp1, *cnp2;
|
||||
|
||||
for (i = 0; i < num_desired_motions; ++i) {
|
||||
num_inliers_by_motion[i] = 0;
|
||||
}
|
||||
if (npoints < minpts * MINPTS_MULTIPLIER || npoints == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
points1 = (double *)aom_malloc(sizeof(*points1) * npoints * 2);
|
||||
points2 = (double *)aom_malloc(sizeof(*points2) * npoints * 2);
|
||||
corners1 = (double *)aom_malloc(sizeof(*corners1) * npoints * 2);
|
||||
corners2 = (double *)aom_malloc(sizeof(*corners2) * npoints * 2);
|
||||
image1_coord = (double *)aom_malloc(sizeof(*image1_coord) * npoints * 2);
|
||||
|
||||
motions =
|
||||
(RANSAC_MOTION *)aom_malloc(sizeof(RANSAC_MOTION) * num_desired_motions);
|
||||
for (i = 0; i < num_desired_motions; ++i) {
|
||||
motions[i].inlier_indices =
|
||||
(int *)aom_malloc(sizeof(*motions->inlier_indices) * npoints);
|
||||
clear_motion(motions + i, npoints);
|
||||
}
|
||||
current_motion.inlier_indices =
|
||||
(int *)aom_malloc(sizeof(*current_motion.inlier_indices) * npoints);
|
||||
clear_motion(¤t_motion, npoints);
|
||||
|
||||
worst_kept_motion = motions;
|
||||
|
||||
if (!(points1 && points2 && corners1 && corners2 && image1_coord && motions &&
|
||||
current_motion.inlier_indices)) {
|
||||
ret_val = 1;
|
||||
goto finish_ransac;
|
||||
}
|
||||
|
||||
cnp1 = corners1;
|
||||
cnp2 = corners2;
|
||||
for (i = 0; i < npoints; ++i) {
|
||||
*(cnp1++) = *(matched_points++);
|
||||
*(cnp1++) = *(matched_points++);
|
||||
*(cnp2++) = *(matched_points++);
|
||||
*(cnp2++) = *(matched_points++);
|
||||
}
|
||||
|
||||
while (MIN_TRIALS > trial_count) {
|
||||
double sum_distance = 0.0;
|
||||
double sum_distance_squared = 0.0;
|
||||
|
||||
clear_motion(¤t_motion, npoints);
|
||||
|
||||
int degenerate = 1;
|
||||
int num_degenerate_iter = 0;
|
||||
|
||||
while (degenerate) {
|
||||
num_degenerate_iter++;
|
||||
if (!get_rand_indices(npoints, minpts, indices, &seed)) {
|
||||
ret_val = 1;
|
||||
goto finish_ransac;
|
||||
}
|
||||
|
||||
copy_points_at_indices(points1, corners1, indices, minpts);
|
||||
copy_points_at_indices(points2, corners2, indices, minpts);
|
||||
|
||||
degenerate = is_degenerate(points1);
|
||||
if (num_degenerate_iter > MAX_DEGENERATE_ITER) {
|
||||
ret_val = 1;
|
||||
goto finish_ransac;
|
||||
}
|
||||
}
|
||||
|
||||
if (find_transformation(minpts, points1, points2, params_this_motion)) {
|
||||
trial_count++;
|
||||
continue;
|
||||
}
|
||||
|
||||
projectpoints(params_this_motion, corners1, image1_coord, npoints, 2, 2);
|
||||
|
||||
for (i = 0; i < npoints; ++i) {
|
||||
double dx = image1_coord[i * 2] - corners2[i * 2];
|
||||
double dy = image1_coord[i * 2 + 1] - corners2[i * 2 + 1];
|
||||
double distance = sqrt(dx * dx + dy * dy);
|
||||
|
||||
if (distance < INLIER_THRESHOLD) {
|
||||
current_motion.inlier_indices[current_motion.num_inliers++] = i;
|
||||
sum_distance += distance;
|
||||
sum_distance_squared += distance * distance;
|
||||
}
|
||||
}
|
||||
|
||||
if (current_motion.num_inliers >= worst_kept_motion->num_inliers &&
|
||||
current_motion.num_inliers > 1) {
|
||||
double mean_distance;
|
||||
mean_distance = sum_distance / ((double)current_motion.num_inliers);
|
||||
current_motion.variance =
|
||||
sum_distance_squared / ((double)current_motion.num_inliers - 1.0) -
|
||||
mean_distance * mean_distance * ((double)current_motion.num_inliers) /
|
||||
((double)current_motion.num_inliers - 1.0);
|
||||
if (is_better_motion(¤t_motion, worst_kept_motion)) {
|
||||
// This motion is better than the worst currently kept motion. Remember
|
||||
// the inlier points and variance. The parameters for each kept motion
|
||||
// will be recomputed later using only the inliers.
|
||||
worst_kept_motion->num_inliers = current_motion.num_inliers;
|
||||
worst_kept_motion->variance = current_motion.variance;
|
||||
memcpy(worst_kept_motion->inlier_indices, current_motion.inlier_indices,
|
||||
sizeof(*current_motion.inlier_indices) * npoints);
|
||||
assert(npoints > 0);
|
||||
// Determine the new worst kept motion and its num_inliers and variance.
|
||||
for (i = 0; i < num_desired_motions; ++i) {
|
||||
if (is_better_motion(worst_kept_motion, &motions[i])) {
|
||||
|
|
@ -601,3 +759,33 @@ int ransac_affine(int *matched_points, int npoints, int *num_inliers_by_motion,
|
|||
params_by_motion, num_desired_motions, 3, is_degenerate_affine,
|
||||
find_affine, project_points_double_affine);
|
||||
}
|
||||
|
||||
int ransac_translation_double_prec(double *matched_points, int npoints,
|
||||
int *num_inliers_by_motion,
|
||||
double *params_by_motion,
|
||||
int num_desired_motions) {
|
||||
return ransac_double_prec(matched_points, npoints, num_inliers_by_motion,
|
||||
params_by_motion, num_desired_motions, 3,
|
||||
is_degenerate_translation, find_translation,
|
||||
project_points_double_translation);
|
||||
}
|
||||
|
||||
int ransac_rotzoom_double_prec(double *matched_points, int npoints,
|
||||
int *num_inliers_by_motion,
|
||||
double *params_by_motion,
|
||||
int num_desired_motions) {
|
||||
return ransac_double_prec(matched_points, npoints, num_inliers_by_motion,
|
||||
params_by_motion, num_desired_motions, 3,
|
||||
is_degenerate_affine, find_rotzoom,
|
||||
project_points_double_rotzoom);
|
||||
}
|
||||
|
||||
int ransac_affine_double_prec(double *matched_points, int npoints,
|
||||
int *num_inliers_by_motion,
|
||||
double *params_by_motion,
|
||||
int num_desired_motions) {
|
||||
return ransac_double_prec(matched_points, npoints, num_inliers_by_motion,
|
||||
params_by_motion, num_desired_motions, 3,
|
||||
is_degenerate_affine, find_affine,
|
||||
project_points_double_affine);
|
||||
}
|
||||
|
|
|
|||
15
third_party/aom/av1/encoder/ransac.h
vendored
15
third_party/aom/av1/encoder/ransac.h
vendored
|
|
@ -22,6 +22,9 @@
|
|||
typedef int (*RansacFunc)(int *matched_points, int npoints,
|
||||
int *num_inliers_by_motion, double *params_by_motion,
|
||||
int num_motions);
|
||||
typedef int (*RansacFuncDouble)(double *matched_points, int npoints,
|
||||
int *num_inliers_by_motion,
|
||||
double *params_by_motion, int num_motions);
|
||||
|
||||
/* Each of these functions fits a motion model from a set of
|
||||
corresponding points in 2 frames using RANSAC. */
|
||||
|
|
@ -32,4 +35,16 @@ int ransac_rotzoom(int *matched_points, int npoints, int *num_inliers_by_motion,
|
|||
int ransac_translation(int *matched_points, int npoints,
|
||||
int *num_inliers_by_motion, double *params_by_motion,
|
||||
int num_motions);
|
||||
int ransac_translation_double_prec(double *matched_points, int npoints,
|
||||
int *num_inliers_by_motion,
|
||||
double *params_by_motion,
|
||||
int num_desired_motions);
|
||||
int ransac_rotzoom_double_prec(double *matched_points, int npoints,
|
||||
int *num_inliers_by_motion,
|
||||
double *params_by_motion,
|
||||
int num_desired_motions);
|
||||
int ransac_affine_double_prec(double *matched_points, int npoints,
|
||||
int *num_inliers_by_motion,
|
||||
double *params_by_motion,
|
||||
int num_desired_motions);
|
||||
#endif // AOM_AV1_ENCODER_RANSAC_H_
|
||||
|
|
|
|||
283
third_party/aom/av1/encoder/ratectrl.c
vendored
283
third_party/aom/av1/encoder/ratectrl.c
vendored
|
|
@ -29,6 +29,7 @@
|
|||
#include "av1/common/seg_common.h"
|
||||
|
||||
#include "av1/encoder/encodemv.h"
|
||||
#include "av1/encoder/encode_strategy.h"
|
||||
#include "av1/encoder/random.h"
|
||||
#include "av1/encoder/ratectrl.h"
|
||||
|
||||
|
|
@ -250,12 +251,10 @@ int av1_rc_get_default_min_gf_interval(int width, int height,
|
|||
// 4K60: 12
|
||||
}
|
||||
|
||||
int av1_rc_get_default_max_gf_interval(double framerate, int min_gf_interval) {
|
||||
int av1_rc_get_default_max_gf_interval(double framerate, int min_gf_interval,
|
||||
int max_pyr_height) {
|
||||
int interval = AOMMIN(MAX_GF_INTERVAL, (int)(framerate * 0.75));
|
||||
interval += (interval & 0x01); // Round to even value
|
||||
#if CONFIG_FIX_GF_LENGTH
|
||||
interval = AOMMAX(FIXED_GF_LENGTH, interval);
|
||||
#endif
|
||||
interval = AOMMAX(av1_rc_get_fixed_gf_length(max_pyr_height), interval);
|
||||
return AOMMAX(interval, min_gf_interval);
|
||||
}
|
||||
|
||||
|
|
@ -312,7 +311,7 @@ void av1_rc_init(const AV1EncoderConfig *oxcf, int pass, RATE_CONTROL *rc) {
|
|||
oxcf->width, oxcf->height, oxcf->init_framerate);
|
||||
if (rc->max_gf_interval == 0)
|
||||
rc->max_gf_interval = av1_rc_get_default_max_gf_interval(
|
||||
oxcf->init_framerate, rc->min_gf_interval);
|
||||
oxcf->init_framerate, rc->min_gf_interval, oxcf->gf_max_pyr_height);
|
||||
rc->baseline_gf_interval = (rc->min_gf_interval + rc->max_gf_interval) / 2;
|
||||
}
|
||||
|
||||
|
|
@ -357,7 +356,7 @@ static double get_rate_correction_factor(const AV1_COMP *cpi, int width,
|
|||
const RATE_CONTROL *const rc = &cpi->rc;
|
||||
double rcf;
|
||||
|
||||
if (cpi->common.frame_type == KEY_FRAME) {
|
||||
if (cpi->common.current_frame.frame_type == KEY_FRAME) {
|
||||
rcf = rc->rate_correction_factors[KF_STD];
|
||||
} else if (cpi->oxcf.pass == 2) {
|
||||
RATE_FACTOR_LEVEL rf_lvl =
|
||||
|
|
@ -384,7 +383,7 @@ static void set_rate_correction_factor(AV1_COMP *cpi, double factor, int width,
|
|||
|
||||
factor = fclamp(factor, MIN_BPB_FACTOR, MAX_BPB_FACTOR);
|
||||
|
||||
if (cpi->common.frame_type == KEY_FRAME) {
|
||||
if (cpi->common.current_frame.frame_type == KEY_FRAME) {
|
||||
rc->rate_correction_factors[KF_STD] = factor;
|
||||
} else if (cpi->oxcf.pass == 2) {
|
||||
RATE_FACTOR_LEVEL rf_lvl =
|
||||
|
|
@ -425,8 +424,8 @@ void av1_rc_update_rate_correction_factors(AV1_COMP *cpi, int width,
|
|||
av1_cyclic_refresh_estimate_bits_at_q(cpi, rate_correction_factor);
|
||||
} else {
|
||||
projected_size_based_on_q = av1_estimate_bits_at_q(
|
||||
cpi->common.frame_type, cm->base_qindex, MBs, rate_correction_factor,
|
||||
cm->seq_params.bit_depth);
|
||||
cpi->common.current_frame.frame_type, cm->base_qindex, MBs,
|
||||
rate_correction_factor, cm->seq_params.bit_depth);
|
||||
}
|
||||
// Work out a size correction factor.
|
||||
if (projected_size_based_on_q > FRAME_OVERHEAD_BITS)
|
||||
|
|
@ -497,8 +496,9 @@ int av1_rc_regulate_q(const AV1_COMP *cpi, int target_bits_per_frame,
|
|||
bits_per_mb_at_this_q =
|
||||
(int)av1_cyclic_refresh_rc_bits_per_mb(cpi, i, correction_factor);
|
||||
} else {
|
||||
bits_per_mb_at_this_q = (int)av1_rc_bits_per_mb(
|
||||
cm->frame_type, i, correction_factor, cm->seq_params.bit_depth);
|
||||
bits_per_mb_at_this_q =
|
||||
(int)av1_rc_bits_per_mb(cm->current_frame.frame_type, i,
|
||||
correction_factor, cm->seq_params.bit_depth);
|
||||
}
|
||||
|
||||
if (bits_per_mb_at_this_q <= target_bits_per_mb) {
|
||||
|
|
@ -559,20 +559,18 @@ static int get_gf_active_quality(const RATE_CONTROL *const rc, int q,
|
|||
arfgf_low_motion_minq, arfgf_high_motion_minq);
|
||||
}
|
||||
|
||||
#if REDUCE_LAST_ALT_BOOST
|
||||
static int get_gf_high_motion_quality(int q, aom_bit_depth_t bit_depth) {
|
||||
int *arfgf_high_motion_minq;
|
||||
ASSIGN_MINQ_TABLE(bit_depth, arfgf_high_motion_minq);
|
||||
return arfgf_high_motion_minq[q];
|
||||
}
|
||||
#endif
|
||||
|
||||
static int calc_active_worst_quality_one_pass_vbr(const AV1_COMP *cpi) {
|
||||
const RATE_CONTROL *const rc = &cpi->rc;
|
||||
const unsigned int curr_frame = cpi->common.current_video_frame;
|
||||
const unsigned int curr_frame = cpi->common.current_frame.frame_number;
|
||||
int active_worst_quality;
|
||||
|
||||
if (cpi->common.frame_type == KEY_FRAME) {
|
||||
if (cpi->common.current_frame.frame_type == KEY_FRAME) {
|
||||
active_worst_quality =
|
||||
curr_frame == 0 ? rc->worst_quality : rc->last_q[KEY_FRAME] * 2;
|
||||
} else {
|
||||
|
|
@ -604,13 +602,13 @@ static int calc_active_worst_quality_one_pass_cbr(const AV1_COMP *cpi) {
|
|||
int adjustment = 0;
|
||||
int active_worst_quality;
|
||||
int ambient_qp;
|
||||
if (cm->frame_type == KEY_FRAME) return rc->worst_quality;
|
||||
if (cm->current_frame.frame_type == KEY_FRAME) return rc->worst_quality;
|
||||
// For ambient_qp we use minimum of avg_frame_qindex[KEY_FRAME/INTER_FRAME]
|
||||
// for the first few frames following key frame. These are both initialized
|
||||
// to worst_quality and updated with (3/4, 1/4) average in postencode_update.
|
||||
// So for first few frames following key, the qp of that key frame is weighted
|
||||
// into the active_worst_quality setting.
|
||||
ambient_qp = (cm->current_video_frame < 5)
|
||||
ambient_qp = (cm->current_frame.frame_number < 5)
|
||||
? AOMMIN(rc->avg_frame_qindex[INTER_FRAME],
|
||||
rc->avg_frame_qindex[KEY_FRAME])
|
||||
: rc->avg_frame_qindex[INTER_FRAME];
|
||||
|
|
@ -650,6 +648,7 @@ static int rc_pick_q_and_bounds_one_pass_cbr(const AV1_COMP *cpi, int width,
|
|||
int *top_index) {
|
||||
const AV1_COMMON *const cm = &cpi->common;
|
||||
const RATE_CONTROL *const rc = &cpi->rc;
|
||||
const CurrentFrame *const current_frame = &cm->current_frame;
|
||||
int active_best_quality;
|
||||
int active_worst_quality = calc_active_worst_quality_one_pass_cbr(cpi);
|
||||
int q;
|
||||
|
|
@ -668,7 +667,7 @@ static int rc_pick_q_and_bounds_one_pass_cbr(const AV1_COMP *cpi, int width,
|
|||
int delta_qindex = av1_compute_qdelta(rc, last_boosted_q,
|
||||
(last_boosted_q * 0.75), bit_depth);
|
||||
active_best_quality = AOMMAX(qindex + delta_qindex, rc->best_quality);
|
||||
} else if (cm->current_video_frame > 0) {
|
||||
} else if (current_frame->frame_number > 0) {
|
||||
// not first frame of one pass and kf_boost is set
|
||||
double q_adj_factor = 1.0;
|
||||
double q_val;
|
||||
|
|
@ -701,7 +700,7 @@ static int rc_pick_q_and_bounds_one_pass_cbr(const AV1_COMP *cpi, int width,
|
|||
active_best_quality = get_gf_active_quality(rc, q, bit_depth);
|
||||
} else {
|
||||
// Use the lower of active_worst_quality and recent/average Q.
|
||||
if (cm->current_video_frame > 1) {
|
||||
if (current_frame->frame_number > 1) {
|
||||
if (rc->avg_frame_qindex[INTER_FRAME] < active_worst_quality)
|
||||
active_best_quality = rtc_minq[rc->avg_frame_qindex[INTER_FRAME]];
|
||||
else
|
||||
|
|
@ -724,18 +723,18 @@ static int rc_pick_q_and_bounds_one_pass_cbr(const AV1_COMP *cpi, int width,
|
|||
*bottom_index = active_best_quality;
|
||||
|
||||
// Limit Q range for the adaptive loop.
|
||||
if (cm->frame_type == KEY_FRAME && !rc->this_key_frame_forced &&
|
||||
!(cm->current_video_frame == 0)) {
|
||||
if (current_frame->frame_type == KEY_FRAME && !rc->this_key_frame_forced &&
|
||||
!(current_frame->frame_number == 0)) {
|
||||
int qdelta = 0;
|
||||
aom_clear_system_state();
|
||||
qdelta = av1_compute_qdelta_by_rate(&cpi->rc, cm->frame_type,
|
||||
qdelta = av1_compute_qdelta_by_rate(&cpi->rc, current_frame->frame_type,
|
||||
active_worst_quality, 2.0, bit_depth);
|
||||
*top_index = active_worst_quality + qdelta;
|
||||
*top_index = AOMMAX(*top_index, *bottom_index);
|
||||
}
|
||||
|
||||
// Special case code to try and match quality with forced key frames
|
||||
if (cm->frame_type == KEY_FRAME && rc->this_key_frame_forced) {
|
||||
if (current_frame->frame_type == KEY_FRAME && rc->this_key_frame_forced) {
|
||||
q = rc->last_boosted_qindex;
|
||||
} else {
|
||||
q = av1_rc_regulate_q(cpi, rc->this_frame_target, active_best_quality,
|
||||
|
|
@ -756,10 +755,28 @@ static int rc_pick_q_and_bounds_one_pass_cbr(const AV1_COMP *cpi, int width,
|
|||
return q;
|
||||
}
|
||||
|
||||
static int gf_group_pyramid_level(const AV1_COMP *cpi) {
|
||||
const GF_GROUP *gf_group = &cpi->twopass.gf_group;
|
||||
int this_height = gf_group->pyramid_level[gf_group->index];
|
||||
return this_height;
|
||||
}
|
||||
|
||||
static int get_active_cq_level(const RATE_CONTROL *rc,
|
||||
const AV1EncoderConfig *const oxcf) {
|
||||
const AV1EncoderConfig *const oxcf,
|
||||
int intra_only, int superres_denom) {
|
||||
static const double cq_adjust_threshold = 0.1;
|
||||
int active_cq_level = oxcf->cq_level;
|
||||
(void)intra_only;
|
||||
if (oxcf->rc_mode == AOM_CQ || oxcf->rc_mode == AOM_Q) {
|
||||
// printf("Superres %d %d %d = %d\n", superres_denom, intra_only,
|
||||
// rc->frames_to_key, !(intra_only && rc->frames_to_key <= 1));
|
||||
if (oxcf->superres_mode == SUPERRES_QTHRESH &&
|
||||
superres_denom != SCALE_NUMERATOR &&
|
||||
!(intra_only && rc->frames_to_key <= 1)) {
|
||||
active_cq_level =
|
||||
AOMMAX(active_cq_level - ((superres_denom - SCALE_NUMERATOR) * 4), 0);
|
||||
}
|
||||
}
|
||||
if (oxcf->rc_mode == AOM_CQ && rc->total_target_bits > 0) {
|
||||
const double x = (double)rc->total_actual_bits / rc->total_target_bits;
|
||||
if (x < cq_adjust_threshold) {
|
||||
|
|
@ -774,8 +791,10 @@ static int rc_pick_q_and_bounds_one_pass_vbr(const AV1_COMP *cpi, int width,
|
|||
int *top_index) {
|
||||
const AV1_COMMON *const cm = &cpi->common;
|
||||
const RATE_CONTROL *const rc = &cpi->rc;
|
||||
const CurrentFrame *const current_frame = &cm->current_frame;
|
||||
const AV1EncoderConfig *const oxcf = &cpi->oxcf;
|
||||
const int cq_level = get_active_cq_level(rc, oxcf);
|
||||
const int cq_level = get_active_cq_level(rc, oxcf, frame_is_intra_only(cm),
|
||||
cm->superres_scale_denominator);
|
||||
int active_best_quality;
|
||||
int active_worst_quality = calc_active_worst_quality_one_pass_vbr(cpi);
|
||||
int q;
|
||||
|
|
@ -849,12 +868,12 @@ static int rc_pick_q_and_bounds_one_pass_vbr(const AV1_COMP *cpi, int width,
|
|||
0.70, 1.0, 0.85, 1.0 };
|
||||
const int delta_qindex = av1_compute_qdelta(
|
||||
rc, q_val,
|
||||
q_val * delta_rate[cm->current_video_frame % FIXED_GF_INTERVAL],
|
||||
q_val * delta_rate[current_frame->frame_number % FIXED_GF_INTERVAL],
|
||||
bit_depth);
|
||||
active_best_quality = AOMMAX(qindex + delta_qindex, rc->best_quality);
|
||||
} else {
|
||||
// Use the lower of active_worst_quality and recent/average Q.
|
||||
active_best_quality = (cm->current_video_frame > 1)
|
||||
active_best_quality = (current_frame->frame_number > 1)
|
||||
? inter_minq[rc->avg_frame_qindex[INTER_FRAME]]
|
||||
: inter_minq[rc->avg_frame_qindex[KEY_FRAME]];
|
||||
// For the constrained quality mode we don't want
|
||||
|
|
@ -878,14 +897,15 @@ static int rc_pick_q_and_bounds_one_pass_vbr(const AV1_COMP *cpi, int width,
|
|||
{
|
||||
int qdelta = 0;
|
||||
aom_clear_system_state();
|
||||
if (cm->frame_type == KEY_FRAME && !rc->this_key_frame_forced &&
|
||||
!(cm->current_video_frame == 0)) {
|
||||
qdelta = av1_compute_qdelta_by_rate(&cpi->rc, cm->frame_type,
|
||||
if (current_frame->frame_type == KEY_FRAME && !rc->this_key_frame_forced &&
|
||||
!(current_frame->frame_number == 0)) {
|
||||
qdelta = av1_compute_qdelta_by_rate(&cpi->rc, current_frame->frame_type,
|
||||
active_worst_quality, 2.0, bit_depth);
|
||||
} else if (!rc->is_src_frame_alt_ref &&
|
||||
(cpi->refresh_golden_frame || cpi->refresh_alt_ref_frame)) {
|
||||
qdelta = av1_compute_qdelta_by_rate(
|
||||
&cpi->rc, cm->frame_type, active_worst_quality, 1.75, bit_depth);
|
||||
qdelta =
|
||||
av1_compute_qdelta_by_rate(&cpi->rc, current_frame->frame_type,
|
||||
active_worst_quality, 1.75, bit_depth);
|
||||
}
|
||||
*top_index = active_worst_quality + qdelta;
|
||||
*top_index = AOMMAX(*top_index, *bottom_index);
|
||||
|
|
@ -894,7 +914,8 @@ static int rc_pick_q_and_bounds_one_pass_vbr(const AV1_COMP *cpi, int width,
|
|||
if (oxcf->rc_mode == AOM_Q) {
|
||||
q = active_best_quality;
|
||||
// Special case code to try and match quality with forced key frames
|
||||
} else if ((cm->frame_type == KEY_FRAME) && rc->this_key_frame_forced) {
|
||||
} else if ((current_frame->frame_type == KEY_FRAME) &&
|
||||
rc->this_key_frame_forced) {
|
||||
q = rc->last_boosted_qindex;
|
||||
} else {
|
||||
q = av1_rc_regulate_q(cpi, rc->this_frame_target, active_best_quality,
|
||||
|
|
@ -934,7 +955,8 @@ static int rc_pick_q_and_bounds_two_pass(const AV1_COMP *cpi, int width,
|
|||
const RATE_CONTROL *const rc = &cpi->rc;
|
||||
const AV1EncoderConfig *const oxcf = &cpi->oxcf;
|
||||
const GF_GROUP *gf_group = &cpi->twopass.gf_group;
|
||||
const int cq_level = get_active_cq_level(rc, oxcf);
|
||||
const int cq_level = get_active_cq_level(rc, oxcf, frame_is_intra_only(cm),
|
||||
cm->superres_scale_denominator);
|
||||
int active_best_quality;
|
||||
int active_worst_quality = cpi->twopass.active_worst_quality;
|
||||
int q;
|
||||
|
|
@ -942,18 +964,20 @@ static int rc_pick_q_and_bounds_two_pass(const AV1_COMP *cpi, int width,
|
|||
const int bit_depth = cm->seq_params.bit_depth;
|
||||
ASSIGN_MINQ_TABLE(bit_depth, inter_minq);
|
||||
|
||||
#if CUSTOMIZED_GF
|
||||
const int is_intrl_arf_boost =
|
||||
gf_group->update_type[gf_group->index] == INTNL_ARF_UPDATE;
|
||||
#else
|
||||
const int is_intrl_arf_boost = cpi->refresh_alt2_ref_frame;
|
||||
#endif // CUSTOMIZED_GF
|
||||
|
||||
if (frame_is_intra_only(cm)) {
|
||||
// Handle the special case for key frames forced when we have reached
|
||||
// the maximum key frame interval. Here force the Q to a range
|
||||
// based on the ambient Q to reduce the risk of popping.
|
||||
if (rc->this_key_frame_forced) {
|
||||
if (rc->frames_to_key == 1 && oxcf->rc_mode == AOM_Q) {
|
||||
// If the next frame is also a key frame or the current frame is the
|
||||
// only frame in the sequence in AOM_Q mode, just use the cq_level
|
||||
// as q.
|
||||
active_best_quality = cq_level;
|
||||
active_worst_quality = cq_level;
|
||||
} else if (rc->this_key_frame_forced) {
|
||||
// Handle the special case for key frames forced when we have reached
|
||||
// the maximum key frame interval. Here force the Q to a range
|
||||
// based on the ambient Q to reduce the risk of popping.
|
||||
double last_boosted_q;
|
||||
int delta_qindex;
|
||||
int qindex;
|
||||
|
|
@ -967,10 +991,13 @@ static int rc_pick_q_and_bounds_two_pass(const AV1_COMP *cpi, int width,
|
|||
active_worst_quality =
|
||||
AOMMIN(qindex + delta_qindex, active_worst_quality);
|
||||
} else {
|
||||
// Increase the boost if the forced keyframe is a forward reference.
|
||||
// These numbers were derived empirically.
|
||||
const double boost_factor = cpi->oxcf.fwd_kf_enabled ? 0.25 : 0.50;
|
||||
qindex = rc->last_boosted_qindex;
|
||||
last_boosted_q = av1_convert_qindex_to_q(qindex, bit_depth);
|
||||
delta_qindex = av1_compute_qdelta(rc, last_boosted_q,
|
||||
last_boosted_q * 0.5, bit_depth);
|
||||
delta_qindex = av1_compute_qdelta(
|
||||
rc, last_boosted_q, last_boosted_q * boost_factor, bit_depth);
|
||||
active_best_quality = AOMMAX(qindex + delta_qindex, rc->best_quality);
|
||||
}
|
||||
} else {
|
||||
|
|
@ -982,6 +1009,10 @@ static int rc_pick_q_and_bounds_two_pass(const AV1_COMP *cpi, int width,
|
|||
active_best_quality =
|
||||
get_kf_active_quality(rc, active_worst_quality, bit_depth);
|
||||
|
||||
if (cpi->twopass.kf_zeromotion_pct >= STATIC_KF_GROUP_THRESH) {
|
||||
active_best_quality /= 3;
|
||||
}
|
||||
|
||||
// Allow somewhat lower kf minq with small image formats.
|
||||
if ((width * height) <= (352 * 288)) {
|
||||
q_adj_factor -= 0.25;
|
||||
|
|
@ -1011,33 +1042,30 @@ static int rc_pick_q_and_bounds_two_pass(const AV1_COMP *cpi, int width,
|
|||
// For constrained quality dont allow Q less than the cq level
|
||||
if (oxcf->rc_mode == AOM_CQ) {
|
||||
if (q < cq_level) q = cq_level;
|
||||
#if USE_SYMM_MULTI_LAYER && MULTI_LVL_BOOST_VBR_CQ
|
||||
|
||||
active_best_quality = get_gf_active_quality(rc, q, bit_depth);
|
||||
|
||||
// Constrained quality use slightly lower active best.
|
||||
active_best_quality = active_best_quality * 15 / 16;
|
||||
|
||||
if (gf_group->update_type[gf_group->index] == ARF_UPDATE ||
|
||||
(is_intrl_arf_boost && !cpi->new_bwdref_update_rule)) {
|
||||
#endif // USE_SYMM_MULTI_LAYER && MULTI_LVL_BOOST_VBR_CQ
|
||||
active_best_quality = get_gf_active_quality(rc, q, bit_depth);
|
||||
|
||||
// Constrained quality use slightly lower active best.
|
||||
active_best_quality = active_best_quality * 15 / 16;
|
||||
#if REDUCE_LAST_ALT_BOOST
|
||||
if (gf_group->update_type[gf_group->index] == ARF_UPDATE) {
|
||||
const int min_boost = get_gf_high_motion_quality(q, bit_depth);
|
||||
const int boost = min_boost - active_best_quality;
|
||||
|
||||
active_best_quality = min_boost - (int)(boost * rc->arf_boost_factor);
|
||||
}
|
||||
#endif
|
||||
*arf_q = active_best_quality;
|
||||
#if USE_SYMM_MULTI_LAYER && MULTI_LVL_BOOST_VBR_CQ
|
||||
} else {
|
||||
} else if (cpi->new_bwdref_update_rule && is_intrl_arf_boost) {
|
||||
assert(rc->arf_q >= 0); // Ensure it is set to a valid value.
|
||||
active_best_quality = rc->arf_q;
|
||||
int this_height = gf_group->pyramid_level[gf_group->index];
|
||||
int this_height = gf_group_pyramid_level(cpi);
|
||||
while (this_height < gf_group->pyramid_height) {
|
||||
active_best_quality = (active_best_quality + cq_level + 1) / 2;
|
||||
++this_height;
|
||||
}
|
||||
}
|
||||
#endif // USE_SYMM_MULTI_LAYER && MULTI_LVL_BOOST_VBR_CQ
|
||||
} else if (oxcf->rc_mode == AOM_Q) {
|
||||
if (!cpi->refresh_alt_ref_frame && !is_intrl_arf_boost) {
|
||||
active_best_quality = cq_level;
|
||||
|
|
@ -1045,50 +1073,41 @@ static int rc_pick_q_and_bounds_two_pass(const AV1_COMP *cpi, int width,
|
|||
if (gf_group->update_type[gf_group->index] == ARF_UPDATE) {
|
||||
active_best_quality = get_gf_active_quality(rc, q, bit_depth);
|
||||
*arf_q = active_best_quality;
|
||||
#if REDUCE_LAST_ALT_BOOST
|
||||
const int min_boost = get_gf_high_motion_quality(q, bit_depth);
|
||||
const int boost = min_boost - active_best_quality;
|
||||
|
||||
active_best_quality = min_boost - (int)(boost * rc->arf_boost_factor);
|
||||
#endif
|
||||
} else {
|
||||
assert(rc->arf_q >= 0); // Ensure it is set to a valid value.
|
||||
active_best_quality = rc->arf_q;
|
||||
}
|
||||
#if USE_SYMM_MULTI_LAYER
|
||||
if (cpi->new_bwdref_update_rule && is_intrl_arf_boost) {
|
||||
int this_height = gf_group->pyramid_level[gf_group->index];
|
||||
int this_height = gf_group_pyramid_level(cpi);
|
||||
while (this_height < gf_group->pyramid_height) {
|
||||
active_best_quality = (active_best_quality + cq_level + 1) / 2;
|
||||
++this_height;
|
||||
}
|
||||
} else {
|
||||
#endif
|
||||
// Modify best quality for second level arfs. For mode AOM_Q this
|
||||
// becomes the baseline frame q.
|
||||
if (gf_group->rf_level[gf_group->index] == GF_ARF_LOW)
|
||||
active_best_quality = (active_best_quality + cq_level + 1) / 2;
|
||||
#if USE_SYMM_MULTI_LAYER
|
||||
}
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
active_best_quality = get_gf_active_quality(rc, q, bit_depth);
|
||||
#if REDUCE_LAST_ALT_BOOST
|
||||
const int min_boost = get_gf_high_motion_quality(q, bit_depth);
|
||||
const int boost = min_boost - active_best_quality;
|
||||
|
||||
active_best_quality = min_boost - (int)(boost * rc->arf_boost_factor);
|
||||
#endif
|
||||
#if USE_SYMM_MULTI_LAYER
|
||||
if (cpi->new_bwdref_update_rule && is_intrl_arf_boost) {
|
||||
int this_height = gf_group->pyramid_level[gf_group->index];
|
||||
int this_height = gf_group_pyramid_level(cpi);
|
||||
while (this_height < gf_group->pyramid_height) {
|
||||
active_best_quality =
|
||||
(active_best_quality + active_worst_quality + 1) / 2;
|
||||
++this_height;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
if (oxcf->rc_mode == AOM_Q) {
|
||||
|
|
@ -1135,7 +1154,7 @@ static int rc_pick_q_and_bounds_two_pass(const AV1_COMP *cpi, int width,
|
|||
// Modify active_best_quality for downscaled normal frames.
|
||||
if (av1_frame_scaled(cm) && !frame_is_kf_gf_arf(cpi)) {
|
||||
int qdelta = av1_compute_qdelta_by_rate(
|
||||
rc, cm->frame_type, active_best_quality, 2.0, bit_depth);
|
||||
rc, cm->current_frame.frame_type, active_best_quality, 2.0, bit_depth);
|
||||
active_best_quality =
|
||||
AOMMAX(active_best_quality + qdelta, rc->best_quality);
|
||||
}
|
||||
|
|
@ -1145,7 +1164,9 @@ static int rc_pick_q_and_bounds_two_pass(const AV1_COMP *cpi, int width,
|
|||
active_worst_quality =
|
||||
clamp(active_worst_quality, active_best_quality, rc->worst_quality);
|
||||
|
||||
if (oxcf->rc_mode == AOM_Q) {
|
||||
if (oxcf->rc_mode == AOM_Q ||
|
||||
(frame_is_intra_only(cm) && !rc->this_key_frame_forced &&
|
||||
cpi->twopass.kf_zeromotion_pct >= STATIC_KF_GROUP_THRESH)) {
|
||||
q = active_best_quality;
|
||||
// Special case code to try and match quality with forced key frames.
|
||||
} else if (frame_is_intra_only(cm) && rc->this_key_frame_forced) {
|
||||
|
|
@ -1193,7 +1214,7 @@ int av1_rc_pick_q_and_bounds(AV1_COMP *cpi, int width, int height,
|
|||
assert(cpi->oxcf.pass == 2 && "invalid encode pass");
|
||||
|
||||
GF_GROUP *gf_group = &cpi->twopass.gf_group;
|
||||
int arf_q = 0;
|
||||
int arf_q = -1; // Initialize to invalid value, for sanity check later.
|
||||
|
||||
q = rc_pick_q_and_bounds_two_pass(cpi, width, height, bottom_index,
|
||||
top_index, &arf_q);
|
||||
|
|
@ -1253,16 +1274,12 @@ static void update_alt_ref_frame_stats(AV1_COMP *cpi) {
|
|||
|
||||
static void update_golden_frame_stats(AV1_COMP *cpi) {
|
||||
RATE_CONTROL *const rc = &cpi->rc;
|
||||
#if CUSTOMIZED_GF
|
||||
const TWO_PASS *const twopass = &cpi->twopass;
|
||||
const GF_GROUP *const gf_group = &twopass->gf_group;
|
||||
const int is_intrnl_arf =
|
||||
cpi->oxcf.pass == 2
|
||||
? gf_group->update_type[gf_group->index] == INTNL_ARF_UPDATE
|
||||
: cpi->refresh_alt2_ref_frame;
|
||||
#else
|
||||
const int is_intnl_arf = cpi->refresh_alt2_ref_frame;
|
||||
#endif
|
||||
|
||||
// Update the Golden frame usage counts.
|
||||
// NOTE(weitinglin): If we use show_existing_frame for an OVERLAY frame,
|
||||
|
|
@ -1288,19 +1305,42 @@ static void update_golden_frame_stats(AV1_COMP *cpi) {
|
|||
}
|
||||
}
|
||||
|
||||
void av1_estimate_qp_gop(AV1_COMP *cpi) {
|
||||
AV1_COMMON *const cm = &cpi->common;
|
||||
int gop_length = cpi->rc.baseline_gf_interval;
|
||||
int bottom_index, top_index;
|
||||
int idx;
|
||||
const int gf_index = cpi->twopass.gf_group.index;
|
||||
|
||||
for (idx = 1; idx <= gop_length + 1 && idx < MAX_LAG_BUFFERS; ++idx) {
|
||||
TplDepFrame *tpl_frame = &cpi->tpl_stats[idx];
|
||||
int target_rate = cpi->twopass.gf_group.bit_allocation[idx];
|
||||
int arf_q = 0;
|
||||
|
||||
cpi->twopass.gf_group.index = idx;
|
||||
rc_set_frame_target(cpi, target_rate, cm->width, cm->height);
|
||||
av1_configure_buffer_updates(
|
||||
cpi, cpi->twopass.gf_group.update_type[cpi->twopass.gf_group.index]);
|
||||
tpl_frame->base_qindex = rc_pick_q_and_bounds_two_pass(
|
||||
cpi, cm->width, cm->height, &bottom_index, &top_index, &arf_q);
|
||||
tpl_frame->base_qindex = AOMMAX(tpl_frame->base_qindex, 1);
|
||||
}
|
||||
// Reset the actual index and frame update
|
||||
cpi->twopass.gf_group.index = gf_index;
|
||||
av1_configure_buffer_updates(
|
||||
cpi, cpi->twopass.gf_group.update_type[cpi->twopass.gf_group.index]);
|
||||
}
|
||||
|
||||
void av1_rc_postencode_update(AV1_COMP *cpi, uint64_t bytes_used) {
|
||||
const AV1_COMMON *const cm = &cpi->common;
|
||||
const CurrentFrame *const current_frame = &cm->current_frame;
|
||||
RATE_CONTROL *const rc = &cpi->rc;
|
||||
#if CUSTOMIZED_GF
|
||||
const TWO_PASS *const twopass = &cpi->twopass;
|
||||
const GF_GROUP *const gf_group = &twopass->gf_group;
|
||||
const int is_intrnl_arf =
|
||||
cpi->oxcf.pass == 2
|
||||
? gf_group->update_type[gf_group->index] == INTNL_ARF_UPDATE
|
||||
: cpi->refresh_alt2_ref_frame;
|
||||
#else
|
||||
const int is_intrnl_arf = cpi->refresh_alt2_ref_frame;
|
||||
#endif
|
||||
|
||||
const int qindex = cm->base_qindex;
|
||||
|
||||
|
|
@ -1315,7 +1355,7 @@ void av1_rc_postencode_update(AV1_COMP *cpi, uint64_t bytes_used) {
|
|||
av1_rc_update_rate_correction_factors(cpi, cm->width, cm->height);
|
||||
|
||||
// Keep a record of last Q and ambient average Q.
|
||||
if (cm->frame_type == KEY_FRAME) {
|
||||
if (current_frame->frame_type == KEY_FRAME) {
|
||||
rc->last_q[KEY_FRAME] = qindex;
|
||||
rc->avg_frame_qindex[KEY_FRAME] =
|
||||
ROUND_POWER_OF_TWO(3 * rc->avg_frame_qindex[KEY_FRAME] + qindex, 2);
|
||||
|
|
@ -1341,13 +1381,14 @@ void av1_rc_postencode_update(AV1_COMP *cpi, uint64_t bytes_used) {
|
|||
// If all mbs in this group are skipped only update if the Q value is
|
||||
// better than that already stored.
|
||||
// This is used to help set quality in forced key frames to reduce popping
|
||||
if ((qindex < rc->last_boosted_qindex) || (cm->frame_type == KEY_FRAME) ||
|
||||
if ((qindex < rc->last_boosted_qindex) ||
|
||||
(current_frame->frame_type == KEY_FRAME) ||
|
||||
(!rc->constrained_gf_group &&
|
||||
(cpi->refresh_alt_ref_frame || is_intrnl_arf ||
|
||||
(cpi->refresh_golden_frame && !rc->is_src_frame_alt_ref)))) {
|
||||
rc->last_boosted_qindex = qindex;
|
||||
}
|
||||
if (cm->frame_type == KEY_FRAME) rc->last_kf_qindex = qindex;
|
||||
if (current_frame->frame_type == KEY_FRAME) rc->last_kf_qindex = qindex;
|
||||
|
||||
update_buffer_level(cpi, rc->projected_frame_size);
|
||||
|
||||
|
|
@ -1357,7 +1398,7 @@ void av1_rc_postencode_update(AV1_COMP *cpi, uint64_t bytes_used) {
|
|||
rc->this_frame_target =
|
||||
(int)(rc->this_frame_target /
|
||||
resize_rate_factor(cpi, cm->width, cm->height));
|
||||
if (cm->frame_type != KEY_FRAME) {
|
||||
if (current_frame->frame_type != KEY_FRAME) {
|
||||
rc->rolling_target_bits = ROUND_POWER_OF_TWO(
|
||||
rc->rolling_target_bits * 3 + rc->this_frame_target, 2);
|
||||
rc->rolling_actual_bits = ROUND_POWER_OF_TWO(
|
||||
|
|
@ -1378,15 +1419,15 @@ void av1_rc_postencode_update(AV1_COMP *cpi, uint64_t bytes_used) {
|
|||
rc->total_target_vs_actual = rc->total_actual_bits - rc->total_target_bits;
|
||||
|
||||
if (is_altref_enabled(cpi) && cpi->refresh_alt_ref_frame &&
|
||||
(cm->frame_type != KEY_FRAME))
|
||||
(current_frame->frame_type != KEY_FRAME))
|
||||
// Update the alternate reference frame stats as appropriate.
|
||||
update_alt_ref_frame_stats(cpi);
|
||||
else
|
||||
// Update the Golden frame stats as appropriate.
|
||||
update_golden_frame_stats(cpi);
|
||||
|
||||
if (cm->frame_type == KEY_FRAME) rc->frames_since_key = 0;
|
||||
// if (cm->current_video_frame == 1 && cm->show_frame)
|
||||
if (current_frame->frame_type == KEY_FRAME) rc->frames_since_key = 0;
|
||||
// if (current_frame->frame_number == 1 && cm->show_frame)
|
||||
/*
|
||||
rc->this_frame_target =
|
||||
(int)(rc->this_frame_target / resize_rate_factor(cpi, cm->width,
|
||||
|
|
@ -1431,9 +1472,11 @@ static int calc_iframe_target_size_one_pass_vbr(const AV1_COMP *const cpi) {
|
|||
return av1_rc_clamp_iframe_target_size(cpi, target);
|
||||
}
|
||||
|
||||
void av1_rc_get_one_pass_vbr_params(AV1_COMP *cpi) {
|
||||
void av1_rc_get_one_pass_vbr_params(AV1_COMP *cpi,
|
||||
EncodeFrameParams *const frame_params) {
|
||||
AV1_COMMON *const cm = &cpi->common;
|
||||
RATE_CONTROL *const rc = &cpi->rc;
|
||||
CurrentFrame *const current_frame = &cm->current_frame;
|
||||
int target;
|
||||
int altref_enabled = is_altref_enabled(cpi);
|
||||
int sframe_dist = cpi->oxcf.sframe_dist;
|
||||
|
|
@ -1441,44 +1484,44 @@ void av1_rc_get_one_pass_vbr_params(AV1_COMP *cpi) {
|
|||
int sframe_enabled = cpi->oxcf.sframe_enabled;
|
||||
// TODO(yaowu): replace the "auto_key && 0" below with proper decision logic.
|
||||
if (!cpi->refresh_alt_ref_frame &&
|
||||
(cm->current_video_frame == 0 || (cpi->frame_flags & FRAMEFLAGS_KEY) ||
|
||||
rc->frames_to_key == 0 || (cpi->oxcf.auto_key && 0))) {
|
||||
cm->frame_type = KEY_FRAME;
|
||||
(current_frame->frame_number == 0 ||
|
||||
(cpi->frame_flags & FRAMEFLAGS_KEY) || rc->frames_to_key == 0 ||
|
||||
(cpi->oxcf.auto_key && 0))) {
|
||||
frame_params->frame_type = KEY_FRAME;
|
||||
rc->this_key_frame_forced =
|
||||
cm->current_video_frame != 0 && rc->frames_to_key == 0;
|
||||
current_frame->frame_number != 0 && rc->frames_to_key == 0;
|
||||
rc->frames_to_key = cpi->oxcf.key_freq;
|
||||
rc->kf_boost = DEFAULT_KF_BOOST;
|
||||
rc->source_alt_ref_active = 0;
|
||||
} else {
|
||||
cm->frame_type = INTER_FRAME;
|
||||
frame_params->frame_type = INTER_FRAME;
|
||||
if (sframe_enabled) {
|
||||
if (altref_enabled) {
|
||||
if (sframe_mode == 1) {
|
||||
// sframe_mode == 1: insert sframe if it matches altref frame.
|
||||
|
||||
if (cm->current_video_frame % sframe_dist == 0 &&
|
||||
cm->frame_type != KEY_FRAME && cm->current_video_frame != 0 &&
|
||||
cpi->refresh_alt_ref_frame) {
|
||||
cm->frame_type = S_FRAME;
|
||||
if (current_frame->frame_number % sframe_dist == 0 &&
|
||||
current_frame->frame_number != 0 && cpi->refresh_alt_ref_frame) {
|
||||
frame_params->frame_type = S_FRAME;
|
||||
}
|
||||
} else {
|
||||
// sframe_mode != 1: if sframe will be inserted at the next available
|
||||
// altref frame
|
||||
|
||||
if (cm->current_video_frame % sframe_dist == 0 &&
|
||||
cm->frame_type != KEY_FRAME && cm->current_video_frame != 0) {
|
||||
if (current_frame->frame_number % sframe_dist == 0 &&
|
||||
current_frame->frame_number != 0) {
|
||||
rc->sframe_due = 1;
|
||||
}
|
||||
|
||||
if (rc->sframe_due && cpi->refresh_alt_ref_frame) {
|
||||
cm->frame_type = S_FRAME;
|
||||
frame_params->frame_type = S_FRAME;
|
||||
rc->sframe_due = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (cm->current_video_frame % sframe_dist == 0 &&
|
||||
cm->frame_type != KEY_FRAME && cm->current_video_frame != 0) {
|
||||
cm->frame_type = S_FRAME;
|
||||
if (current_frame->frame_number % sframe_dist == 0 &&
|
||||
current_frame->frame_number != 0) {
|
||||
frame_params->frame_type = S_FRAME;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1501,7 +1544,7 @@ void av1_rc_get_one_pass_vbr_params(AV1_COMP *cpi) {
|
|||
if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ)
|
||||
av1_cyclic_refresh_update_parameters(cpi);
|
||||
|
||||
if (cm->frame_type == KEY_FRAME)
|
||||
if (frame_params->frame_type == KEY_FRAME)
|
||||
target = calc_iframe_target_size_one_pass_vbr(cpi);
|
||||
else
|
||||
target = calc_pframe_target_size_one_pass_vbr(cpi);
|
||||
|
|
@ -1550,7 +1593,7 @@ static int calc_pframe_target_size_one_pass_cbr(const AV1_COMP *cpi) {
|
|||
static int calc_iframe_target_size_one_pass_cbr(const AV1_COMP *cpi) {
|
||||
const RATE_CONTROL *rc = &cpi->rc;
|
||||
int target;
|
||||
if (cpi->common.current_video_frame == 0) {
|
||||
if (cpi->common.current_frame.frame_number == 0) {
|
||||
target = ((rc->starting_buffer_level / 2) > INT_MAX)
|
||||
? INT_MAX
|
||||
: (int)(rc->starting_buffer_level / 2);
|
||||
|
|
@ -1567,21 +1610,24 @@ static int calc_iframe_target_size_one_pass_cbr(const AV1_COMP *cpi) {
|
|||
return av1_rc_clamp_iframe_target_size(cpi, target);
|
||||
}
|
||||
|
||||
void av1_rc_get_one_pass_cbr_params(AV1_COMP *cpi) {
|
||||
void av1_rc_get_one_pass_cbr_params(AV1_COMP *cpi,
|
||||
EncodeFrameParams *const frame_params) {
|
||||
AV1_COMMON *const cm = &cpi->common;
|
||||
RATE_CONTROL *const rc = &cpi->rc;
|
||||
CurrentFrame *const current_frame = &cm->current_frame;
|
||||
int target;
|
||||
// TODO(yaowu): replace the "auto_key && 0" below with proper decision logic.
|
||||
if ((cm->current_video_frame == 0 || (cpi->frame_flags & FRAMEFLAGS_KEY) ||
|
||||
rc->frames_to_key == 0 || (cpi->oxcf.auto_key && 0))) {
|
||||
cm->frame_type = KEY_FRAME;
|
||||
if ((current_frame->frame_number == 0 ||
|
||||
(cpi->frame_flags & FRAMEFLAGS_KEY) || rc->frames_to_key == 0 ||
|
||||
(cpi->oxcf.auto_key && 0))) {
|
||||
frame_params->frame_type = KEY_FRAME;
|
||||
rc->this_key_frame_forced =
|
||||
cm->current_video_frame != 0 && rc->frames_to_key == 0;
|
||||
current_frame->frame_number != 0 && rc->frames_to_key == 0;
|
||||
rc->frames_to_key = cpi->oxcf.key_freq;
|
||||
rc->kf_boost = DEFAULT_KF_BOOST;
|
||||
rc->source_alt_ref_active = 0;
|
||||
} else {
|
||||
cm->frame_type = INTER_FRAME;
|
||||
frame_params->frame_type = INTER_FRAME;
|
||||
}
|
||||
if (rc->frames_till_gf_update_due == 0) {
|
||||
if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ)
|
||||
|
|
@ -1602,7 +1648,7 @@ void av1_rc_get_one_pass_cbr_params(AV1_COMP *cpi) {
|
|||
if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ)
|
||||
av1_cyclic_refresh_update_parameters(cpi);
|
||||
|
||||
if (cm->frame_type == KEY_FRAME)
|
||||
if (frame_params->frame_type == KEY_FRAME)
|
||||
target = calc_iframe_target_size_one_pass_cbr(cpi);
|
||||
else
|
||||
target = calc_pframe_target_size_one_pass_cbr(cpi);
|
||||
|
|
@ -1674,15 +1720,10 @@ void av1_rc_set_gf_interval_range(const AV1_COMP *const cpi,
|
|||
oxcf->width, oxcf->height, cpi->framerate);
|
||||
if (rc->max_gf_interval == 0)
|
||||
rc->max_gf_interval = av1_rc_get_default_max_gf_interval(
|
||||
cpi->framerate, rc->min_gf_interval);
|
||||
cpi->framerate, rc->min_gf_interval, oxcf->gf_max_pyr_height);
|
||||
|
||||
// Extended interval for genuinely static scenes
|
||||
rc->static_scene_max_gf_interval = MAX_LAG_BUFFERS * 2;
|
||||
|
||||
if (is_altref_enabled(cpi)) {
|
||||
if (rc->static_scene_max_gf_interval > oxcf->lag_in_frames - 1)
|
||||
rc->static_scene_max_gf_interval = oxcf->lag_in_frames - 1;
|
||||
}
|
||||
// Extended max interval for genuinely static scenes like slide shows.
|
||||
rc->static_scene_max_gf_interval = MAX_STATIC_GF_GROUP_LENGTH;
|
||||
|
||||
if (rc->max_gf_interval > rc->static_scene_max_gf_interval)
|
||||
rc->max_gf_interval = rc->static_scene_max_gf_interval;
|
||||
|
|
@ -1733,7 +1774,7 @@ static void vbr_rate_correction(AV1_COMP *cpi, int *this_frame_target) {
|
|||
// This number is used to damp the per frame rate correction.
|
||||
// Range 0 - 1.0
|
||||
if (cpi->twopass.total_stats.count != 0.) {
|
||||
position_factor = sqrt((double)cpi->common.current_video_frame /
|
||||
position_factor = sqrt((double)cpi->common.current_frame.frame_number /
|
||||
cpi->twopass.total_stats.count);
|
||||
}
|
||||
max_delta = (int)(position_factor *
|
||||
|
|
|
|||
65
third_party/aom/av1/encoder/ratectrl.h
vendored
65
third_party/aom/av1/encoder/ratectrl.h
vendored
|
|
@ -16,6 +16,7 @@
|
|||
#include "aom/aom_integer.h"
|
||||
|
||||
#include "av1/common/blockd.h"
|
||||
#include "av1/common/onyxc_int.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
|
@ -24,48 +25,24 @@ extern "C" {
|
|||
// Bits Per MB at different Q (Multiplied by 512)
|
||||
#define BPER_MB_NORMBITS 9
|
||||
|
||||
#define CUSTOMIZED_GF 1
|
||||
// Threshold used to define if a KF group is static (e.g. a slide show).
|
||||
// Essentially, this means that no frame in the group has more than 1% of MBs
|
||||
// that are not marked as coded with 0,0 motion in the first pass.
|
||||
#define STATIC_KF_GROUP_THRESH 99
|
||||
#define STATIC_KF_GROUP_FLOAT_THRESH 0.99
|
||||
|
||||
#if CONFIG_FIX_GF_LENGTH
|
||||
#define FIXED_GF_LENGTH 16
|
||||
// The maximum duration of a GF group that is static (e.g. a slide show).
|
||||
#define MAX_STATIC_GF_GROUP_LENGTH 250
|
||||
|
||||
// Minimum and maximum height for the new pyramid structure.
|
||||
// (Old structure supports height = 1, but does NOT support height = 4).
|
||||
#define MIN_PYRAMID_LVL 2
|
||||
#define MAX_PYRAMID_LVL 4
|
||||
// We allow a frame to have at most two left/right descendants before changing
|
||||
// them into to a subtree, i.e., we allow the following structure:
|
||||
/* OUT_OF_ORDER_FRAME
|
||||
/ / \ \
|
||||
(two left children) F F F F (two right children) */
|
||||
// Therefore the max gf size supported by 4 layer structure is
|
||||
// 1 (KEY/OVERLAY) + 1 + 2 + 4 + 16 (two children on both side of their parent)
|
||||
#define MAX_PYRAMID_SIZE 24
|
||||
#define USE_SYMM_MULTI_LAYER 1
|
||||
#define REDUCE_LAST_ALT_BOOST 1
|
||||
#define REDUCE_LAST_GF_LENGTH 1
|
||||
#define MULTI_LVL_BOOST_VBR_CQ 1
|
||||
#else
|
||||
#define USE_SYMM_MULTI_LAYER 0
|
||||
#define REDUCE_LAST_ALT_BOOST 0
|
||||
#define REDUCE_LAST_GF_LENGTH 0
|
||||
#define MULTI_LVL_BOOST_VBR_CQ 0
|
||||
#endif
|
||||
|
||||
#if USE_SYMM_MULTI_LAYER
|
||||
#define USE_MANUAL_GF4_STRUCT 0
|
||||
#endif
|
||||
|
||||
#define MIN_GF_INTERVAL 4
|
||||
#define MAX_GF_INTERVAL 16
|
||||
#define FIXED_GF_INTERVAL 8 // Used in some testing modes only
|
||||
|
||||
typedef enum {
|
||||
INTER_NORMAL = 0,
|
||||
INTER_LOW = 1,
|
||||
INTER_HIGH = 2,
|
||||
GF_ARF_LOW = 3,
|
||||
GF_ARF_STD = 4,
|
||||
KF_STD = 5,
|
||||
RATE_FACTOR_LEVELS = 6
|
||||
} RATE_FACTOR_LEVEL;
|
||||
|
||||
static const double rate_factor_deltas[RATE_FACTOR_LEVELS] = {
|
||||
1.00, // INTER_NORMAL
|
||||
0.80, // INTER_LOW
|
||||
|
|
@ -93,7 +70,6 @@ typedef struct {
|
|||
int last_kf_qindex; // Q index of the last key frame coded.
|
||||
|
||||
int gfu_boost;
|
||||
int last_boost;
|
||||
int kf_boost;
|
||||
|
||||
double rate_correction_factors[RATE_FACTOR_LEVELS];
|
||||
|
|
@ -195,7 +171,10 @@ int av1_rc_get_default_min_gf_interval(int width, int height, double framerate);
|
|||
// Note av1_rc_get_default_max_gf_interval() requires the min_gf_interval to
|
||||
// be passed in to ensure that the max_gf_interval returned is at least as bis
|
||||
// as that.
|
||||
int av1_rc_get_default_max_gf_interval(double framerate, int min_frame_rate);
|
||||
int av1_rc_get_default_max_gf_interval(double framerate, int min_frame_rate,
|
||||
int max_pyr_height);
|
||||
|
||||
int av1_rc_get_fixed_gf_length(int max_pyr_height);
|
||||
|
||||
// Generally at the high level, the following flow is expected
|
||||
// to be enforced for rate control:
|
||||
|
|
@ -220,8 +199,11 @@ int av1_rc_get_default_max_gf_interval(double framerate, int min_frame_rate);
|
|||
|
||||
// Functions to set parameters for encoding before the actual
|
||||
// encode_frame_to_data_rate() function.
|
||||
void av1_rc_get_one_pass_vbr_params(struct AV1_COMP *cpi);
|
||||
void av1_rc_get_one_pass_cbr_params(struct AV1_COMP *cpi);
|
||||
struct EncodeFrameParams;
|
||||
void av1_rc_get_one_pass_vbr_params(
|
||||
struct AV1_COMP *cpi, struct EncodeFrameParams *const frame_params);
|
||||
void av1_rc_get_one_pass_cbr_params(
|
||||
struct AV1_COMP *cpi, struct EncodeFrameParams *const frame_params);
|
||||
|
||||
// Post encode update of the rate control parameters based
|
||||
// on bytes used
|
||||
|
|
@ -262,9 +244,6 @@ int av1_rc_clamp_iframe_target_size(const struct AV1_COMP *const cpi,
|
|||
int target);
|
||||
int av1_rc_clamp_pframe_target_size(const struct AV1_COMP *const cpi,
|
||||
int target);
|
||||
// Utility to set frame_target into the RATE_CONTROL structure
|
||||
// This function is called only from the av1_rc_get_..._params() functions.
|
||||
void av1_rc_set_frame_target(struct AV1_COMP *cpi, int target);
|
||||
|
||||
// Computes a q delta (in "q index" terms) to get from a starting q value
|
||||
// to a target q value
|
||||
|
|
@ -288,6 +267,8 @@ void av1_set_target_rate(struct AV1_COMP *cpi, int width, int height);
|
|||
|
||||
int av1_resize_one_pass_cbr(struct AV1_COMP *cpi);
|
||||
|
||||
void av1_estimate_qp_gop(struct AV1_COMP *cpi);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
|
|
|||
1275
third_party/aom/av1/encoder/rd.c
vendored
1275
third_party/aom/av1/encoder/rd.c
vendored
File diff suppressed because it is too large
Load diff
283
third_party/aom/av1/encoder/rd.h
vendored
283
third_party/aom/av1/encoder/rd.h
vendored
|
|
@ -48,7 +48,7 @@ extern "C" {
|
|||
|
||||
// This enumerator type needs to be kept aligned with the mode order in
|
||||
// const MODE_DEFINITION av1_mode_order[MAX_MODES] used in the rd code.
|
||||
typedef enum {
|
||||
enum {
|
||||
THR_NEARESTMV,
|
||||
THR_NEARESTL2,
|
||||
THR_NEARESTL3,
|
||||
|
|
@ -246,9 +246,9 @@ typedef enum {
|
|||
MAX_SINGLE_REF_MODES = LAST_SINGLE_REF_MODES + 1,
|
||||
LAST_COMP_REF_MODES = THR_COMP_GLOBAL_GLOBALBA,
|
||||
MAX_COMP_REF_MODES = LAST_COMP_REF_MODES + 1
|
||||
} THR_MODES;
|
||||
} UENUM1BYTE(THR_MODES);
|
||||
|
||||
typedef enum {
|
||||
enum {
|
||||
THR_LAST,
|
||||
THR_LAST2,
|
||||
THR_LAST3,
|
||||
|
|
@ -275,7 +275,7 @@ typedef enum {
|
|||
THR_INTRA,
|
||||
|
||||
MAX_REFS
|
||||
} THR_MODES_SUB8X8;
|
||||
} UENUM1BYTE(THR_MODES_SUB8X8);
|
||||
|
||||
typedef struct RD_OPT {
|
||||
// Thresh_mult is used to set a threshold for the rd score. A higher value
|
||||
|
|
@ -283,13 +283,14 @@ typedef struct RD_OPT {
|
|||
// is used in combination with the current block size, and thresh_freq_fact
|
||||
// to pick a threshold.
|
||||
int thresh_mult[MAX_MODES];
|
||||
int thresh_mult_sub8x8[MAX_REFS];
|
||||
|
||||
int threshes[MAX_SEGMENTS][BLOCK_SIZES_ALL][MAX_MODES];
|
||||
|
||||
int64_t prediction_type_threshes[REF_FRAMES][REFERENCE_MODES];
|
||||
|
||||
int RDMULT;
|
||||
|
||||
double r0;
|
||||
} RD_OPT;
|
||||
|
||||
static INLINE void av1_init_rd_stats(RD_STATS *rd_stats) {
|
||||
|
|
@ -317,6 +318,25 @@ static INLINE void av1_init_rd_stats(RD_STATS *rd_stats) {
|
|||
}
|
||||
}
|
||||
#endif
|
||||
#if CONFIG_ONE_PASS_SVM
|
||||
rd_stats->eob = 0;
|
||||
rd_stats->eob_0 = 0;
|
||||
rd_stats->eob_1 = 0;
|
||||
rd_stats->eob_2 = 0;
|
||||
rd_stats->eob_3 = 0;
|
||||
|
||||
rd_stats->rd = 0;
|
||||
rd_stats->rd_0 = 0;
|
||||
rd_stats->rd_1 = 0;
|
||||
rd_stats->rd_2 = 0;
|
||||
rd_stats->rd_3 = 0;
|
||||
|
||||
rd_stats->y_sse = 0;
|
||||
rd_stats->sse_0 = 0;
|
||||
rd_stats->sse_1 = 0;
|
||||
rd_stats->sse_2 = 0;
|
||||
rd_stats->sse_3 = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE void av1_invalid_rd_stats(RD_STATS *rd_stats) {
|
||||
|
|
@ -344,6 +364,30 @@ static INLINE void av1_invalid_rd_stats(RD_STATS *rd_stats) {
|
|||
}
|
||||
}
|
||||
#endif
|
||||
#if CONFIG_ONE_PASS_SVM
|
||||
// TODO(chiyotsai@google.com): Change invalid values to INT_MAX and
|
||||
// INT64_MAX. Currently there are some code paths where rd_stats's properties
|
||||
// are set directly without calling av1_init_rd_stats, so changing it now will
|
||||
// break this speed feature. Need to hunt down all places where rd_stats is
|
||||
// used without initialized.
|
||||
rd_stats->eob = 0;
|
||||
rd_stats->eob_0 = 0;
|
||||
rd_stats->eob_1 = 0;
|
||||
rd_stats->eob_2 = 0;
|
||||
rd_stats->eob_3 = 0;
|
||||
|
||||
rd_stats->rd = 0;
|
||||
rd_stats->rd_0 = 0;
|
||||
rd_stats->rd_1 = 0;
|
||||
rd_stats->rd_2 = 0;
|
||||
rd_stats->rd_3 = 0;
|
||||
|
||||
rd_stats->y_sse = 0;
|
||||
rd_stats->sse_0 = 0;
|
||||
rd_stats->sse_1 = 0;
|
||||
rd_stats->sse_2 = 0;
|
||||
rd_stats->sse_3 = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE void av1_merge_rd_stats(RD_STATS *rd_stats_dst,
|
||||
|
|
@ -377,26 +421,245 @@ static INLINE void av1_merge_rd_stats(RD_STATS *rd_stats_dst,
|
|||
}
|
||||
}
|
||||
#endif
|
||||
#if CONFIG_ONE_PASS_SVM
|
||||
rd_stats_dst->eob += rd_stats_src->eob;
|
||||
rd_stats_dst->eob_0 += rd_stats_src->eob_0;
|
||||
rd_stats_dst->eob_1 += rd_stats_src->eob_1;
|
||||
rd_stats_dst->eob_2 += rd_stats_src->eob_2;
|
||||
rd_stats_dst->eob_3 += rd_stats_src->eob_3;
|
||||
|
||||
rd_stats_dst->rd += rd_stats_src->rd;
|
||||
rd_stats_dst->rd_0 += rd_stats_src->rd_0;
|
||||
rd_stats_dst->rd_1 += rd_stats_src->rd_1;
|
||||
rd_stats_dst->rd_2 += rd_stats_src->rd_2;
|
||||
rd_stats_dst->rd_3 += rd_stats_src->rd_3;
|
||||
|
||||
rd_stats_dst->y_sse += rd_stats_src->y_sse;
|
||||
rd_stats_dst->sse_0 += rd_stats_src->sse_0;
|
||||
rd_stats_dst->sse_1 += rd_stats_src->sse_1;
|
||||
rd_stats_dst->sse_2 += rd_stats_src->sse_2;
|
||||
rd_stats_dst->sse_3 += rd_stats_src->sse_3;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if CONFIG_ONE_PASS_SVM
|
||||
static INLINE void av1_add_reg_stat(RD_STATS *rd_stats, int eob, int64_t rd,
|
||||
int64_t sse, int blk_row, int blk_col,
|
||||
BLOCK_SIZE bsize, BLOCK_SIZE crop_bsize) {
|
||||
// NOTE: Currently the calculation of regional features works by assuming
|
||||
// bsize is square so that each transform block of size crop_bsize either
|
||||
// 1. locates completely within a quadrant or
|
||||
// 2. is exactly half of bsize or
|
||||
// 3. is the entire prediction block
|
||||
// Size of TX block and SB
|
||||
const int block_width_mi = mi_size_wide[bsize];
|
||||
const int block_height_mi = mi_size_high[bsize];
|
||||
const int crop_width_mi = mi_size_wide[crop_bsize];
|
||||
const int crop_height_mi = mi_size_high[crop_bsize];
|
||||
|
||||
// Increment the eob proportionally to how much the tx_block overlaps with
|
||||
// each quadrant. We will scale it by MAX_MIB_SIZE * MAX_MIB_SIZE to avoid
|
||||
// being truncated.
|
||||
const int max_scaling_factor = MAX_MIB_SIZE * MAX_MIB_SIZE;
|
||||
|
||||
// Update the stats
|
||||
rd_stats->eob = eob;
|
||||
rd_stats->rd = rd;
|
||||
rd_stats->y_sse = sse;
|
||||
|
||||
if (crop_width_mi <= block_width_mi / 2 &&
|
||||
crop_height_mi <= block_width_mi / 2) {
|
||||
// The transform block lies completely in a quadrant.
|
||||
const int scaling_factor = max_scaling_factor;
|
||||
const int r_eob = eob * scaling_factor, r_rd = rd * scaling_factor,
|
||||
r_sse = sse * scaling_factor;
|
||||
|
||||
if (blk_row < block_height_mi / 2 && blk_col < block_width_mi / 2) {
|
||||
rd_stats->eob_0 = r_eob;
|
||||
rd_stats->rd_0 = r_rd;
|
||||
rd_stats->sse_0 = r_sse;
|
||||
} else if (blk_row < block_height_mi / 2 && blk_col >= block_width_mi / 2) {
|
||||
rd_stats->eob_1 = r_eob;
|
||||
rd_stats->rd_1 = r_rd;
|
||||
rd_stats->sse_1 = r_sse;
|
||||
} else if (blk_row >= block_height_mi / 2 && blk_col < block_width_mi / 2) {
|
||||
rd_stats->eob_2 = r_eob;
|
||||
rd_stats->rd_2 = r_rd;
|
||||
rd_stats->sse_2 = r_sse;
|
||||
} else {
|
||||
rd_stats->eob_3 = r_eob;
|
||||
rd_stats->rd_3 = r_rd;
|
||||
rd_stats->sse_3 = r_sse;
|
||||
}
|
||||
} else if (crop_height_mi == block_height_mi &&
|
||||
crop_width_mi == block_width_mi) {
|
||||
// The transform block is the whole prediction block
|
||||
const int scaling_factor = max_scaling_factor;
|
||||
const int r_eob = eob * scaling_factor, r_rd = rd * scaling_factor,
|
||||
r_sse = sse * scaling_factor;
|
||||
|
||||
rd_stats->eob_0 = r_eob;
|
||||
rd_stats->rd_0 = r_rd;
|
||||
rd_stats->sse_0 = r_sse;
|
||||
|
||||
rd_stats->eob_1 = r_eob;
|
||||
rd_stats->rd_1 = r_rd;
|
||||
rd_stats->sse_1 = r_sse;
|
||||
|
||||
rd_stats->eob_2 = r_eob;
|
||||
rd_stats->rd_2 = r_rd;
|
||||
rd_stats->sse_2 = r_sse;
|
||||
|
||||
rd_stats->eob_3 = r_eob;
|
||||
rd_stats->rd_3 = r_rd;
|
||||
rd_stats->sse_3 = r_sse;
|
||||
} else if (crop_height_mi == block_height_mi) {
|
||||
// The tranform block is a vertical block
|
||||
const int scaling_factor = max_scaling_factor / 2;
|
||||
const int r_eob = eob * scaling_factor, r_rd = rd * scaling_factor,
|
||||
r_sse = sse * scaling_factor;
|
||||
|
||||
if (blk_col < block_width_mi / 2) {
|
||||
rd_stats->eob_0 = r_eob;
|
||||
rd_stats->rd_0 = r_rd;
|
||||
rd_stats->sse_0 = r_sse;
|
||||
|
||||
rd_stats->eob_2 = r_eob;
|
||||
rd_stats->rd_2 = r_rd;
|
||||
rd_stats->sse_2 = r_sse;
|
||||
} else {
|
||||
rd_stats->eob_1 = r_eob;
|
||||
rd_stats->rd_1 = r_rd;
|
||||
rd_stats->sse_1 = r_sse;
|
||||
|
||||
rd_stats->eob_3 = r_eob;
|
||||
rd_stats->rd_3 = r_rd;
|
||||
rd_stats->sse_3 = r_sse;
|
||||
}
|
||||
} else if (crop_width_mi == block_width_mi) {
|
||||
// The tranform block is a horizontal block half the size of predition block
|
||||
const int scaling_factor = max_scaling_factor / 2;
|
||||
const int r_eob = eob * scaling_factor, r_rd = rd * scaling_factor,
|
||||
r_sse = sse * scaling_factor;
|
||||
|
||||
if (blk_row < block_height_mi / 2) {
|
||||
rd_stats->eob_0 = r_eob;
|
||||
rd_stats->rd_0 = r_rd;
|
||||
rd_stats->sse_0 = r_sse;
|
||||
|
||||
rd_stats->eob_1 = r_eob;
|
||||
rd_stats->rd_1 = r_rd;
|
||||
rd_stats->sse_1 = r_sse;
|
||||
} else {
|
||||
rd_stats->eob_2 = r_eob;
|
||||
rd_stats->rd_2 = r_rd;
|
||||
rd_stats->sse_2 = r_sse;
|
||||
|
||||
rd_stats->eob_3 = r_eob;
|
||||
rd_stats->rd_3 = r_rd;
|
||||
rd_stats->sse_3 = r_sse;
|
||||
}
|
||||
} else {
|
||||
assert(0 && "Unexpected transform size");
|
||||
}
|
||||
}
|
||||
|
||||
static INLINE void av1_reg_stat_skipmode_update(RD_STATS *rd_stats,
|
||||
int rdmult) {
|
||||
// Update the stats
|
||||
rd_stats->eob = 0;
|
||||
rd_stats->eob_0 = 0;
|
||||
rd_stats->eob_1 = 0;
|
||||
rd_stats->eob_2 = 0;
|
||||
rd_stats->eob_3 = 0;
|
||||
|
||||
rd_stats->rd = RDCOST(rdmult, 0, rd_stats->sse);
|
||||
rd_stats->rd_0 = RDCOST(rdmult, 0, rd_stats->sse_0);
|
||||
rd_stats->rd_1 = RDCOST(rdmult, 0, rd_stats->sse_1);
|
||||
rd_stats->rd_2 = RDCOST(rdmult, 0, rd_stats->sse_2);
|
||||
rd_stats->rd_3 = RDCOST(rdmult, 0, rd_stats->sse_3);
|
||||
}
|
||||
|
||||
static INLINE void av1_copy_reg_stat(RD_STATS *rd_stats_dst,
|
||||
RD_STATS *rd_stats_src) {
|
||||
rd_stats_dst->eob = rd_stats_src->eob;
|
||||
rd_stats_dst->eob_0 = rd_stats_src->eob_0;
|
||||
rd_stats_dst->eob_1 = rd_stats_src->eob_1;
|
||||
rd_stats_dst->eob_2 = rd_stats_src->eob_2;
|
||||
rd_stats_dst->eob_3 = rd_stats_src->eob_3;
|
||||
|
||||
rd_stats_dst->rd = rd_stats_src->rd;
|
||||
rd_stats_dst->rd_0 = rd_stats_src->rd_0;
|
||||
rd_stats_dst->rd_1 = rd_stats_src->rd_1;
|
||||
rd_stats_dst->rd_2 = rd_stats_src->rd_2;
|
||||
rd_stats_dst->rd_3 = rd_stats_src->rd_3;
|
||||
|
||||
rd_stats_dst->y_sse = rd_stats_src->y_sse;
|
||||
rd_stats_dst->sse_0 = rd_stats_src->sse_0;
|
||||
rd_stats_dst->sse_1 = rd_stats_src->sse_1;
|
||||
rd_stats_dst->sse_2 = rd_stats_src->sse_2;
|
||||
rd_stats_dst->sse_3 = rd_stats_src->sse_3;
|
||||
}
|
||||
|
||||
static INLINE void av1_unpack_reg_stat(RD_STATS *rd_stats, int *eob, int *eob_0,
|
||||
int *eob_1, int *eob_2, int *eob_3,
|
||||
int64_t *rd, int64_t *rd_0,
|
||||
int64_t *rd_1, int64_t *rd_2,
|
||||
int64_t *rd_3) {
|
||||
*rd = rd_stats->rd;
|
||||
*rd_0 = rd_stats->rd_0;
|
||||
*rd_1 = rd_stats->rd_1;
|
||||
*rd_2 = rd_stats->rd_2;
|
||||
*rd_3 = rd_stats->rd_3;
|
||||
|
||||
*eob = rd_stats->eob;
|
||||
*eob_0 = rd_stats->eob_0;
|
||||
*eob_1 = rd_stats->eob_1;
|
||||
*eob_2 = rd_stats->eob_2;
|
||||
*eob_3 = rd_stats->eob_3;
|
||||
}
|
||||
|
||||
static INLINE void av1_set_reg_stat(RD_STATS *rd_stats, int eob, int eob_0,
|
||||
int eob_1, int eob_2, int eob_3, int64_t rd,
|
||||
int64_t rd_0, int64_t rd_1, int64_t rd_2,
|
||||
int64_t rd_3) {
|
||||
rd_stats->rd = rd;
|
||||
rd_stats->rd_0 = rd_0;
|
||||
rd_stats->rd_1 = rd_1;
|
||||
rd_stats->rd_2 = rd_2;
|
||||
rd_stats->rd_3 = rd_3;
|
||||
|
||||
rd_stats->eob = eob;
|
||||
rd_stats->eob_0 = eob_0;
|
||||
rd_stats->eob_1 = eob_1;
|
||||
rd_stats->eob_2 = eob_2;
|
||||
rd_stats->eob_3 = eob_3;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct TileInfo;
|
||||
struct TileDataEnc;
|
||||
struct AV1_COMP;
|
||||
struct macroblock;
|
||||
|
||||
int av1_compute_rd_mult_based_on_qindex(const struct AV1_COMP *cpi, int qindex);
|
||||
|
||||
int av1_compute_rd_mult(const struct AV1_COMP *cpi, int qindex);
|
||||
|
||||
void av1_initialize_rd_consts(struct AV1_COMP *cpi);
|
||||
|
||||
void av1_initialize_cost_tables(const AV1_COMMON *const cm, MACROBLOCK *x);
|
||||
|
||||
void av1_initialize_me_consts(const struct AV1_COMP *cpi, MACROBLOCK *x,
|
||||
int qindex);
|
||||
|
||||
void av1_model_rd_from_var_lapndz(int64_t var, unsigned int n,
|
||||
unsigned int qstep, int *rate, int64_t *dist);
|
||||
|
||||
void av1_model_rd_curvfit(double xqr, double *rate_f, double *distbysse_f);
|
||||
void av1_model_rd_surffit(double xm, double yl, double *rate_f,
|
||||
double *distbysse_f);
|
||||
void av1_model_rd_curvfit(BLOCK_SIZE bsize, double sse_norm, double xqr,
|
||||
double *rate_f, double *distbysse_f);
|
||||
void av1_model_rd_surffit(BLOCK_SIZE bsize, double sse_norm, double xm,
|
||||
double yl, double *rate_f, double *distbysse_f);
|
||||
|
||||
int av1_get_switchable_rate(const AV1_COMMON *const cm, MACROBLOCK *x,
|
||||
const MACROBLOCKD *xd);
|
||||
|
|
@ -421,8 +684,6 @@ void av1_get_entropy_contexts(BLOCK_SIZE bsize,
|
|||
|
||||
void av1_set_rd_speed_thresholds(struct AV1_COMP *cpi);
|
||||
|
||||
void av1_set_rd_speed_thresholds_sub8x8(struct AV1_COMP *cpi);
|
||||
|
||||
void av1_update_rd_thresh_fact(const AV1_COMMON *const cm,
|
||||
int (*fact)[MAX_MODES], int rd_thresh, int bsize,
|
||||
int best_mode_index);
|
||||
|
|
@ -457,6 +718,8 @@ void av1_fill_mode_rates(AV1_COMMON *const cm, MACROBLOCK *x,
|
|||
void av1_fill_coeff_costs(MACROBLOCK *x, FRAME_CONTEXT *fc,
|
||||
const int num_planes);
|
||||
|
||||
int av1_get_adaptive_rdmult(const struct AV1_COMP *cpi, double beta);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
|
|
|||
4233
third_party/aom/av1/encoder/rdopt.c
vendored
4233
third_party/aom/av1/encoder/rdopt.c
vendored
File diff suppressed because it is too large
Load diff
27
third_party/aom/av1/encoder/rdopt.h
vendored
27
third_party/aom/av1/encoder/rdopt.h
vendored
|
|
@ -12,6 +12,8 @@
|
|||
#ifndef AOM_AV1_ENCODER_RDOPT_H_
|
||||
#define AOM_AV1_ENCODER_RDOPT_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "av1/common/blockd.h"
|
||||
#include "av1/common/txb_common.h"
|
||||
|
||||
|
|
@ -126,10 +128,31 @@ void av1_rd_pick_inter_mode_sb_seg_skip(
|
|||
struct macroblock *x, int mi_row, int mi_col, struct RD_STATS *rd_cost,
|
||||
BLOCK_SIZE bsize, PICK_MODE_CONTEXT *ctx, int64_t best_rd_so_far);
|
||||
|
||||
#if CONFIG_COLLECT_INTER_MODE_RD_STATS
|
||||
/** Returns an integer indicating the strength of the edge.
|
||||
* 0 means no edge found, 556 is the strength of a solid black/white edge,
|
||||
* and the number may range higher if the signal is even stronger (e.g., on a
|
||||
* corner). high_bd is a bool indicating the source should be treated
|
||||
* as a 16-bit array. bd is the bit depth.
|
||||
*/
|
||||
uint16_t av1_edge_exists(const uint8_t *src, int src_stride, int w, int h,
|
||||
bool high_bd, int bd);
|
||||
|
||||
/** Applies a Gaussian blur with sigma = 1.3. Used by av1_edge_exists and
|
||||
* tests.
|
||||
*/
|
||||
void gaussian_blur(const uint8_t *src, int src_stride, int w, int h,
|
||||
uint8_t *dst, bool high_bd, int bd);
|
||||
|
||||
/* Applies standard 3x3 Sobel matrix. */
|
||||
typedef struct {
|
||||
int16_t x;
|
||||
int16_t y;
|
||||
} sobel_xy;
|
||||
|
||||
sobel_xy sobel(const uint8_t *input, int stride, int i, int j, bool high_bd);
|
||||
|
||||
void av1_inter_mode_data_init(struct TileDataEnc *tile_data);
|
||||
void av1_inter_mode_data_fit(TileDataEnc *tile_data, int rdmult);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
|
|
|
|||
130
third_party/aom/av1/encoder/reconinter_enc.c
vendored
130
third_party/aom/av1/encoder/reconinter_enc.c
vendored
|
|
@ -138,26 +138,28 @@ static INLINE void build_inter_predictors(const AV1_COMMON *cm, MACROBLOCKD *xd,
|
|||
assert(bw < 8 || bh < 8);
|
||||
ConvolveParams conv_params = get_conv_params_no_round(
|
||||
0, plane, xd->tmp_conv_dst, tmp_dst_stride, is_compound, xd->bd);
|
||||
conv_params.use_jnt_comp_avg = 0;
|
||||
conv_params.use_dist_wtd_comp_avg = 0;
|
||||
struct buf_2d *const dst_buf = &pd->dst;
|
||||
uint8_t *dst = dst_buf->buf + dst_buf->stride * y + x;
|
||||
|
||||
ref = 0;
|
||||
const RefBuffer *ref_buf =
|
||||
&cm->frame_refs[this_mbmi->ref_frame[ref] - LAST_FRAME];
|
||||
const RefCntBuffer *ref_buf =
|
||||
get_ref_frame_buf(cm, this_mbmi->ref_frame[ref]);
|
||||
const struct scale_factors *ref_scale_factors =
|
||||
get_ref_scale_factors_const(cm, this_mbmi->ref_frame[ref]);
|
||||
|
||||
pd->pre[ref].buf0 =
|
||||
(plane == 1) ? ref_buf->buf->u_buffer : ref_buf->buf->v_buffer;
|
||||
(plane == 1) ? ref_buf->buf.u_buffer : ref_buf->buf.v_buffer;
|
||||
pd->pre[ref].buf =
|
||||
pd->pre[ref].buf0 + scaled_buffer_offset(pre_x, pre_y,
|
||||
ref_buf->buf->uv_stride,
|
||||
&ref_buf->sf);
|
||||
pd->pre[ref].width = ref_buf->buf->uv_crop_width;
|
||||
pd->pre[ref].height = ref_buf->buf->uv_crop_height;
|
||||
pd->pre[ref].stride = ref_buf->buf->uv_stride;
|
||||
ref_buf->buf.uv_stride,
|
||||
ref_scale_factors);
|
||||
pd->pre[ref].width = ref_buf->buf.uv_crop_width;
|
||||
pd->pre[ref].height = ref_buf->buf.uv_crop_height;
|
||||
pd->pre[ref].stride = ref_buf->buf.uv_stride;
|
||||
|
||||
const struct scale_factors *const sf =
|
||||
is_intrabc ? &cm->sf_identity : &ref_buf->sf;
|
||||
is_intrabc ? &cm->sf_identity : ref_scale_factors;
|
||||
struct buf_2d *const pre_buf = is_intrabc ? dst_buf : &pd->pre[ref];
|
||||
|
||||
const MV mv = this_mbmi->mv[ref].as_mv;
|
||||
|
|
@ -194,15 +196,15 @@ static INLINE void build_inter_predictors(const AV1_COMMON *cm, MACROBLOCKD *xd,
|
|||
{
|
||||
ConvolveParams conv_params = get_conv_params_no_round(
|
||||
0, plane, xd->tmp_conv_dst, MAX_SB_SIZE, is_compound, xd->bd);
|
||||
av1_jnt_comp_weight_assign(cm, mi, 0, &conv_params.fwd_offset,
|
||||
&conv_params.bck_offset,
|
||||
&conv_params.use_jnt_comp_avg, is_compound);
|
||||
av1_dist_wtd_comp_weight_assign(
|
||||
cm, mi, 0, &conv_params.fwd_offset, &conv_params.bck_offset,
|
||||
&conv_params.use_dist_wtd_comp_avg, is_compound);
|
||||
|
||||
struct buf_2d *const dst_buf = &pd->dst;
|
||||
uint8_t *const dst = dst_buf->buf;
|
||||
for (ref = 0; ref < 1 + is_compound; ++ref) {
|
||||
const struct scale_factors *const sf =
|
||||
is_intrabc ? &cm->sf_identity : &xd->block_refs[ref]->sf;
|
||||
is_intrabc ? &cm->sf_identity : xd->block_ref_scale_factors[ref];
|
||||
struct buf_2d *const pre_buf = is_intrabc ? dst_buf : &pd->pre[ref];
|
||||
const MV mv = mi->mv[ref].as_mv;
|
||||
|
||||
|
|
@ -235,46 +237,19 @@ static INLINE void build_inter_predictors(const AV1_COMMON *cm, MACROBLOCKD *xd,
|
|||
}
|
||||
}
|
||||
|
||||
static void build_inter_predictors_for_planes(const AV1_COMMON *cm,
|
||||
MACROBLOCKD *xd, BLOCK_SIZE bsize,
|
||||
int mi_row, int mi_col,
|
||||
int plane_from, int plane_to) {
|
||||
int plane;
|
||||
static void build_inter_predictors_for_plane(const AV1_COMMON *cm,
|
||||
MACROBLOCKD *xd, int mi_row,
|
||||
int mi_col, const BUFFER_SET *ctx,
|
||||
BLOCK_SIZE bsize, int plane_idx) {
|
||||
const struct macroblockd_plane *pd = &xd->plane[plane_idx];
|
||||
if (!is_chroma_reference(mi_row, mi_col, bsize, pd->subsampling_x,
|
||||
pd->subsampling_y))
|
||||
return;
|
||||
|
||||
const int mi_x = mi_col * MI_SIZE;
|
||||
const int mi_y = mi_row * MI_SIZE;
|
||||
for (plane = plane_from; plane <= plane_to; ++plane) {
|
||||
const struct macroblockd_plane *pd = &xd->plane[plane];
|
||||
const int bw = pd->width;
|
||||
const int bh = pd->height;
|
||||
|
||||
if (!is_chroma_reference(mi_row, mi_col, bsize, pd->subsampling_x,
|
||||
pd->subsampling_y))
|
||||
continue;
|
||||
|
||||
build_inter_predictors(cm, xd, plane, xd->mi[0], 0, bw, bh, mi_x, mi_y);
|
||||
}
|
||||
}
|
||||
|
||||
void av1_build_inter_predictors_sby(const AV1_COMMON *cm, MACROBLOCKD *xd,
|
||||
int mi_row, int mi_col, BUFFER_SET *ctx,
|
||||
BLOCK_SIZE bsize) {
|
||||
av1_build_inter_predictors_sbp(cm, xd, mi_row, mi_col, ctx, bsize, 0);
|
||||
}
|
||||
|
||||
void av1_build_inter_predictors_sbuv(const AV1_COMMON *cm, MACROBLOCKD *xd,
|
||||
int mi_row, int mi_col, BUFFER_SET *ctx,
|
||||
BLOCK_SIZE bsize) {
|
||||
for (int plane_idx = 1; plane_idx < MAX_MB_PLANE; plane_idx++) {
|
||||
av1_build_inter_predictors_sbp(cm, xd, mi_row, mi_col, ctx, bsize,
|
||||
plane_idx);
|
||||
}
|
||||
}
|
||||
|
||||
void av1_build_inter_predictors_sbp(const AV1_COMMON *cm, MACROBLOCKD *xd,
|
||||
int mi_row, int mi_col, BUFFER_SET *ctx,
|
||||
BLOCK_SIZE bsize, int plane_idx) {
|
||||
build_inter_predictors_for_planes(cm, xd, bsize, mi_row, mi_col, plane_idx,
|
||||
plane_idx);
|
||||
build_inter_predictors(cm, xd, plane_idx, xd->mi[0], 0, pd->width, pd->height,
|
||||
mi_x, mi_y);
|
||||
|
||||
if (is_interintra_pred(xd->mi[0])) {
|
||||
BUFFER_SET default_ctx = { { NULL, NULL, NULL }, { 0, 0, 0 } };
|
||||
|
|
@ -289,13 +264,14 @@ void av1_build_inter_predictors_sbp(const AV1_COMMON *cm, MACROBLOCKD *xd,
|
|||
}
|
||||
}
|
||||
|
||||
void av1_build_inter_predictors_sb(const AV1_COMMON *cm, MACROBLOCKD *xd,
|
||||
int mi_row, int mi_col, BUFFER_SET *ctx,
|
||||
BLOCK_SIZE bsize) {
|
||||
const int num_planes = av1_num_planes(cm);
|
||||
av1_build_inter_predictors_sby(cm, xd, mi_row, mi_col, ctx, bsize);
|
||||
if (num_planes > 1)
|
||||
av1_build_inter_predictors_sbuv(cm, xd, mi_row, mi_col, ctx, bsize);
|
||||
void av1_enc_build_inter_predictor(const AV1_COMMON *cm, MACROBLOCKD *xd,
|
||||
int mi_row, int mi_col,
|
||||
const BUFFER_SET *ctx, BLOCK_SIZE bsize,
|
||||
int plane_from, int plane_to) {
|
||||
for (int plane_idx = plane_from; plane_idx <= plane_to; ++plane_idx) {
|
||||
build_inter_predictors_for_plane(cm, xd, mi_row, mi_col, ctx, bsize,
|
||||
plane_idx);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(sarahparker):
|
||||
|
|
@ -308,7 +284,7 @@ void av1_build_inter_predictor(const uint8_t *src, int src_stride, uint8_t *dst,
|
|||
InterpFilters interp_filters,
|
||||
const WarpTypesAllowed *warp_types, int p_col,
|
||||
int p_row, int plane, int ref,
|
||||
enum mv_precision precision, int x, int y,
|
||||
mv_precision precision, int x, int y,
|
||||
const MACROBLOCKD *xd, int can_use_previous) {
|
||||
const int is_q4 = precision == MV_PRECISION_Q4;
|
||||
const MV mv_q4 = { is_q4 ? src_mv->row : src_mv->row * 2,
|
||||
|
|
@ -338,7 +314,7 @@ static INLINE void build_prediction_by_above_pred(
|
|||
MB_MODE_INFO backup_mbmi = *above_mbmi;
|
||||
|
||||
av1_setup_build_prediction_by_above_pred(xd, rel_mi_col, above_mi_width,
|
||||
above_mbmi, ctxt, num_planes);
|
||||
&backup_mbmi, ctxt, num_planes);
|
||||
mi_x = above_mi_col << MI_SIZE_LOG2;
|
||||
mi_y = ctxt->mi_row << MI_SIZE_LOG2;
|
||||
|
||||
|
|
@ -351,9 +327,9 @@ static INLINE void build_prediction_by_above_pred(
|
|||
block_size_high[BLOCK_64X64] >> (pd->subsampling_y + 1));
|
||||
|
||||
if (av1_skip_u4x4_pred_in_obmc(bsize, pd, 0)) continue;
|
||||
build_inter_predictors(ctxt->cm, xd, j, above_mbmi, 1, bw, bh, mi_x, mi_y);
|
||||
build_inter_predictors(ctxt->cm, xd, j, &backup_mbmi, 1, bw, bh, mi_x,
|
||||
mi_y);
|
||||
}
|
||||
*above_mbmi = backup_mbmi;
|
||||
}
|
||||
|
||||
void av1_build_prediction_by_above_preds(const AV1_COMMON *cm, MACROBLOCKD *xd,
|
||||
|
|
@ -394,7 +370,7 @@ static INLINE void build_prediction_by_left_pred(
|
|||
MB_MODE_INFO backup_mbmi = *left_mbmi;
|
||||
|
||||
av1_setup_build_prediction_by_left_pred(xd, rel_mi_row, left_mi_height,
|
||||
left_mbmi, ctxt, num_planes);
|
||||
&backup_mbmi, ctxt, num_planes);
|
||||
mi_x = ctxt->mi_col << MI_SIZE_LOG2;
|
||||
mi_y = left_mi_row << MI_SIZE_LOG2;
|
||||
const BLOCK_SIZE bsize = xd->mi[0]->sb_type;
|
||||
|
|
@ -406,9 +382,9 @@ static INLINE void build_prediction_by_left_pred(
|
|||
int bh = (left_mi_height << MI_SIZE_LOG2) >> pd->subsampling_y;
|
||||
|
||||
if (av1_skip_u4x4_pred_in_obmc(bsize, pd, 1)) continue;
|
||||
build_inter_predictors(ctxt->cm, xd, j, left_mbmi, 1, bw, bh, mi_x, mi_y);
|
||||
build_inter_predictors(ctxt->cm, xd, j, &backup_mbmi, 1, bw, bh, mi_x,
|
||||
mi_y);
|
||||
}
|
||||
*left_mbmi = backup_mbmi;
|
||||
}
|
||||
|
||||
void av1_build_prediction_by_left_preds(const AV1_COMMON *cm, MACROBLOCKD *xd,
|
||||
|
|
@ -451,7 +427,7 @@ void av1_build_obmc_inter_predictors_sb(const AV1_COMMON *cm, MACROBLOCKD *xd,
|
|||
int dst_height1[MAX_MB_PLANE] = { MAX_SB_SIZE, MAX_SB_SIZE, MAX_SB_SIZE };
|
||||
int dst_height2[MAX_MB_PLANE] = { MAX_SB_SIZE, MAX_SB_SIZE, MAX_SB_SIZE };
|
||||
|
||||
if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) {
|
||||
if (is_cur_buf_hbd(xd)) {
|
||||
int len = sizeof(uint16_t);
|
||||
dst_buf1[0] = CONVERT_TO_BYTEPTR(xd->tmp_obmc_bufs[0]);
|
||||
dst_buf1[1] =
|
||||
|
|
@ -475,7 +451,7 @@ void av1_build_obmc_inter_predictors_sb(const AV1_COMMON *cm, MACROBLOCKD *xd,
|
|||
dst_width1, dst_height1, dst_stride1);
|
||||
av1_build_prediction_by_left_preds(cm, xd, mi_row, mi_col, dst_buf2,
|
||||
dst_width2, dst_height2, dst_stride2);
|
||||
av1_setup_dst_planes(xd->plane, xd->mi[0]->sb_type, get_frame_new_buffer(cm),
|
||||
av1_setup_dst_planes(xd->plane, xd->mi[0]->sb_type, &cm->cur_frame->buf,
|
||||
mi_row, mi_col, 0, num_planes);
|
||||
av1_build_obmc_inter_prediction(cm, xd, mi_row, mi_col, dst_buf1, dst_stride1,
|
||||
dst_buf2, dst_stride2);
|
||||
|
|
@ -492,7 +468,7 @@ static void build_inter_predictors_single_buf(MACROBLOCKD *xd, int plane,
|
|||
struct macroblockd_plane *const pd = &xd->plane[plane];
|
||||
const MB_MODE_INFO *mi = xd->mi[0];
|
||||
|
||||
const struct scale_factors *const sf = &xd->block_refs[ref]->sf;
|
||||
const struct scale_factors *const sf = xd->block_ref_scale_factors[ref];
|
||||
struct buf_2d *const pre_buf = &pd->pre[ref];
|
||||
uint8_t *const dst = get_buf_by_bd(xd, ext_dst) + ext_dst_stride * y + x;
|
||||
const MV mv = mi->mv[ref].as_mv;
|
||||
|
|
@ -574,37 +550,41 @@ static void build_wedge_inter_predictor_from_buf(
|
|||
uint8_t *const dst = dst_buf->buf + dst_buf->stride * y + x;
|
||||
mbmi->interinter_comp.seg_mask = xd->seg_mask;
|
||||
const INTERINTER_COMPOUND_DATA *comp_data = &mbmi->interinter_comp;
|
||||
const int is_hbd = is_cur_buf_hbd(xd);
|
||||
|
||||
if (is_compound && is_masked_compound_type(comp_data->type)) {
|
||||
if (!plane && comp_data->type == COMPOUND_DIFFWTD) {
|
||||
if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH)
|
||||
if (is_hbd) {
|
||||
av1_build_compound_diffwtd_mask_highbd(
|
||||
comp_data->seg_mask, comp_data->mask_type,
|
||||
CONVERT_TO_BYTEPTR(ext_dst0), ext_dst_stride0,
|
||||
CONVERT_TO_BYTEPTR(ext_dst1), ext_dst_stride1, h, w, xd->bd);
|
||||
else
|
||||
} else {
|
||||
av1_build_compound_diffwtd_mask(
|
||||
comp_data->seg_mask, comp_data->mask_type, ext_dst0,
|
||||
ext_dst_stride0, ext_dst1, ext_dst_stride1, h, w);
|
||||
}
|
||||
}
|
||||
|
||||
if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH)
|
||||
if (is_hbd) {
|
||||
build_masked_compound_highbd(
|
||||
dst, dst_buf->stride, CONVERT_TO_BYTEPTR(ext_dst0), ext_dst_stride0,
|
||||
CONVERT_TO_BYTEPTR(ext_dst1), ext_dst_stride1, comp_data,
|
||||
mbmi->sb_type, h, w, xd->bd);
|
||||
else
|
||||
} else {
|
||||
build_masked_compound(dst, dst_buf->stride, ext_dst0, ext_dst_stride0,
|
||||
ext_dst1, ext_dst_stride1, comp_data, mbmi->sb_type,
|
||||
h, w);
|
||||
}
|
||||
} else {
|
||||
if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH)
|
||||
if (is_hbd) {
|
||||
aom_highbd_convolve_copy(CONVERT_TO_BYTEPTR(ext_dst0), ext_dst_stride0,
|
||||
dst, dst_buf->stride, NULL, 0, NULL, 0, w, h,
|
||||
xd->bd);
|
||||
else
|
||||
} else {
|
||||
aom_convolve_copy(ext_dst0, ext_dst_stride0, dst, dst_buf->stride, NULL,
|
||||
0, NULL, 0, w, h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
21
third_party/aom/av1/encoder/reconinter_enc.h
vendored
21
third_party/aom/av1/encoder/reconinter_enc.h
vendored
|
|
@ -23,21 +23,10 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
void av1_build_inter_predictors_sby(const AV1_COMMON *cm, MACROBLOCKD *xd,
|
||||
int mi_row, int mi_col, BUFFER_SET *ctx,
|
||||
BLOCK_SIZE bsize);
|
||||
|
||||
void av1_build_inter_predictors_sbuv(const AV1_COMMON *cm, MACROBLOCKD *xd,
|
||||
int mi_row, int mi_col, BUFFER_SET *ctx,
|
||||
BLOCK_SIZE bsize);
|
||||
|
||||
void av1_build_inter_predictors_sbp(const AV1_COMMON *cm, MACROBLOCKD *xd,
|
||||
int mi_row, int mi_col, BUFFER_SET *ctx,
|
||||
BLOCK_SIZE bsize, int plane_idx);
|
||||
|
||||
void av1_build_inter_predictors_sb(const AV1_COMMON *cm, MACROBLOCKD *xd,
|
||||
int mi_row, int mi_col, BUFFER_SET *ctx,
|
||||
BLOCK_SIZE bsize);
|
||||
void av1_enc_build_inter_predictor(const AV1_COMMON *cm, MACROBLOCKD *xd,
|
||||
int mi_row, int mi_col,
|
||||
const BUFFER_SET *ctx, BLOCK_SIZE bsize,
|
||||
int plane_from, int plane_to);
|
||||
|
||||
void av1_build_inter_predictor(const uint8_t *src, int src_stride, uint8_t *dst,
|
||||
int dst_stride, const MV *src_mv,
|
||||
|
|
@ -46,7 +35,7 @@ void av1_build_inter_predictor(const uint8_t *src, int src_stride, uint8_t *dst,
|
|||
InterpFilters interp_filters,
|
||||
const WarpTypesAllowed *warp_types, int p_col,
|
||||
int p_row, int plane, int ref,
|
||||
enum mv_precision precision, int x, int y,
|
||||
mv_precision precision, int x, int y,
|
||||
const MACROBLOCKD *xd, int can_use_previous);
|
||||
|
||||
// Detect if the block have sub-pixel level motion vectors
|
||||
|
|
|
|||
2
third_party/aom/av1/encoder/segmentation.c
vendored
2
third_party/aom/av1/encoder/segmentation.c
vendored
|
|
@ -62,7 +62,7 @@ static void count_segs(const AV1_COMMON *cm, MACROBLOCKD *xd,
|
|||
no_pred_segcounts[segment_id]++;
|
||||
|
||||
// Temporal prediction not allowed on key frames
|
||||
if (cm->frame_type != KEY_FRAME) {
|
||||
if (cm->current_frame.frame_type != KEY_FRAME) {
|
||||
const BLOCK_SIZE bsize = xd->mi[0]->sb_type;
|
||||
// Test to see if the segment id matches the predicted value.
|
||||
const int pred_segment_id =
|
||||
|
|
|
|||
226
third_party/aom/av1/encoder/speed_features.c
vendored
226
third_party/aom/av1/encoder/speed_features.c
vendored
|
|
@ -24,6 +24,8 @@
|
|||
#define DISABLE_TRELLISQ_SEARCH 0
|
||||
|
||||
#define MAX_MESH_SPEED 5 // Max speed setting for mesh motion method
|
||||
// Max speed setting for tx domain evaluation
|
||||
#define MAX_TX_DOMAIN_EVAL_SPEED 5
|
||||
static MESH_PATTERN
|
||||
good_quality_mesh_patterns[MAX_MESH_SPEED + 1][MAX_MESH_STEP] = {
|
||||
{ { 64, 8 }, { 28, 4 }, { 15, 1 }, { 7, 1 } },
|
||||
|
|
@ -50,6 +52,22 @@ static MESH_PATTERN intrabc_mesh_patterns[MAX_MESH_SPEED + 1][MAX_MESH_STEP] = {
|
|||
static uint8_t intrabc_max_mesh_pct[MAX_MESH_SPEED + 1] = { 100, 100, 100,
|
||||
25, 25, 10 };
|
||||
|
||||
// Threshold values to be used for pruning the txfm_domain_distortion
|
||||
// based on block MSE
|
||||
// TODO(any): Experiment the threshold logic based on variance metric
|
||||
static unsigned int tx_domain_dist_thresholds[MAX_TX_DOMAIN_EVAL_SPEED + 1] = {
|
||||
UINT_MAX, 162754, 22026, 22026, 22026, 0
|
||||
};
|
||||
// Threshold values to be used for disabling coeff RD-optimization
|
||||
// based on block MSE
|
||||
// TODO(any): Experiment the threshold logic based on variance metric
|
||||
static unsigned int coeff_opt_dist_thresholds[5] = { UINT_MAX, 162754, 162754,
|
||||
22026, 22026 };
|
||||
// scaling values to be used for gating wedge/compound segment based on best
|
||||
// approximate rd
|
||||
static int comp_type_rd_threshold_mul[3] = { 1, 11, 12 };
|
||||
static int comp_type_rd_threshold_div[3] = { 3, 16, 16 };
|
||||
|
||||
// Intra only frames, golden frames (except alt ref overlays) and
|
||||
// alt ref frames tend to be coded at a higher than ambient quality
|
||||
static int frame_is_boosted(const AV1_COMP *cpi) {
|
||||
|
|
@ -62,7 +80,7 @@ static int frame_is_boosted(const AV1_COMP *cpi) {
|
|||
// partly on the screen area that over which they propogate. Propogation is
|
||||
// limited by transform block size but the screen area take up by a given block
|
||||
// size will be larger for a small image format stretched to full screen.
|
||||
static BLOCK_SIZE set_partition_min_limit(AV1_COMMON *const cm) {
|
||||
static BLOCK_SIZE set_partition_min_limit(const AV1_COMMON *const cm) {
|
||||
unsigned int screen_area = (cm->width * cm->height);
|
||||
|
||||
// Select block size based on image format size.
|
||||
|
|
@ -85,10 +103,9 @@ static int has_internal_image_edge(const AV1_COMP *cpi) {
|
|||
(cpi->twopass.this_frame_stats.inactive_zone_cols > 0));
|
||||
}
|
||||
|
||||
static void set_good_speed_feature_framesize_dependent(AV1_COMP *cpi,
|
||||
SPEED_FEATURES *sf,
|
||||
int speed) {
|
||||
AV1_COMMON *const cm = &cpi->common;
|
||||
static void set_good_speed_feature_framesize_dependent(
|
||||
const AV1_COMP *const cpi, SPEED_FEATURES *const sf, int speed) {
|
||||
const AV1_COMMON *const cm = &cpi->common;
|
||||
const int is_720p_or_larger = AOMMIN(cm->width, cm->height) >= 720;
|
||||
const int is_480p_or_larger = AOMMIN(cm->width, cm->height) >= 480;
|
||||
|
||||
|
|
@ -126,6 +143,17 @@ static void set_good_speed_feature_framesize_dependent(AV1_COMP *cpi,
|
|||
}
|
||||
|
||||
if (speed >= 2) {
|
||||
if (is_720p_or_larger) {
|
||||
sf->use_square_partition_only_threshold = BLOCK_64X64;
|
||||
} else if (is_480p_or_larger) {
|
||||
sf->use_square_partition_only_threshold = BLOCK_32X32;
|
||||
} else {
|
||||
// TODO(chiyotsai@google.com): Setting the threshold to BLOCK_16X16 incurs
|
||||
// a large loss (about 0.584%). Try increasing the threshold on boosted
|
||||
// frame and see if it improves the performance.
|
||||
sf->use_square_partition_only_threshold = BLOCK_32X32;
|
||||
}
|
||||
|
||||
if (is_720p_or_larger) {
|
||||
sf->disable_split_mask =
|
||||
cm->show_frame ? DISABLE_ALL_SPLIT : DISABLE_ALL_INTER_SPLIT;
|
||||
|
|
@ -172,11 +200,12 @@ static void set_good_speed_feature_framesize_dependent(AV1_COMP *cpi,
|
|||
}
|
||||
}
|
||||
|
||||
static void set_good_speed_features_framesize_independent(AV1_COMP *cpi,
|
||||
SPEED_FEATURES *sf,
|
||||
int speed) {
|
||||
AV1_COMMON *const cm = &cpi->common;
|
||||
static void set_good_speed_features_framesize_independent(
|
||||
const AV1_COMP *const cpi, SPEED_FEATURES *const sf, int speed) {
|
||||
const AV1_COMMON *const cm = &cpi->common;
|
||||
const int boosted = frame_is_boosted(cpi);
|
||||
const int is_boosted_arf2_bwd_type =
|
||||
boosted || cpi->refresh_bwd_ref_frame || cpi->refresh_alt2_ref_frame;
|
||||
|
||||
// Speed 0 for all speed features that give neutral coding performance change.
|
||||
sf->reduce_inter_modes = 1;
|
||||
|
|
@ -184,54 +213,79 @@ static void set_good_speed_features_framesize_independent(AV1_COMP *cpi,
|
|||
sf->ml_prune_rect_partition = 1;
|
||||
sf->ml_prune_ab_partition = 1;
|
||||
sf->ml_prune_4_partition = 1;
|
||||
sf->simple_motion_search_prune_rect = 1;
|
||||
sf->adaptive_txb_search_level = 1;
|
||||
sf->jnt_comp_skip_mv_search = 1;
|
||||
sf->use_dist_wtd_comp_flag = DIST_WTD_COMP_SKIP_MV_SEARCH;
|
||||
sf->model_based_prune_tx_search_level = 1;
|
||||
sf->model_based_post_interp_filter_breakout = 1;
|
||||
sf->model_based_motion_mode_rd_breakout = 1;
|
||||
|
||||
// TODO(debargha): Test, tweak and turn on either 1 or 2
|
||||
sf->inter_mode_rd_model_estimation = 1;
|
||||
sf->prune_ref_frame_for_rect_partitions =
|
||||
!(boosted || cpi->refresh_bwd_ref_frame || cpi->refresh_alt2_ref_frame);
|
||||
|
||||
sf->prune_ref_frame_for_rect_partitions = !is_boosted_arf2_bwd_type;
|
||||
sf->prune_ref_mode_for_partitions = sf->prune_ref_frame_for_rect_partitions;
|
||||
sf->less_rectangular_check_level = 1;
|
||||
sf->gm_search_type = GM_REDUCED_REF_SEARCH;
|
||||
sf->gm_search_type = GM_REDUCED_REF_SEARCH_SKIP_L2_L3;
|
||||
sf->gm_disable_recode = 1;
|
||||
sf->use_fast_interpolation_filter_search = 1;
|
||||
sf->intra_tx_size_search_init_depth_sqr = 1;
|
||||
sf->intra_angle_estimation = 1;
|
||||
sf->selective_ref_frame = 1;
|
||||
sf->prune_wedge_pred_diff_based = 1;
|
||||
sf->disable_wedge_search_var_thresh = 0;
|
||||
sf->disable_wedge_search_edge_thresh = 0;
|
||||
sf->prune_motion_mode_level = 1;
|
||||
sf->cb_pred_filter_search = 0;
|
||||
|
||||
if (speed >= 1) {
|
||||
sf->gm_erroradv_type = GM_ERRORADV_TR_1;
|
||||
sf->selective_ref_frame = 1;
|
||||
sf->selective_ref_frame = 2;
|
||||
|
||||
sf->inter_tx_size_search_init_depth_rect = 1;
|
||||
sf->inter_tx_size_search_init_depth_sqr = 1;
|
||||
sf->intra_tx_size_search_init_depth_rect = 1;
|
||||
sf->intra_tx_size_search_init_depth_sqr = 1;
|
||||
sf->tx_size_search_lgr_block = 1;
|
||||
if (speed >= CONFIG_2PASS_PARTITION_SEARCH_LVL) {
|
||||
sf->two_pass_partition_search = 1;
|
||||
sf->mode_pruning_based_on_two_pass_partition_search = 1;
|
||||
}
|
||||
sf->prune_ext_partition_types_search_level = 2;
|
||||
sf->use_fast_interpolation_filter_search = 1;
|
||||
sf->skip_repeat_interpolation_filter_search = 1;
|
||||
sf->tx_type_search.skip_tx_search = 1;
|
||||
sf->tx_type_search.ml_tx_split_thresh = 40;
|
||||
sf->model_based_prune_tx_search_level = 0;
|
||||
sf->model_based_post_interp_filter_breakout = 0;
|
||||
// TODO(angiebird): Re-evaluate the impact of inter_mode_rd_model_estimation
|
||||
// on speed 1
|
||||
sf->inter_mode_rd_model_estimation = 0;
|
||||
sf->adaptive_txb_search_level = 2;
|
||||
sf->use_intra_txb_hash = 1;
|
||||
sf->optimize_b_precheck = 1;
|
||||
sf->dual_sgr_penalty_level = 1;
|
||||
sf->use_accurate_subpel_search = 1;
|
||||
sf->use_accurate_subpel_search = USE_4_TAPS;
|
||||
sf->reuse_inter_intra_mode = 1;
|
||||
sf->prune_comp_search_by_single_result = 1;
|
||||
sf->skip_repeated_newmv = 1;
|
||||
sf->obmc_full_pixel_search_level = 1;
|
||||
// TODO(anyone): Following speed feature will be further explored to
|
||||
// identify the appropriate tradeoff between encoder performance and its
|
||||
// speed.
|
||||
sf->prune_single_motion_modes_by_simple_trans = 1;
|
||||
|
||||
sf->simple_motion_search_split_only = 1;
|
||||
|
||||
sf->disable_wedge_search_var_thresh = 0;
|
||||
sf->disable_wedge_search_edge_thresh = 0;
|
||||
sf->disable_interinter_wedge_newmv_search = boosted ? 0 : 1;
|
||||
sf->prune_comp_type_by_comp_avg = 1;
|
||||
sf->prune_motion_mode_level = 2;
|
||||
sf->gm_search_type = GM_REDUCED_REF_SEARCH_SKIP_L2_L3_ARF2;
|
||||
sf->cb_pred_filter_search = 1;
|
||||
sf->use_transform_domain_distortion = boosted ? 0 : 1;
|
||||
sf->perform_coeff_opt = boosted ? 0 : 1;
|
||||
}
|
||||
|
||||
if (speed >= 2) {
|
||||
sf->gm_erroradv_type = GM_ERRORADV_TR_2;
|
||||
|
||||
sf->selective_ref_frame = 2;
|
||||
sf->selective_ref_frame = 3;
|
||||
sf->fast_cdef_search = 1;
|
||||
|
||||
sf->adaptive_rd_thresh = 1;
|
||||
|
|
@ -246,10 +300,19 @@ static void set_good_speed_features_framesize_independent(AV1_COMP *cpi,
|
|||
// sf->auto_min_max_partition_size = RELAXED_NEIGHBORING_MIN_MAX;
|
||||
sf->allow_partition_search_skip = 1;
|
||||
sf->disable_wedge_search_var_thresh = 100;
|
||||
sf->disable_wedge_search_edge_thresh = 0;
|
||||
sf->disable_interinter_wedge_newmv_search = 1;
|
||||
sf->fast_wedge_sign_estimate = 1;
|
||||
sf->disable_dual_filter = 1;
|
||||
sf->use_dist_wtd_comp_flag = DIST_WTD_COMP_DISABLED;
|
||||
sf->prune_comp_type_by_comp_avg = 2;
|
||||
sf->cb_pred_filter_search = 0;
|
||||
sf->adaptive_interp_filter_search = 1;
|
||||
sf->perform_coeff_opt = boosted ? 0 : 2;
|
||||
}
|
||||
|
||||
if (speed >= 3) {
|
||||
sf->selective_ref_frame = 4;
|
||||
sf->tx_size_search_method = boosted ? USE_FULL_RD : USE_LARGESTALL;
|
||||
sf->less_rectangular_check_level = 2;
|
||||
sf->adaptive_pred_interp_filter = 1;
|
||||
|
|
@ -258,26 +321,33 @@ static void set_good_speed_features_framesize_independent(AV1_COMP *cpi,
|
|||
// See aomedia:1778.
|
||||
// sf->adaptive_motion_search = 1;
|
||||
sf->recode_loop = ALLOW_RECODE_KFARFGF;
|
||||
sf->use_transform_domain_distortion = 1;
|
||||
sf->use_accurate_subpel_search = 0;
|
||||
sf->use_transform_domain_distortion = boosted ? 1 : 2;
|
||||
sf->use_accurate_subpel_search = USE_2_TAPS;
|
||||
sf->adaptive_rd_thresh = 2;
|
||||
sf->tx_type_search.prune_mode = PRUNE_2D_FAST;
|
||||
sf->gm_search_type = GM_DISABLE_SEARCH;
|
||||
sf->prune_comp_search_by_single_result = 2;
|
||||
sf->prune_motion_mode_level = boosted ? 2 : 3;
|
||||
sf->prune_warp_using_wmtype = 1;
|
||||
// TODO(yunqing): evaluate this speed feature for speed 1 & 2, and combine
|
||||
// it with cpi->sf.disable_wedge_search_var_thresh.
|
||||
sf->disable_wedge_interintra_search = 1;
|
||||
sf->perform_coeff_opt = is_boosted_arf2_bwd_type ? 2 : 3;
|
||||
}
|
||||
|
||||
if (speed >= 4) {
|
||||
sf->use_intra_txb_hash = 0;
|
||||
sf->tx_type_search.fast_intra_tx_type_search = 1;
|
||||
sf->tx_type_search.fast_inter_tx_type_search = 1;
|
||||
sf->use_square_partition_only_threshold =
|
||||
boosted ? BLOCK_128X128 : BLOCK_4X4;
|
||||
sf->tx_size_search_method =
|
||||
frame_is_intra_only(cm) ? USE_FULL_RD : USE_LARGESTALL;
|
||||
sf->mv.subpel_search_method = SUBPEL_TREE_PRUNED;
|
||||
sf->adaptive_pred_interp_filter = 0;
|
||||
sf->adaptive_mode_search = 1;
|
||||
sf->cb_partition_search = !boosted;
|
||||
sf->alt_ref_search_fp = 1;
|
||||
sf->skip_sharp_interp_filter_search = 1;
|
||||
sf->perform_coeff_opt = is_boosted_arf2_bwd_type ? 2 : 4;
|
||||
sf->adaptive_txb_search_level = boosted ? 2 : 3;
|
||||
}
|
||||
|
||||
if (speed >= 5) {
|
||||
|
|
@ -294,7 +364,7 @@ static void set_good_speed_features_framesize_independent(AV1_COMP *cpi,
|
|||
sf->mv.subpel_search_method = SUBPEL_TREE_PRUNED_MORE;
|
||||
sf->adaptive_rd_thresh = 4;
|
||||
sf->mode_search_skip_flags =
|
||||
(cm->frame_type == KEY_FRAME)
|
||||
(cm->current_frame.frame_type == KEY_FRAME)
|
||||
? 0
|
||||
: FLAG_SKIP_INTRA_DIRMISMATCH | FLAG_SKIP_INTRA_BESTINTER |
|
||||
FLAG_SKIP_COMP_BESTINTRA | FLAG_SKIP_INTRA_LOWVAR |
|
||||
|
|
@ -327,35 +397,28 @@ static void set_good_speed_features_framesize_independent(AV1_COMP *cpi,
|
|||
sf->mv.search_method = FAST_HEX;
|
||||
sf->partition_search_type = REFERENCE_PARTITION;
|
||||
sf->mode_search_skip_flags |= FLAG_SKIP_INTRA_DIRMISMATCH;
|
||||
// TODO(any): evaluate adaptive_mode_search=1 for speed 7 & 8
|
||||
sf->adaptive_mode_search = 2;
|
||||
}
|
||||
if (speed >= 8) {
|
||||
sf->mv.search_method = FAST_DIAMOND;
|
||||
sf->mv.subpel_force_stop = 2;
|
||||
sf->mv.subpel_force_stop = HALF_PEL;
|
||||
sf->lpf_pick = LPF_PICK_MINIMAL_LPF;
|
||||
}
|
||||
}
|
||||
|
||||
void av1_set_speed_features_framesize_dependent(AV1_COMP *cpi) {
|
||||
void av1_set_speed_features_framesize_dependent(AV1_COMP *cpi, int speed) {
|
||||
SPEED_FEATURES *const sf = &cpi->sf;
|
||||
const AV1EncoderConfig *const oxcf = &cpi->oxcf;
|
||||
RD_OPT *const rd = &cpi->rd;
|
||||
int i;
|
||||
|
||||
if (oxcf->mode == GOOD) {
|
||||
set_good_speed_feature_framesize_dependent(cpi, sf, oxcf->speed);
|
||||
set_good_speed_feature_framesize_dependent(cpi, sf, speed);
|
||||
}
|
||||
|
||||
if (sf->disable_split_mask == DISABLE_ALL_SPLIT) {
|
||||
sf->adaptive_pred_interp_filter = 0;
|
||||
}
|
||||
|
||||
// Check for masked out split cases.
|
||||
for (i = 0; i < MAX_REFS; ++i) {
|
||||
if (sf->disable_split_mask & (1 << i)) {
|
||||
rd->thresh_mult_sub8x8[i] = INT_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
// This is only used in motion vector unit test.
|
||||
if (cpi->oxcf.motion_vector_unit_test == 1)
|
||||
cpi->find_fractional_mv_step = av1_return_max_sub_pixel_mv;
|
||||
|
|
@ -363,7 +426,7 @@ void av1_set_speed_features_framesize_dependent(AV1_COMP *cpi) {
|
|||
cpi->find_fractional_mv_step = av1_return_min_sub_pixel_mv;
|
||||
}
|
||||
|
||||
void av1_set_speed_features_framesize_independent(AV1_COMP *cpi) {
|
||||
void av1_set_speed_features_framesize_independent(AV1_COMP *cpi, int speed) {
|
||||
AV1_COMMON *const cm = &cpi->common;
|
||||
SPEED_FEATURES *const sf = &cpi->sf;
|
||||
MACROBLOCK *const x = &cpi->td.mb;
|
||||
|
|
@ -376,7 +439,7 @@ void av1_set_speed_features_framesize_independent(AV1_COMP *cpi) {
|
|||
sf->recode_loop = ALLOW_RECODE;
|
||||
sf->mv.subpel_search_method = SUBPEL_TREE;
|
||||
sf->mv.subpel_iters_per_step = 2;
|
||||
sf->mv.subpel_force_stop = 0;
|
||||
sf->mv.subpel_force_stop = EIGHTH_PEL;
|
||||
#if DISABLE_TRELLISQ_SEARCH == 2
|
||||
sf->optimize_coefficients = !is_lossless_requested(&cpi->oxcf)
|
||||
? FINAL_PASS_TRELLIS_OPT
|
||||
|
|
@ -402,6 +465,7 @@ void av1_set_speed_features_framesize_independent(AV1_COMP *cpi) {
|
|||
sf->tx_size_search_lgr_block = 0;
|
||||
sf->model_based_prune_tx_search_level = 0;
|
||||
sf->model_based_post_interp_filter_breakout = 0;
|
||||
sf->model_based_motion_mode_rd_breakout = 0;
|
||||
sf->reduce_inter_modes = 0;
|
||||
sf->selective_ref_gm = 1;
|
||||
sf->adaptive_motion_search = 0;
|
||||
|
|
@ -420,6 +484,7 @@ void av1_set_speed_features_framesize_independent(AV1_COMP *cpi) {
|
|||
sf->less_rectangular_check_level = 0;
|
||||
sf->use_square_partition_only_threshold = BLOCK_128X128;
|
||||
sf->prune_ref_frame_for_rect_partitions = 0;
|
||||
sf->prune_ref_mode_for_partitions = 0;
|
||||
sf->auto_min_max_partition_size = NOT_IN_USE;
|
||||
sf->rd_auto_partition_min_limit = BLOCK_4X4;
|
||||
sf->default_max_partition_size = BLOCK_LARGEST;
|
||||
|
|
@ -429,9 +494,11 @@ void av1_set_speed_features_framesize_independent(AV1_COMP *cpi) {
|
|||
sf->mode_search_skip_flags = 0;
|
||||
sf->disable_filter_search_var_thresh = 0;
|
||||
sf->allow_partition_search_skip = 0;
|
||||
sf->use_accurate_subpel_search = 2;
|
||||
sf->use_accurate_subpel_search = USE_8_TAPS;
|
||||
sf->disable_wedge_search_edge_thresh = 0;
|
||||
sf->disable_wedge_search_var_thresh = 0;
|
||||
sf->fast_wedge_sign_estimate = 0;
|
||||
sf->prune_wedge_pred_diff_based = 0;
|
||||
sf->drop_ref = 0;
|
||||
sf->skip_intra_in_interframe = 1;
|
||||
sf->txb_split_cap = 1;
|
||||
|
|
@ -439,12 +506,17 @@ void av1_set_speed_features_framesize_independent(AV1_COMP *cpi) {
|
|||
sf->two_pass_partition_search = 0;
|
||||
sf->mode_pruning_based_on_two_pass_partition_search = 0;
|
||||
sf->use_intra_txb_hash = 0;
|
||||
sf->use_inter_txb_hash = 1;
|
||||
// TODO(any) : clean use_inter_txb_hash code
|
||||
sf->use_inter_txb_hash = 0;
|
||||
sf->use_mb_rd_hash = 1;
|
||||
sf->optimize_b_precheck = 0;
|
||||
sf->jnt_comp_fast_tx_search = 0;
|
||||
sf->jnt_comp_skip_mv_search = 0;
|
||||
sf->dist_wtd_comp_fast_tx_search = 0;
|
||||
sf->use_dist_wtd_comp_flag = DIST_WTD_COMP_ENABLED;
|
||||
sf->reuse_inter_intra_mode = 0;
|
||||
sf->intra_angle_estimation = 0;
|
||||
sf->skip_obmc_in_uniform_mv_field = 0;
|
||||
sf->skip_wm_in_uniform_mv_field = 0;
|
||||
sf->adaptive_interp_filter_search = 0;
|
||||
|
||||
for (i = 0; i < TX_SIZES; i++) {
|
||||
sf->intra_y_mode_mask[i] = INTRA_ALL;
|
||||
|
|
@ -466,27 +538,48 @@ void av1_set_speed_features_framesize_independent(AV1_COMP *cpi) {
|
|||
sf->ml_prune_ab_partition = 0;
|
||||
sf->ml_prune_4_partition = 0;
|
||||
sf->fast_cdef_search = 0;
|
||||
for (i = 0; i < PARTITION_BLOCK_SIZES; ++i)
|
||||
for (i = 0; i < PARTITION_BLOCK_SIZES; ++i) {
|
||||
sf->ml_partition_search_breakout_thresh[i] = -1; // -1 means not enabled.
|
||||
}
|
||||
sf->simple_motion_search_split_only = 0;
|
||||
sf->simple_motion_search_prune_rect = 0;
|
||||
|
||||
// Set this at the appropriate speed levels
|
||||
sf->use_transform_domain_distortion = 0;
|
||||
sf->gm_search_type = GM_FULL_SEARCH;
|
||||
sf->gm_disable_recode = 0;
|
||||
sf->use_fast_interpolation_filter_search = 0;
|
||||
sf->disable_dual_filter = 0;
|
||||
sf->skip_repeat_interpolation_filter_search = 0;
|
||||
sf->use_hash_based_trellis = 0;
|
||||
sf->prune_comp_search_by_single_result = 0;
|
||||
sf->skip_repeated_newmv = 0;
|
||||
sf->prune_single_motion_modes_by_simple_trans = 0;
|
||||
|
||||
// Set decoder side speed feature to use less dual sgr modes
|
||||
sf->dual_sgr_penalty_level = 0;
|
||||
|
||||
// TODO(angiebird, debargha): Re-evaluate the impact of
|
||||
// inter_mode_rd_model_estimation in conjunction with
|
||||
// model_based_motion_mode_rd_breakout
|
||||
sf->inter_mode_rd_model_estimation = 0;
|
||||
|
||||
sf->obmc_full_pixel_search_level = 0;
|
||||
sf->skip_sharp_interp_filter_search = 0;
|
||||
sf->prune_comp_type_by_comp_avg = 0;
|
||||
sf->disable_interinter_wedge_newmv_search = 0;
|
||||
sf->prune_motion_mode_level = 0;
|
||||
sf->prune_warp_using_wmtype = 0;
|
||||
|
||||
sf->disable_wedge_interintra_search = 0;
|
||||
sf->perform_coeff_opt = 0;
|
||||
|
||||
if (oxcf->mode == GOOD)
|
||||
set_good_speed_features_framesize_independent(cpi, sf, oxcf->speed);
|
||||
set_good_speed_features_framesize_independent(cpi, sf, speed);
|
||||
|
||||
if (!cpi->seq_params_locked) {
|
||||
cpi->common.seq_params.enable_dual_filter &= !sf->disable_dual_filter;
|
||||
}
|
||||
|
||||
// sf->partition_search_breakout_dist_thr is set assuming max 64x64
|
||||
// blocks. Normalise this if the blocks are bigger.
|
||||
|
|
@ -497,28 +590,31 @@ void av1_set_speed_features_framesize_independent(AV1_COMP *cpi) {
|
|||
cpi->diamond_search_sad = av1_diamond_search_sad;
|
||||
|
||||
sf->allow_exhaustive_searches = 1;
|
||||
int speed = (oxcf->speed > MAX_MESH_SPEED) ? MAX_MESH_SPEED : oxcf->speed;
|
||||
|
||||
const int mesh_speed = AOMMIN(speed, MAX_MESH_SPEED);
|
||||
if (cpi->twopass.fr_content_type == FC_GRAPHICS_ANIMATION)
|
||||
sf->exhaustive_searches_thresh = (1 << 24);
|
||||
else
|
||||
sf->exhaustive_searches_thresh = (1 << 25);
|
||||
sf->max_exaustive_pct = good_quality_max_mesh_pct[speed];
|
||||
if (speed > 0)
|
||||
sf->max_exaustive_pct = good_quality_max_mesh_pct[mesh_speed];
|
||||
if (mesh_speed > 0)
|
||||
sf->exhaustive_searches_thresh = sf->exhaustive_searches_thresh << 1;
|
||||
|
||||
for (i = 0; i < MAX_MESH_STEP; ++i) {
|
||||
sf->mesh_patterns[i].range = good_quality_mesh_patterns[speed][i].range;
|
||||
sf->mesh_patterns[i].range =
|
||||
good_quality_mesh_patterns[mesh_speed][i].range;
|
||||
sf->mesh_patterns[i].interval =
|
||||
good_quality_mesh_patterns[speed][i].interval;
|
||||
good_quality_mesh_patterns[mesh_speed][i].interval;
|
||||
}
|
||||
if ((frame_is_intra_only(cm) && cm->allow_screen_content_tools) &&
|
||||
(cpi->twopass.fr_content_type == FC_GRAPHICS_ANIMATION ||
|
||||
cpi->oxcf.content == AOM_CONTENT_SCREEN)) {
|
||||
for (i = 0; i < MAX_MESH_STEP; ++i) {
|
||||
sf->mesh_patterns[i].range = intrabc_mesh_patterns[speed][i].range;
|
||||
sf->mesh_patterns[i].interval = intrabc_mesh_patterns[speed][i].interval;
|
||||
sf->mesh_patterns[i].range = intrabc_mesh_patterns[mesh_speed][i].range;
|
||||
sf->mesh_patterns[i].interval =
|
||||
intrabc_mesh_patterns[mesh_speed][i].interval;
|
||||
}
|
||||
sf->max_exaustive_pct = intrabc_max_mesh_pct[speed];
|
||||
sf->max_exaustive_pct = intrabc_max_mesh_pct[mesh_speed];
|
||||
}
|
||||
|
||||
// Slow quant, dct and trellis not worthwhile for first pass
|
||||
|
|
@ -544,7 +640,7 @@ void av1_set_speed_features_framesize_independent(AV1_COMP *cpi) {
|
|||
cpi->optimize_speed_feature =
|
||||
oxcf->pass != 1 ? sf->optimize_coefficients : NO_TRELLIS_OPT;
|
||||
// FIXME: trellis not very efficient for quantisation matrices
|
||||
if (cm->using_qmatrix) cpi->optimize_speed_feature = NO_TRELLIS_OPT;
|
||||
if (oxcf->using_qm) cpi->optimize_speed_feature = NO_TRELLIS_OPT;
|
||||
if (oxcf->disable_trellis_quant) cpi->optimize_speed_feature = NO_TRELLIS_OPT;
|
||||
|
||||
x->min_partition_size = sf->default_min_partition_size;
|
||||
|
|
@ -555,10 +651,26 @@ void av1_set_speed_features_framesize_independent(AV1_COMP *cpi) {
|
|||
cpi->find_fractional_mv_step = av1_return_max_sub_pixel_mv;
|
||||
else if (cpi->oxcf.motion_vector_unit_test == 2)
|
||||
cpi->find_fractional_mv_step = av1_return_min_sub_pixel_mv;
|
||||
cpi->max_comp_type_rd_threshold_mul =
|
||||
comp_type_rd_threshold_mul[sf->prune_comp_type_by_comp_avg];
|
||||
cpi->max_comp_type_rd_threshold_div =
|
||||
comp_type_rd_threshold_div[sf->prune_comp_type_by_comp_avg];
|
||||
const int tx_domain_speed = AOMMIN(speed, MAX_TX_DOMAIN_EVAL_SPEED);
|
||||
cpi->tx_domain_dist_threshold = tx_domain_dist_thresholds[tx_domain_speed];
|
||||
|
||||
// assert ensures that coeff_opt_dist_thresholds is accessed correctly
|
||||
assert(cpi->sf.perform_coeff_opt >= 0 && cpi->sf.perform_coeff_opt < 5);
|
||||
cpi->coeff_opt_dist_threshold =
|
||||
coeff_opt_dist_thresholds[cpi->sf.perform_coeff_opt];
|
||||
|
||||
#if CONFIG_DIST_8X8
|
||||
if (sf->use_transform_domain_distortion > 0) cpi->oxcf.using_dist_8x8 = 0;
|
||||
|
||||
if (cpi->oxcf.using_dist_8x8) x->min_partition_size = BLOCK_8X8;
|
||||
#endif // CONFIG_DIST_8X8
|
||||
if (cpi->oxcf.row_mt == 1 && (cpi->oxcf.max_threads > 1)) {
|
||||
sf->adaptive_rd_thresh = 0;
|
||||
if (sf->inter_mode_rd_model_estimation == 1)
|
||||
sf->inter_mode_rd_model_estimation = 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
182
third_party/aom/av1/encoder/speed_features.h
vendored
182
third_party/aom/av1/encoder/speed_features.h
vendored
|
|
@ -73,7 +73,7 @@ enum {
|
|||
(1 << THR_ALTR) | (1 << THR_GOLD)
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
enum {
|
||||
TXFM_CODING_SF = 1,
|
||||
INTER_PRED_SF = 2,
|
||||
INTRA_PRED_SF = 4,
|
||||
|
|
@ -82,9 +82,9 @@ typedef enum {
|
|||
RD_SKIP_SF = 32,
|
||||
RESERVE_2_SF = 64,
|
||||
RESERVE_3_SF = 128,
|
||||
} DEV_SPEED_FEATURES;
|
||||
} UENUM1BYTE(DEV_SPEED_FEATURES);
|
||||
|
||||
typedef enum {
|
||||
enum {
|
||||
DIAMOND = 0,
|
||||
NSTEP = 1,
|
||||
HEX = 2,
|
||||
|
|
@ -92,9 +92,9 @@ typedef enum {
|
|||
SQUARE = 4,
|
||||
FAST_HEX = 5,
|
||||
FAST_DIAMOND = 6
|
||||
} SEARCH_METHODS;
|
||||
} UENUM1BYTE(SEARCH_METHODS);
|
||||
|
||||
typedef enum {
|
||||
enum {
|
||||
// No recode.
|
||||
DISALLOW_RECODE = 0,
|
||||
// Allow recode for KF and exceeding maximum frame bandwidth.
|
||||
|
|
@ -103,28 +103,28 @@ typedef enum {
|
|||
ALLOW_RECODE_KFARFGF = 2,
|
||||
// Allow recode for all frames based on bitrate constraints.
|
||||
ALLOW_RECODE = 3,
|
||||
} RECODE_LOOP_TYPE;
|
||||
} UENUM1BYTE(RECODE_LOOP_TYPE);
|
||||
|
||||
typedef enum {
|
||||
enum {
|
||||
SUBPEL_TREE = 0,
|
||||
SUBPEL_TREE_PRUNED = 1, // Prunes 1/2-pel searches
|
||||
SUBPEL_TREE_PRUNED_MORE = 2, // Prunes 1/2-pel searches more aggressively
|
||||
SUBPEL_TREE_PRUNED_EVENMORE = 3, // Prunes 1/2- and 1/4-pel searches
|
||||
// Other methods to come
|
||||
} SUBPEL_SEARCH_METHODS;
|
||||
} UENUM1BYTE(SUBPEL_SEARCH_METHODS);
|
||||
|
||||
typedef enum {
|
||||
enum {
|
||||
USE_FULL_RD = 0,
|
||||
USE_FAST_RD,
|
||||
USE_LARGESTALL,
|
||||
} TX_SIZE_SEARCH_METHOD;
|
||||
} UENUM1BYTE(TX_SIZE_SEARCH_METHOD);
|
||||
|
||||
typedef enum {
|
||||
enum {
|
||||
NOT_IN_USE = 0,
|
||||
RELAXED_NEIGHBORING_MIN_MAX = 1
|
||||
} AUTO_MIN_MAX_MODE;
|
||||
} UENUM1BYTE(AUTO_MIN_MAX_MODE);
|
||||
|
||||
typedef enum {
|
||||
enum {
|
||||
// Try the full image with different values.
|
||||
LPF_PICK_FROM_FULL_IMAGE,
|
||||
// Try a small portion of the image with different values.
|
||||
|
|
@ -133,9 +133,9 @@ typedef enum {
|
|||
LPF_PICK_FROM_Q,
|
||||
// Pick 0 to disable LPF if LPF was enabled last frame
|
||||
LPF_PICK_MINIMAL_LPF
|
||||
} LPF_PICK_METHOD;
|
||||
} UENUM1BYTE(LPF_PICK_METHOD);
|
||||
|
||||
typedef enum {
|
||||
enum {
|
||||
// Terminate search early based on distortion so far compared to
|
||||
// qp step, distortion in the neighborhood of the frame, etc.
|
||||
FLAG_EARLY_TERMINATE = 1 << 0,
|
||||
|
|
@ -152,9 +152,9 @@ typedef enum {
|
|||
|
||||
// Skips intra modes other than DC_PRED if the source variance is small
|
||||
FLAG_SKIP_INTRA_LOWVAR = 1 << 5,
|
||||
} MODE_SEARCH_SKIP_LOGIC;
|
||||
} UENUM1BYTE(MODE_SEARCH_SKIP_LOGIC);
|
||||
|
||||
typedef enum {
|
||||
enum {
|
||||
NO_PRUNE = 0,
|
||||
// eliminates one tx type in vertical and horizontal direction
|
||||
PRUNE_ONE = 1,
|
||||
|
|
@ -165,7 +165,7 @@ typedef enum {
|
|||
PRUNE_2D_ACCURATE = 3,
|
||||
// similar, but applies much more aggressive pruning to get better speed-up
|
||||
PRUNE_2D_FAST = 4,
|
||||
} TX_TYPE_PRUNE_MODE;
|
||||
} UENUM1BYTE(TX_TYPE_PRUNE_MODE);
|
||||
|
||||
typedef struct {
|
||||
TX_TYPE_PRUNE_MODE prune_mode;
|
||||
|
|
@ -184,7 +184,7 @@ typedef struct {
|
|||
int skip_tx_search;
|
||||
} TX_TYPE_SEARCH;
|
||||
|
||||
typedef enum {
|
||||
enum {
|
||||
// Search partitions using RD criterion
|
||||
SEARCH_PARTITION,
|
||||
|
||||
|
|
@ -192,7 +192,14 @@ typedef enum {
|
|||
FIXED_PARTITION,
|
||||
|
||||
REFERENCE_PARTITION
|
||||
} PARTITION_SEARCH_TYPE;
|
||||
} UENUM1BYTE(PARTITION_SEARCH_TYPE);
|
||||
|
||||
enum {
|
||||
EIGHTH_PEL,
|
||||
QUARTER_PEL,
|
||||
HALF_PEL,
|
||||
FULL_PEL
|
||||
} UENUM1BYTE(SUBPEL_FORCE_STOP);
|
||||
|
||||
typedef struct MV_SPEED_FEATURES {
|
||||
// Motion search method (Diamond, NSTEP, Hex, Big Diamond, Square, etc).
|
||||
|
|
@ -215,8 +222,8 @@ typedef struct MV_SPEED_FEATURES {
|
|||
// Maximum number of steps in logarithmic subpel search before giving up.
|
||||
int subpel_iters_per_step;
|
||||
|
||||
// Control when to stop subpel search
|
||||
int subpel_force_stop;
|
||||
// When to stop subpel search.
|
||||
SUBPEL_FORCE_STOP subpel_force_stop;
|
||||
} MV_SPEED_FEATURES;
|
||||
|
||||
#define MAX_MESH_STEP 4
|
||||
|
|
@ -226,29 +233,42 @@ typedef struct MESH_PATTERN {
|
|||
int interval;
|
||||
} MESH_PATTERN;
|
||||
|
||||
typedef enum {
|
||||
enum {
|
||||
GM_FULL_SEARCH,
|
||||
GM_REDUCED_REF_SEARCH,
|
||||
GM_REDUCED_REF_SEARCH_SKIP_L2_L3,
|
||||
GM_REDUCED_REF_SEARCH_SKIP_L2_L3_ARF2,
|
||||
GM_DISABLE_SEARCH
|
||||
} GM_SEARCH_TYPE;
|
||||
} UENUM1BYTE(GM_SEARCH_TYPE);
|
||||
|
||||
typedef enum {
|
||||
enum {
|
||||
GM_ERRORADV_TR_0,
|
||||
GM_ERRORADV_TR_1,
|
||||
GM_ERRORADV_TR_2,
|
||||
GM_ERRORADV_TR_TYPES,
|
||||
} GM_ERRORADV_TYPE;
|
||||
} UENUM1BYTE(GM_ERRORADV_TYPE);
|
||||
|
||||
typedef enum {
|
||||
enum {
|
||||
NO_TRELLIS_OPT, // No trellis optimization
|
||||
FULL_TRELLIS_OPT, // Trellis optimization in all stages
|
||||
FINAL_PASS_TRELLIS_OPT // Trellis optimization in only the final encode pass
|
||||
} TRELLIS_OPT_TYPE;
|
||||
} UENUM1BYTE(TRELLIS_OPT_TYPE);
|
||||
|
||||
typedef enum {
|
||||
enum {
|
||||
FULL_TXFM_RD,
|
||||
LOW_TXFM_RD,
|
||||
} TXFM_RD_MODEL;
|
||||
} UENUM1BYTE(TXFM_RD_MODEL);
|
||||
|
||||
enum {
|
||||
DIST_WTD_COMP_ENABLED,
|
||||
DIST_WTD_COMP_SKIP_MV_SEARCH,
|
||||
DIST_WTD_COMP_DISABLED,
|
||||
} UENUM1BYTE(DIST_WTD_COMP_FLAG);
|
||||
|
||||
typedef enum {
|
||||
FLAG_SKIP_EIGHTTAP = 1 << EIGHTTAP_REGULAR,
|
||||
FLAG_SKIP_EIGHTTAP_SMOOTH = 1 << EIGHTTAP_SMOOTH,
|
||||
FLAG_SKIP_EIGHTTAP_SHARP = 1 << MULTITAP_SHARP,
|
||||
} INTERP_FILTER_MASK;
|
||||
|
||||
typedef struct SPEED_FEATURES {
|
||||
MV_SPEED_FEATURES mv;
|
||||
|
|
@ -329,11 +349,16 @@ typedef struct SPEED_FEATURES {
|
|||
// 1: use model based rd breakout
|
||||
int model_based_post_interp_filter_breakout;
|
||||
|
||||
// Model based breakout in motion_mode_rd
|
||||
// 0: no breakout
|
||||
// 1: use model based rd breakout
|
||||
int model_based_motion_mode_rd_breakout;
|
||||
|
||||
// Used if partition_search_type = FIXED_SIZE_PARTITION
|
||||
BLOCK_SIZE always_this_block_size;
|
||||
|
||||
// Drop less likely to be picked reference frames in the RD search.
|
||||
// Has three levels for now: 0, 1 and 2, where higher levels prune more
|
||||
// Has five levels for now: 0, 1, 2, 3 and 4, where higher levels prune more
|
||||
// aggressively than lower ones. (0 means no pruning).
|
||||
int selective_ref_frame;
|
||||
|
||||
|
|
@ -371,6 +396,9 @@ typedef struct SPEED_FEATURES {
|
|||
// Prune reference frames for rectangular partitions.
|
||||
int prune_ref_frame_for_rect_partitions;
|
||||
|
||||
// Prune ref/mode choices for partitions.
|
||||
int prune_ref_mode_for_partitions;
|
||||
|
||||
// Sets min and max partition sizes for this superblock based on the
|
||||
// same superblock in last encoded frame, and the left and above neighbor.
|
||||
AUTO_MIN_MAX_MODE auto_min_max_partition_size;
|
||||
|
|
@ -431,12 +459,19 @@ typedef struct SPEED_FEATURES {
|
|||
// Choose a very large value (UINT_MAX) to use 8-tap always
|
||||
unsigned int disable_filter_search_var_thresh;
|
||||
|
||||
// A source variance threshold below which wedge search is disabled
|
||||
// Only enable wedge search if the edge strength is greater than
|
||||
// this threshold. A value of 0 signals that this check is disabled.
|
||||
unsigned int disable_wedge_search_edge_thresh;
|
||||
|
||||
// Only enable wedge search if the variance is above this threshold.
|
||||
unsigned int disable_wedge_search_var_thresh;
|
||||
|
||||
// Whether fast wedge sign estimate is used
|
||||
int fast_wedge_sign_estimate;
|
||||
|
||||
// Whether to prune wedge search based on predictor difference
|
||||
int prune_wedge_pred_diff_based;
|
||||
|
||||
// These bit masks allow you to enable or disable intra modes for each
|
||||
// transform size separately.
|
||||
int intra_y_mode_mask[TX_SIZES];
|
||||
|
|
@ -473,7 +508,7 @@ typedef struct SPEED_FEATURES {
|
|||
|
||||
// If true, sub-pixel search uses the exact convolve function used for final
|
||||
// encoding and decoding; otherwise, it uses bilinear interpolation.
|
||||
int use_accurate_subpel_search;
|
||||
SUBPEL_SEARCH_TYPE use_accurate_subpel_search;
|
||||
|
||||
// Whether to compute distortion in the image domain (slower but
|
||||
// more accurate), or in the transform domain (faster but less acurate).
|
||||
|
|
@ -492,6 +527,9 @@ typedef struct SPEED_FEATURES {
|
|||
// usually includes EIGHTTAP_REGULAR.
|
||||
int use_fast_interpolation_filter_search;
|
||||
|
||||
// Disable dual filter
|
||||
int disable_dual_filter;
|
||||
|
||||
// Save results of interpolation_filter_search for a block
|
||||
// Check mv and ref_frames before search, if they are same with previous
|
||||
// saved results, it can be skipped.
|
||||
|
|
@ -522,18 +560,23 @@ typedef struct SPEED_FEATURES {
|
|||
// Calculate RD cost before doing optimize_b, and skip if the cost is large.
|
||||
int optimize_b_precheck;
|
||||
|
||||
// Use model rd instead of transform search in jnt_comp
|
||||
int jnt_comp_fast_tx_search;
|
||||
// Use model rd instead of transform search in dist_wtd_comp
|
||||
int dist_wtd_comp_fast_tx_search;
|
||||
|
||||
// Skip mv search in jnt_comp
|
||||
int jnt_comp_skip_mv_search;
|
||||
// Decide when and how to use joint_comp.
|
||||
DIST_WTD_COMP_FLAG use_dist_wtd_comp_flag;
|
||||
|
||||
// Decoder side speed feature to add penalty for use of dual-sgr filters.
|
||||
// Takes values 0 - 10, 0 indicating no penalty and each additional level
|
||||
// adding a penalty of 1%
|
||||
int dual_sgr_penalty_level;
|
||||
|
||||
// Dynamically estimate final rd from prediction error and mode cost
|
||||
// 2-pass inter mode model estimation where the preliminary pass skips
|
||||
// transform search and uses a model to estimate rd, while the final pass
|
||||
// computes the full transform search. two types of models are supported:
|
||||
// 0: not used
|
||||
// 1: used with online dynamic rd model
|
||||
// 2: used with static rd model
|
||||
int inter_mode_rd_model_estimation;
|
||||
|
||||
// Skip some ref frames in compound motion search by single motion search
|
||||
|
|
@ -543,6 +586,10 @@ typedef struct SPEED_FEATURES {
|
|||
// single inter mode as a group.
|
||||
int prune_comp_search_by_single_result;
|
||||
|
||||
// Skip certain motion modes (OBMC, warped, interintra) for single reference
|
||||
// motion search, using the results of single ref SIMPLE_TRANSLATION
|
||||
int prune_single_motion_modes_by_simple_trans;
|
||||
|
||||
// Reuse the inter_intra_mode search result from NEARESTMV mode to other
|
||||
// single ref modes
|
||||
int reuse_inter_intra_mode;
|
||||
|
|
@ -554,12 +601,65 @@ typedef struct SPEED_FEATURES {
|
|||
|
||||
// flag to skip NEWMV mode in drl if the motion search result is the same
|
||||
int skip_repeated_newmv;
|
||||
|
||||
// Prune intra mode candidates based on source block gradient stats.
|
||||
int intra_angle_estimation;
|
||||
|
||||
// Skip obmc or warped motion mode when neighborhood motion field is
|
||||
// identical
|
||||
int skip_obmc_in_uniform_mv_field;
|
||||
int skip_wm_in_uniform_mv_field;
|
||||
|
||||
// Enable/disable ME for interinter wedge search.
|
||||
int disable_interinter_wedge_newmv_search;
|
||||
|
||||
// skip sharp_filter evaluation based on regular and smooth filter rd for
|
||||
// dual_filter=0 case
|
||||
int skip_sharp_interp_filter_search;
|
||||
|
||||
// prune wedge and compound segment approximate rd evaluation based on
|
||||
// compound average rd/ref_best_rd
|
||||
int prune_comp_type_by_comp_avg;
|
||||
|
||||
// Prune/gate motion mode evaluation based on token based rd
|
||||
// during transform search for inter blocks
|
||||
// Values are 0 (not used) , 1 - 3 with progressively increasing
|
||||
// aggressiveness
|
||||
int prune_motion_mode_level;
|
||||
|
||||
// Gate warp evaluation for motions of type IDENTITY,
|
||||
// TRANSLATION and AFFINE(based on number of warp neighbors)
|
||||
int prune_warp_using_wmtype;
|
||||
|
||||
// Perform simple_motion_search on each possible subblock and use it to prune
|
||||
// PARTITION_HORZ and PARTITION_VERT.
|
||||
int simple_motion_search_prune_rect;
|
||||
|
||||
// Perform simple motion search before none_partition to decide if we
|
||||
// want to split directly without trying other partition types.
|
||||
int simple_motion_search_split_only;
|
||||
|
||||
int cb_pred_filter_search;
|
||||
|
||||
// adaptive interp_filter search to allow skip of certain filter types.
|
||||
int adaptive_interp_filter_search;
|
||||
|
||||
// mask for skip evaluation of certain interp_filter type.
|
||||
INTERP_FILTER_MASK interp_filter_search_mask;
|
||||
|
||||
// Enable/disable interintra wedge search.
|
||||
int disable_wedge_interintra_search;
|
||||
|
||||
// Flag used to control the extent of coeff R-D optimization
|
||||
int perform_coeff_opt;
|
||||
} SPEED_FEATURES;
|
||||
|
||||
struct AV1_COMP;
|
||||
|
||||
void av1_set_speed_features_framesize_independent(struct AV1_COMP *cpi);
|
||||
void av1_set_speed_features_framesize_dependent(struct AV1_COMP *cpi);
|
||||
void av1_set_speed_features_framesize_independent(struct AV1_COMP *cpi,
|
||||
int speed);
|
||||
void av1_set_speed_features_framesize_dependent(struct AV1_COMP *cpi,
|
||||
int speed);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
|
|
|
|||
877
third_party/aom/av1/encoder/temporal_filter.c
vendored
877
third_party/aom/av1/encoder/temporal_filter.c
vendored
File diff suppressed because it is too large
Load diff
14
third_party/aom/av1/encoder/temporal_filter.h
vendored
14
third_party/aom/av1/encoder/temporal_filter.h
vendored
|
|
@ -16,6 +16,20 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ARNR_FILT_QINDEX 128
|
||||
|
||||
// Block size used in temporal filtering
|
||||
#define TF_BLOCK BLOCK_32X32
|
||||
#define BH 32
|
||||
#define BH_LOG2 5
|
||||
#define BW 32
|
||||
#define BW_LOG2 5
|
||||
#define BLK_PELS 1024 // Pixels in the block
|
||||
#define THR_SHIFT 2
|
||||
#define TF_SUB_BLOCK BLOCK_16X16
|
||||
#define SUB_BH 16
|
||||
#define SUB_BW 16
|
||||
|
||||
void av1_temporal_filter(AV1_COMP *cpi, int distance);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
|||
19
third_party/aom/av1/encoder/tokenize.c
vendored
19
third_party/aom/av1/encoder/tokenize.c
vendored
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
static int cost_and_tokenize_map(Av1ColorMapParam *param, TOKENEXTRA **t,
|
||||
int plane, int calc_rate, int allow_update_cdf,
|
||||
FRAME_COUNTS *counts) {
|
||||
FRAME_COUNTS *counts, MapCdf map_pb_cdf) {
|
||||
const uint8_t *const color_map = param->color_map;
|
||||
MapCdf map_cdf = param->map_cdf;
|
||||
ColorCost color_cost = param->color_cost;
|
||||
|
|
@ -55,7 +55,7 @@ static int cost_and_tokenize_map(Av1ColorMapParam *param, TOKENEXTRA **t,
|
|||
this_rate += (*color_cost)[palette_size_idx][color_ctx][color_new_idx];
|
||||
} else {
|
||||
(*t)->token = color_new_idx;
|
||||
(*t)->color_map_cdf = map_cdf[palette_size_idx][color_ctx];
|
||||
(*t)->color_map_cdf = map_pb_cdf[palette_size_idx][color_ctx];
|
||||
++(*t);
|
||||
if (allow_update_cdf)
|
||||
update_cdf(map_cdf[palette_size_idx][color_ctx], color_new_idx, n);
|
||||
|
|
@ -107,7 +107,10 @@ int av1_cost_color_map(const MACROBLOCK *const x, int plane, BLOCK_SIZE bsize,
|
|||
assert(plane == 0 || plane == 1);
|
||||
Av1ColorMapParam color_map_params;
|
||||
get_color_map_params(x, plane, bsize, tx_size, type, &color_map_params);
|
||||
return cost_and_tokenize_map(&color_map_params, NULL, plane, 1, 0, NULL);
|
||||
MapCdf map_pb_cdf = plane ? x->tile_pb_ctx->palette_uv_color_index_cdf
|
||||
: x->tile_pb_ctx->palette_y_color_index_cdf;
|
||||
return cost_and_tokenize_map(&color_map_params, NULL, plane, 1, 0, NULL,
|
||||
map_pb_cdf);
|
||||
}
|
||||
|
||||
void av1_tokenize_color_map(const MACROBLOCK *const x, int plane,
|
||||
|
|
@ -121,13 +124,15 @@ void av1_tokenize_color_map(const MACROBLOCK *const x, int plane,
|
|||
(*t)->token = color_map_params.color_map[0];
|
||||
(*t)->color_map_cdf = NULL;
|
||||
++(*t);
|
||||
MapCdf map_pb_cdf = plane ? x->tile_pb_ctx->palette_uv_color_index_cdf
|
||||
: x->tile_pb_ctx->palette_y_color_index_cdf;
|
||||
cost_and_tokenize_map(&color_map_params, t, plane, 0, allow_update_cdf,
|
||||
counts);
|
||||
counts, map_pb_cdf);
|
||||
}
|
||||
|
||||
void tokenize_vartx(ThreadData *td, TOKENEXTRA **t, RUN_TYPE dry_run,
|
||||
TX_SIZE tx_size, BLOCK_SIZE plane_bsize, int blk_row,
|
||||
int blk_col, int block, int plane, void *arg) {
|
||||
static void tokenize_vartx(ThreadData *td, TOKENEXTRA **t, RUN_TYPE dry_run,
|
||||
TX_SIZE tx_size, BLOCK_SIZE plane_bsize, int blk_row,
|
||||
int blk_col, int block, int plane, void *arg) {
|
||||
MACROBLOCK *const x = &td->mb;
|
||||
MACROBLOCKD *const xd = &x->e_mbd;
|
||||
MB_MODE_INFO *const mbmi = xd->mi[0];
|
||||
|
|
|
|||
4
third_party/aom/av1/encoder/tokenize.h
vendored
4
third_party/aom/av1/encoder/tokenize.h
vendored
|
|
@ -38,11 +38,11 @@ struct tokenize_b_args {
|
|||
uint8_t allow_update_cdf;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
enum {
|
||||
OUTPUT_ENABLED = 0,
|
||||
DRY_RUN_NORMAL,
|
||||
DRY_RUN_COSTCOEFFS,
|
||||
} RUN_TYPE;
|
||||
} UENUM1BYTE(RUN_TYPE);
|
||||
|
||||
// Note in all the tokenize functions rate if non NULL is incremented
|
||||
// with the coefficient token cost only if dry_run = DRY_RUN_COSTCOEFS,
|
||||
|
|
|
|||
595
third_party/aom/av1/encoder/tpl_model.c
vendored
Normal file
595
third_party/aom/av1/encoder/tpl_model.c
vendored
Normal file
|
|
@ -0,0 +1,595 @@
|
|||
/*
|
||||
* Copyright (c) 2019, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "config/aom_config.h"
|
||||
#include "config/aom_dsp_rtcd.h"
|
||||
|
||||
#include "aom/aom_codec.h"
|
||||
|
||||
#include "av1/common/onyxc_int.h"
|
||||
#include "av1/common/reconintra.h"
|
||||
|
||||
#include "av1/encoder/encoder.h"
|
||||
#include "av1/encoder/reconinter_enc.h"
|
||||
|
||||
typedef struct GF_PICTURE {
|
||||
YV12_BUFFER_CONFIG *frame;
|
||||
int ref_frame[7];
|
||||
} GF_PICTURE;
|
||||
|
||||
static void get_quantize_error(MACROBLOCK *x, int plane, tran_low_t *coeff,
|
||||
tran_low_t *qcoeff, tran_low_t *dqcoeff,
|
||||
TX_SIZE tx_size, int64_t *recon_error,
|
||||
int64_t *sse) {
|
||||
const struct macroblock_plane *const p = &x->plane[plane];
|
||||
const SCAN_ORDER *const scan_order = &av1_default_scan_orders[tx_size];
|
||||
uint16_t eob;
|
||||
int pix_num = 1 << num_pels_log2_lookup[txsize_to_bsize[tx_size]];
|
||||
const int shift = tx_size == TX_32X32 ? 0 : 2;
|
||||
|
||||
av1_quantize_fp_32x32(coeff, pix_num, p->zbin_QTX, p->round_fp_QTX,
|
||||
p->quant_fp_QTX, p->quant_shift_QTX, qcoeff, dqcoeff,
|
||||
p->dequant_QTX, &eob, scan_order->scan,
|
||||
scan_order->iscan);
|
||||
|
||||
*recon_error = av1_block_error(coeff, dqcoeff, pix_num, sse) >> shift;
|
||||
*recon_error = AOMMAX(*recon_error, 1);
|
||||
|
||||
*sse = (*sse) >> shift;
|
||||
*sse = AOMMAX(*sse, 1);
|
||||
}
|
||||
|
||||
static void wht_fwd_txfm(int16_t *src_diff, int bw, tran_low_t *coeff,
|
||||
TX_SIZE tx_size) {
|
||||
switch (tx_size) {
|
||||
case TX_8X8: aom_hadamard_8x8(src_diff, bw, coeff); break;
|
||||
case TX_16X16: aom_hadamard_16x16(src_diff, bw, coeff); break;
|
||||
case TX_32X32: aom_hadamard_32x32(src_diff, bw, coeff); break;
|
||||
default: assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t motion_compensated_prediction(AV1_COMP *cpi, ThreadData *td,
|
||||
uint8_t *cur_frame_buf,
|
||||
uint8_t *ref_frame_buf,
|
||||
int stride, BLOCK_SIZE bsize,
|
||||
int mi_row, int mi_col) {
|
||||
AV1_COMMON *cm = &cpi->common;
|
||||
MACROBLOCK *const x = &td->mb;
|
||||
MACROBLOCKD *const xd = &x->e_mbd;
|
||||
MV_SPEED_FEATURES *const mv_sf = &cpi->sf.mv;
|
||||
const SEARCH_METHODS search_method = NSTEP;
|
||||
int step_param;
|
||||
int sadpb = x->sadperbit16;
|
||||
uint32_t bestsme = UINT_MAX;
|
||||
int distortion;
|
||||
uint32_t sse;
|
||||
int cost_list[5];
|
||||
const MvLimits tmp_mv_limits = x->mv_limits;
|
||||
|
||||
MV best_ref_mv1 = { 0, 0 };
|
||||
MV best_ref_mv1_full; /* full-pixel value of best_ref_mv1 */
|
||||
|
||||
best_ref_mv1_full.col = best_ref_mv1.col >> 3;
|
||||
best_ref_mv1_full.row = best_ref_mv1.row >> 3;
|
||||
|
||||
// Setup frame pointers
|
||||
x->plane[0].src.buf = cur_frame_buf;
|
||||
x->plane[0].src.stride = stride;
|
||||
xd->plane[0].pre[0].buf = ref_frame_buf;
|
||||
xd->plane[0].pre[0].stride = stride;
|
||||
|
||||
step_param = mv_sf->reduce_first_step_size;
|
||||
step_param = AOMMIN(step_param, MAX_MVSEARCH_STEPS - 2);
|
||||
|
||||
av1_set_mv_search_range(&x->mv_limits, &best_ref_mv1);
|
||||
|
||||
av1_full_pixel_search(cpi, x, bsize, &best_ref_mv1_full, step_param,
|
||||
search_method, 0, sadpb, cond_cost_list(cpi, cost_list),
|
||||
&best_ref_mv1, INT_MAX, 0, (MI_SIZE * mi_col),
|
||||
(MI_SIZE * mi_row), 0);
|
||||
|
||||
/* restore UMV window */
|
||||
x->mv_limits = tmp_mv_limits;
|
||||
|
||||
const int pw = block_size_wide[bsize];
|
||||
const int ph = block_size_high[bsize];
|
||||
bestsme = cpi->find_fractional_mv_step(
|
||||
x, cm, mi_row, mi_col, &best_ref_mv1, cpi->common.allow_high_precision_mv,
|
||||
x->errorperbit, &cpi->fn_ptr[bsize], 0, mv_sf->subpel_iters_per_step,
|
||||
cond_cost_list(cpi, cost_list), NULL, NULL, &distortion, &sse, NULL, NULL,
|
||||
0, 0, pw, ph, 1, 1);
|
||||
|
||||
return bestsme;
|
||||
}
|
||||
|
||||
static void mode_estimation(AV1_COMP *cpi, MACROBLOCK *x, MACROBLOCKD *xd,
|
||||
struct scale_factors *sf, GF_PICTURE *gf_picture,
|
||||
int frame_idx, int16_t *src_diff, tran_low_t *coeff,
|
||||
tran_low_t *qcoeff, tran_low_t *dqcoeff, int mi_row,
|
||||
int mi_col, BLOCK_SIZE bsize, TX_SIZE tx_size,
|
||||
YV12_BUFFER_CONFIG *ref_frame[], uint8_t *predictor,
|
||||
int64_t *recon_error, int64_t *sse,
|
||||
TplDepStats *tpl_stats) {
|
||||
AV1_COMMON *cm = &cpi->common;
|
||||
ThreadData *td = &cpi->td;
|
||||
|
||||
const int bw = 4 << mi_size_wide_log2[bsize];
|
||||
const int bh = 4 << mi_size_high_log2[bsize];
|
||||
const int pix_num = bw * bh;
|
||||
int best_rf_idx = -1;
|
||||
int_mv best_mv;
|
||||
int64_t best_inter_cost = INT64_MAX;
|
||||
int64_t inter_cost;
|
||||
int rf_idx;
|
||||
const InterpFilters kernel =
|
||||
av1_make_interp_filters(EIGHTTAP_REGULAR, EIGHTTAP_REGULAR);
|
||||
|
||||
int64_t best_intra_cost = INT64_MAX;
|
||||
int64_t intra_cost;
|
||||
PREDICTION_MODE mode;
|
||||
int mb_y_offset = mi_row * MI_SIZE * xd->cur_buf->y_stride + mi_col * MI_SIZE;
|
||||
MB_MODE_INFO mi_above, mi_left;
|
||||
|
||||
memset(tpl_stats, 0, sizeof(*tpl_stats));
|
||||
|
||||
xd->mb_to_top_edge = -((mi_row * MI_SIZE) * 8);
|
||||
xd->mb_to_bottom_edge = ((cm->mi_rows - 1 - mi_row) * MI_SIZE) * 8;
|
||||
xd->mb_to_left_edge = -((mi_col * MI_SIZE) * 8);
|
||||
xd->mb_to_right_edge = ((cm->mi_cols - 1 - mi_col) * MI_SIZE) * 8;
|
||||
xd->above_mbmi = (mi_row > 0) ? &mi_above : NULL;
|
||||
xd->left_mbmi = (mi_col > 0) ? &mi_left : NULL;
|
||||
|
||||
// Intra prediction search
|
||||
for (mode = DC_PRED; mode <= PAETH_PRED; ++mode) {
|
||||
uint8_t *src, *dst;
|
||||
int src_stride, dst_stride;
|
||||
|
||||
src = xd->cur_buf->y_buffer + mb_y_offset;
|
||||
src_stride = xd->cur_buf->y_stride;
|
||||
|
||||
dst = &predictor[0];
|
||||
dst_stride = bw;
|
||||
|
||||
xd->mi[0]->sb_type = bsize;
|
||||
xd->mi[0]->ref_frame[0] = INTRA_FRAME;
|
||||
|
||||
av1_predict_intra_block(
|
||||
cm, xd, block_size_wide[bsize], block_size_high[bsize], tx_size, mode,
|
||||
0, 0, FILTER_INTRA_MODES, src, src_stride, dst, dst_stride, 0, 0, 0);
|
||||
|
||||
if (is_cur_buf_hbd(xd)) {
|
||||
aom_highbd_subtract_block(bh, bw, src_diff, bw, src, src_stride, dst,
|
||||
dst_stride, xd->bd);
|
||||
} else {
|
||||
aom_subtract_block(bh, bw, src_diff, bw, src, src_stride, dst,
|
||||
dst_stride);
|
||||
}
|
||||
|
||||
wht_fwd_txfm(src_diff, bw, coeff, tx_size);
|
||||
|
||||
intra_cost = aom_satd(coeff, pix_num);
|
||||
|
||||
if (intra_cost < best_intra_cost) best_intra_cost = intra_cost;
|
||||
}
|
||||
|
||||
// Motion compensated prediction
|
||||
best_mv.as_int = 0;
|
||||
|
||||
(void)mb_y_offset;
|
||||
// Motion estimation column boundary
|
||||
x->mv_limits.col_min = -((mi_col * MI_SIZE) + (17 - 2 * AOM_INTERP_EXTEND));
|
||||
x->mv_limits.col_max =
|
||||
((cm->mi_cols - 1 - mi_col) * MI_SIZE) + (17 - 2 * AOM_INTERP_EXTEND);
|
||||
|
||||
for (rf_idx = 0; rf_idx < 7; ++rf_idx) {
|
||||
if (ref_frame[rf_idx] == NULL) continue;
|
||||
|
||||
motion_compensated_prediction(cpi, td, xd->cur_buf->y_buffer + mb_y_offset,
|
||||
ref_frame[rf_idx]->y_buffer + mb_y_offset,
|
||||
xd->cur_buf->y_stride, bsize, mi_row, mi_col);
|
||||
|
||||
// TODO(jingning): Not yet support high bit-depth in the next three
|
||||
// steps.
|
||||
ConvolveParams conv_params = get_conv_params(0, 0, xd->bd);
|
||||
WarpTypesAllowed warp_types;
|
||||
memset(&warp_types, 0, sizeof(WarpTypesAllowed));
|
||||
|
||||
av1_build_inter_predictor(
|
||||
ref_frame[rf_idx]->y_buffer + mb_y_offset, ref_frame[rf_idx]->y_stride,
|
||||
&predictor[0], bw, &x->best_mv.as_mv, sf, bw, bh, &conv_params, kernel,
|
||||
&warp_types, mi_col * MI_SIZE, mi_row * MI_SIZE, 0, 0, MV_PRECISION_Q3,
|
||||
mi_col * MI_SIZE, mi_row * MI_SIZE, xd, 0);
|
||||
if (is_cur_buf_hbd(xd)) {
|
||||
aom_highbd_subtract_block(
|
||||
bh, bw, src_diff, bw, xd->cur_buf->y_buffer + mb_y_offset,
|
||||
xd->cur_buf->y_stride, &predictor[0], bw, xd->bd);
|
||||
} else {
|
||||
aom_subtract_block(bh, bw, src_diff, bw,
|
||||
xd->cur_buf->y_buffer + mb_y_offset,
|
||||
xd->cur_buf->y_stride, &predictor[0], bw);
|
||||
}
|
||||
wht_fwd_txfm(src_diff, bw, coeff, tx_size);
|
||||
|
||||
inter_cost = aom_satd(coeff, pix_num);
|
||||
if (inter_cost < best_inter_cost) {
|
||||
best_rf_idx = rf_idx;
|
||||
best_inter_cost = inter_cost;
|
||||
best_mv.as_int = x->best_mv.as_int;
|
||||
get_quantize_error(x, 0, coeff, qcoeff, dqcoeff, tx_size, recon_error,
|
||||
sse);
|
||||
}
|
||||
}
|
||||
best_intra_cost = AOMMAX(best_intra_cost, 1);
|
||||
best_inter_cost = AOMMIN(best_intra_cost, best_inter_cost);
|
||||
tpl_stats->inter_cost = best_inter_cost << TPL_DEP_COST_SCALE_LOG2;
|
||||
tpl_stats->intra_cost = best_intra_cost << TPL_DEP_COST_SCALE_LOG2;
|
||||
tpl_stats->mc_dep_cost = tpl_stats->intra_cost + tpl_stats->mc_flow;
|
||||
|
||||
tpl_stats->ref_frame_index = gf_picture[frame_idx].ref_frame[best_rf_idx];
|
||||
tpl_stats->mv.as_int = best_mv.as_int;
|
||||
}
|
||||
|
||||
static int round_floor(int ref_pos, int bsize_pix) {
|
||||
int round;
|
||||
if (ref_pos < 0)
|
||||
round = -(1 + (-ref_pos - 1) / bsize_pix);
|
||||
else
|
||||
round = ref_pos / bsize_pix;
|
||||
|
||||
return round;
|
||||
}
|
||||
|
||||
static int get_overlap_area(int grid_pos_row, int grid_pos_col, int ref_pos_row,
|
||||
int ref_pos_col, int block, BLOCK_SIZE bsize) {
|
||||
int width = 0, height = 0;
|
||||
int bw = 4 << mi_size_wide_log2[bsize];
|
||||
int bh = 4 << mi_size_high_log2[bsize];
|
||||
|
||||
switch (block) {
|
||||
case 0:
|
||||
width = grid_pos_col + bw - ref_pos_col;
|
||||
height = grid_pos_row + bh - ref_pos_row;
|
||||
break;
|
||||
case 1:
|
||||
width = ref_pos_col + bw - grid_pos_col;
|
||||
height = grid_pos_row + bh - ref_pos_row;
|
||||
break;
|
||||
case 2:
|
||||
width = grid_pos_col + bw - ref_pos_col;
|
||||
height = ref_pos_row + bh - grid_pos_row;
|
||||
break;
|
||||
case 3:
|
||||
width = ref_pos_col + bw - grid_pos_col;
|
||||
height = ref_pos_row + bh - grid_pos_row;
|
||||
break;
|
||||
default: assert(0);
|
||||
}
|
||||
|
||||
return width * height;
|
||||
}
|
||||
|
||||
static void tpl_model_update_b(TplDepFrame *tpl_frame, TplDepStats *tpl_stats,
|
||||
int mi_row, int mi_col, const BLOCK_SIZE bsize) {
|
||||
TplDepFrame *ref_tpl_frame = &tpl_frame[tpl_stats->ref_frame_index];
|
||||
TplDepStats *ref_stats = ref_tpl_frame->tpl_stats_ptr;
|
||||
MV mv = tpl_stats->mv.as_mv;
|
||||
int mv_row = mv.row >> 3;
|
||||
int mv_col = mv.col >> 3;
|
||||
|
||||
int ref_pos_row = mi_row * MI_SIZE + mv_row;
|
||||
int ref_pos_col = mi_col * MI_SIZE + mv_col;
|
||||
|
||||
const int bw = 4 << mi_size_wide_log2[bsize];
|
||||
const int bh = 4 << mi_size_high_log2[bsize];
|
||||
const int mi_height = mi_size_high[bsize];
|
||||
const int mi_width = mi_size_wide[bsize];
|
||||
const int pix_num = bw * bh;
|
||||
|
||||
// top-left on grid block location in pixel
|
||||
int grid_pos_row_base = round_floor(ref_pos_row, bh) * bh;
|
||||
int grid_pos_col_base = round_floor(ref_pos_col, bw) * bw;
|
||||
int block;
|
||||
|
||||
for (block = 0; block < 4; ++block) {
|
||||
int grid_pos_row = grid_pos_row_base + bh * (block >> 1);
|
||||
int grid_pos_col = grid_pos_col_base + bw * (block & 0x01);
|
||||
|
||||
if (grid_pos_row >= 0 && grid_pos_row < ref_tpl_frame->mi_rows * MI_SIZE &&
|
||||
grid_pos_col >= 0 && grid_pos_col < ref_tpl_frame->mi_cols * MI_SIZE) {
|
||||
int overlap_area = get_overlap_area(
|
||||
grid_pos_row, grid_pos_col, ref_pos_row, ref_pos_col, block, bsize);
|
||||
int ref_mi_row = round_floor(grid_pos_row, bh) * mi_height;
|
||||
int ref_mi_col = round_floor(grid_pos_col, bw) * mi_width;
|
||||
|
||||
int64_t mc_flow = tpl_stats->mc_dep_cost -
|
||||
(tpl_stats->mc_dep_cost * tpl_stats->inter_cost) /
|
||||
tpl_stats->intra_cost;
|
||||
|
||||
int idx, idy;
|
||||
|
||||
for (idy = 0; idy < mi_height; ++idy) {
|
||||
for (idx = 0; idx < mi_width; ++idx) {
|
||||
TplDepStats *des_stats =
|
||||
&ref_stats[(ref_mi_row + idy) * ref_tpl_frame->stride +
|
||||
(ref_mi_col + idx)];
|
||||
|
||||
des_stats->mc_flow += (mc_flow * overlap_area) / pix_num;
|
||||
des_stats->mc_ref_cost +=
|
||||
((tpl_stats->intra_cost - tpl_stats->inter_cost) * overlap_area) /
|
||||
pix_num;
|
||||
assert(overlap_area >= 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void tpl_model_update(TplDepFrame *tpl_frame, TplDepStats *tpl_stats,
|
||||
int mi_row, int mi_col, const BLOCK_SIZE bsize) {
|
||||
int idx, idy;
|
||||
const int mi_height = mi_size_high[bsize];
|
||||
const int mi_width = mi_size_wide[bsize];
|
||||
|
||||
for (idy = 0; idy < mi_height; ++idy) {
|
||||
for (idx = 0; idx < mi_width; ++idx) {
|
||||
TplDepStats *tpl_ptr =
|
||||
&tpl_stats[(mi_row + idy) * tpl_frame->stride + (mi_col + idx)];
|
||||
tpl_model_update_b(tpl_frame, tpl_ptr, mi_row + idy, mi_col + idx,
|
||||
BLOCK_4X4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void tpl_model_store(TplDepStats *tpl_stats, int mi_row, int mi_col,
|
||||
BLOCK_SIZE bsize, int stride,
|
||||
const TplDepStats *src_stats) {
|
||||
const int mi_height = mi_size_high[bsize];
|
||||
const int mi_width = mi_size_wide[bsize];
|
||||
int idx, idy;
|
||||
|
||||
int64_t intra_cost = src_stats->intra_cost / (mi_height * mi_width);
|
||||
int64_t inter_cost = src_stats->inter_cost / (mi_height * mi_width);
|
||||
|
||||
TplDepStats *tpl_ptr;
|
||||
|
||||
intra_cost = AOMMAX(1, intra_cost);
|
||||
inter_cost = AOMMAX(1, inter_cost);
|
||||
|
||||
for (idy = 0; idy < mi_height; ++idy) {
|
||||
tpl_ptr = &tpl_stats[(mi_row + idy) * stride + mi_col];
|
||||
for (idx = 0; idx < mi_width; ++idx) {
|
||||
tpl_ptr->intra_cost = intra_cost;
|
||||
tpl_ptr->inter_cost = inter_cost;
|
||||
tpl_ptr->mc_dep_cost = tpl_ptr->intra_cost + tpl_ptr->mc_flow;
|
||||
tpl_ptr->ref_frame_index = src_stats->ref_frame_index;
|
||||
tpl_ptr->mv.as_int = src_stats->mv.as_int;
|
||||
++tpl_ptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void mc_flow_dispenser(AV1_COMP *cpi, GF_PICTURE *gf_picture,
|
||||
int frame_idx) {
|
||||
TplDepFrame *tpl_frame = &cpi->tpl_stats[frame_idx];
|
||||
YV12_BUFFER_CONFIG *this_frame = gf_picture[frame_idx].frame;
|
||||
YV12_BUFFER_CONFIG *ref_frame[7] = {
|
||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL
|
||||
};
|
||||
|
||||
AV1_COMMON *cm = &cpi->common;
|
||||
struct scale_factors sf;
|
||||
int rdmult, idx;
|
||||
ThreadData *td = &cpi->td;
|
||||
MACROBLOCK *x = &td->mb;
|
||||
MACROBLOCKD *xd = &x->e_mbd;
|
||||
int mi_row, mi_col;
|
||||
|
||||
DECLARE_ALIGNED(16, uint16_t, predictor16[32 * 32 * 3]);
|
||||
DECLARE_ALIGNED(16, uint8_t, predictor8[32 * 32 * 3]);
|
||||
uint8_t *predictor;
|
||||
DECLARE_ALIGNED(16, int16_t, src_diff[32 * 32]);
|
||||
DECLARE_ALIGNED(16, tran_low_t, coeff[32 * 32]);
|
||||
DECLARE_ALIGNED(16, tran_low_t, qcoeff[32 * 32]);
|
||||
DECLARE_ALIGNED(16, tran_low_t, dqcoeff[32 * 32]);
|
||||
|
||||
const BLOCK_SIZE bsize = BLOCK_32X32;
|
||||
const TX_SIZE tx_size = max_txsize_lookup[bsize];
|
||||
const int mi_height = mi_size_high[bsize];
|
||||
const int mi_width = mi_size_wide[bsize];
|
||||
int64_t recon_error, sse;
|
||||
|
||||
// Setup scaling factor
|
||||
av1_setup_scale_factors_for_frame(
|
||||
&sf, this_frame->y_crop_width, this_frame->y_crop_height,
|
||||
this_frame->y_crop_width, this_frame->y_crop_height);
|
||||
|
||||
if (is_cur_buf_hbd(xd))
|
||||
predictor = CONVERT_TO_BYTEPTR(predictor16);
|
||||
else
|
||||
predictor = predictor8;
|
||||
|
||||
// Prepare reference frame pointers. If any reference frame slot is
|
||||
// unavailable, the pointer will be set to Null.
|
||||
for (idx = 0; idx < 7; ++idx) {
|
||||
int rf_idx = gf_picture[frame_idx].ref_frame[idx];
|
||||
if (rf_idx != -1) ref_frame[idx] = gf_picture[rf_idx].frame;
|
||||
}
|
||||
|
||||
xd->mi = cm->mi_grid_visible;
|
||||
xd->mi[0] = cm->mi;
|
||||
xd->cur_buf = this_frame;
|
||||
|
||||
// Get rd multiplier set up.
|
||||
rdmult = (int)av1_compute_rd_mult(cpi, tpl_frame->base_qindex);
|
||||
if (rdmult < 1) rdmult = 1;
|
||||
set_error_per_bit(&cpi->td.mb, rdmult);
|
||||
av1_initialize_me_consts(cpi, &cpi->td.mb, tpl_frame->base_qindex);
|
||||
|
||||
tpl_frame->is_valid = 1;
|
||||
|
||||
cm->base_qindex = tpl_frame->base_qindex;
|
||||
av1_frame_init_quantizer(cpi);
|
||||
|
||||
for (mi_row = 0; mi_row < cm->mi_rows; mi_row += mi_height) {
|
||||
// Motion estimation row boundary
|
||||
x->mv_limits.row_min = -((mi_row * MI_SIZE) + (17 - 2 * AOM_INTERP_EXTEND));
|
||||
x->mv_limits.row_max =
|
||||
(cm->mi_rows - 1 - mi_row) * MI_SIZE + (17 - 2 * AOM_INTERP_EXTEND);
|
||||
for (mi_col = 0; mi_col < cm->mi_cols; mi_col += mi_width) {
|
||||
TplDepStats tpl_stats;
|
||||
mode_estimation(cpi, x, xd, &sf, gf_picture, frame_idx, src_diff, coeff,
|
||||
qcoeff, dqcoeff, mi_row, mi_col, bsize, tx_size,
|
||||
ref_frame, predictor, &recon_error, &sse, &tpl_stats);
|
||||
|
||||
// Motion flow dependency dispenser.
|
||||
tpl_model_store(tpl_frame->tpl_stats_ptr, mi_row, mi_col, bsize,
|
||||
tpl_frame->stride, &tpl_stats);
|
||||
|
||||
tpl_model_update(cpi->tpl_stats, tpl_frame->tpl_stats_ptr, mi_row, mi_col,
|
||||
bsize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void init_gop_frames(AV1_COMP *cpi, GF_PICTURE *gf_picture,
|
||||
const GF_GROUP *gf_group, int *tpl_group_frames,
|
||||
const EncodeFrameInput *const frame_input) {
|
||||
AV1_COMMON *cm = &cpi->common;
|
||||
const SequenceHeader *const seq_params = &cm->seq_params;
|
||||
int frame_idx = 0;
|
||||
int i;
|
||||
int gld_index = -1;
|
||||
int alt_index = -1;
|
||||
int lst_index = -1;
|
||||
int extend_frame_count = 0;
|
||||
int pframe_qindex = cpi->tpl_stats[2].base_qindex;
|
||||
|
||||
RefCntBuffer *frame_bufs = cm->buffer_pool->frame_bufs;
|
||||
int recon_frame_index[INTER_REFS_PER_FRAME + 1] = { -1, -1, -1, -1,
|
||||
-1, -1, -1, -1 };
|
||||
|
||||
// TODO(jingning): To be used later for gf frame type parsing.
|
||||
(void)gf_group;
|
||||
|
||||
for (i = 0; i < FRAME_BUFFERS && frame_idx < INTER_REFS_PER_FRAME + 1; ++i) {
|
||||
if (frame_bufs[i].ref_count == 0) {
|
||||
alloc_frame_mvs(cm, &frame_bufs[i]);
|
||||
if (aom_realloc_frame_buffer(
|
||||
&frame_bufs[i].buf, cm->width, cm->height,
|
||||
seq_params->subsampling_x, seq_params->subsampling_y,
|
||||
seq_params->use_highbitdepth, cpi->oxcf.border_in_pixels,
|
||||
cm->byte_alignment, NULL, NULL, NULL))
|
||||
aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR,
|
||||
"Failed to allocate frame buffer");
|
||||
|
||||
recon_frame_index[frame_idx] = i;
|
||||
++frame_idx;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < INTER_REFS_PER_FRAME + 1; ++i) {
|
||||
assert(recon_frame_index[i] >= 0);
|
||||
cpi->tpl_recon_frames[i] = &frame_bufs[recon_frame_index[i]].buf;
|
||||
}
|
||||
|
||||
*tpl_group_frames = 0;
|
||||
|
||||
// Initialize Golden reference frame.
|
||||
gf_picture[0].frame = NULL;
|
||||
RefCntBuffer *ref_buf = get_ref_frame_buf(cm, GOLDEN_FRAME);
|
||||
if (ref_buf) gf_picture[0].frame = &ref_buf->buf;
|
||||
for (i = 0; i < 7; ++i) gf_picture[0].ref_frame[i] = -1;
|
||||
gld_index = 0;
|
||||
++*tpl_group_frames;
|
||||
|
||||
// Initialize ARF frame
|
||||
gf_picture[1].frame = frame_input->source;
|
||||
gf_picture[1].ref_frame[0] = gld_index;
|
||||
gf_picture[1].ref_frame[1] = lst_index;
|
||||
gf_picture[1].ref_frame[2] = alt_index;
|
||||
// TODO(yuec) Need o figure out full AV1 reference model
|
||||
for (i = 3; i < 7; ++i) gf_picture[1].ref_frame[i] = -1;
|
||||
alt_index = 1;
|
||||
++*tpl_group_frames;
|
||||
|
||||
// Initialize P frames
|
||||
for (frame_idx = 2; frame_idx < MAX_LAG_BUFFERS; ++frame_idx) {
|
||||
struct lookahead_entry *buf =
|
||||
av1_lookahead_peek(cpi->lookahead, frame_idx - 2);
|
||||
|
||||
if (buf == NULL) break;
|
||||
|
||||
gf_picture[frame_idx].frame = &buf->img;
|
||||
gf_picture[frame_idx].ref_frame[0] = gld_index;
|
||||
gf_picture[frame_idx].ref_frame[1] = lst_index;
|
||||
gf_picture[frame_idx].ref_frame[2] = alt_index;
|
||||
for (i = 3; i < 7; ++i) gf_picture[frame_idx].ref_frame[i] = -1;
|
||||
|
||||
++*tpl_group_frames;
|
||||
lst_index = frame_idx;
|
||||
|
||||
if (frame_idx == cpi->rc.baseline_gf_interval + 1) break;
|
||||
}
|
||||
|
||||
gld_index = frame_idx;
|
||||
lst_index = AOMMAX(0, frame_idx - 1);
|
||||
alt_index = -1;
|
||||
++frame_idx;
|
||||
|
||||
// Extend two frames outside the current gf group.
|
||||
for (; frame_idx < MAX_LAG_BUFFERS && extend_frame_count < 2; ++frame_idx) {
|
||||
struct lookahead_entry *buf =
|
||||
av1_lookahead_peek(cpi->lookahead, frame_idx - 2);
|
||||
|
||||
if (buf == NULL) break;
|
||||
|
||||
cpi->tpl_stats[frame_idx].base_qindex = pframe_qindex;
|
||||
|
||||
gf_picture[frame_idx].frame = &buf->img;
|
||||
gf_picture[frame_idx].ref_frame[0] = gld_index;
|
||||
gf_picture[frame_idx].ref_frame[1] = lst_index;
|
||||
gf_picture[frame_idx].ref_frame[2] = alt_index;
|
||||
for (i = 3; i < 7; ++i) gf_picture[frame_idx].ref_frame[i] = -1;
|
||||
lst_index = frame_idx;
|
||||
++*tpl_group_frames;
|
||||
++extend_frame_count;
|
||||
}
|
||||
}
|
||||
|
||||
static void init_tpl_stats(AV1_COMP *cpi) {
|
||||
int frame_idx;
|
||||
for (frame_idx = 0; frame_idx < MAX_LAG_BUFFERS; ++frame_idx) {
|
||||
TplDepFrame *tpl_frame = &cpi->tpl_stats[frame_idx];
|
||||
memset(tpl_frame->tpl_stats_ptr, 0,
|
||||
tpl_frame->height * tpl_frame->width *
|
||||
sizeof(*tpl_frame->tpl_stats_ptr));
|
||||
tpl_frame->is_valid = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void av1_tpl_setup_stats(AV1_COMP *cpi,
|
||||
const EncodeFrameInput *const frame_input) {
|
||||
GF_PICTURE gf_picture[MAX_LAG_BUFFERS];
|
||||
const GF_GROUP *gf_group = &cpi->twopass.gf_group;
|
||||
int tpl_group_frames = 0;
|
||||
int frame_idx;
|
||||
|
||||
init_gop_frames(cpi, gf_picture, gf_group, &tpl_group_frames, frame_input);
|
||||
|
||||
init_tpl_stats(cpi);
|
||||
|
||||
// Backward propagation from tpl_group_frames to 1.
|
||||
for (frame_idx = tpl_group_frames - 1; frame_idx > 0; --frame_idx)
|
||||
mc_flow_dispenser(cpi, gf_picture, frame_idx);
|
||||
}
|
||||
26
third_party/aom/av1/encoder/tpl_model.h
vendored
Normal file
26
third_party/aom/av1/encoder/tpl_model.h
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright (c) 2019, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#ifndef AOM_AV1_ENCODER_TPL_MODEL_H_
|
||||
#define AOM_AV1_ENCODER_TPL_MODEL_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void av1_tpl_setup_stats(AV1_COMP *cpi,
|
||||
const EncodeFrameInput *const frame_input);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // AOM_AV1_ENCODER_TPL_MODEL_H_
|
||||
|
|
@ -11,45 +11,78 @@
|
|||
|
||||
#include "av1/encoder/x86/av1_txfm1d_sse4.h"
|
||||
|
||||
void av1_fdct32_new_sse4_1(const __m128i *input, __m128i *output,
|
||||
int8_t cos_bit) {
|
||||
void av1_fdct32_new_sse4_1(__m128i *input, __m128i *output, int cos_bit,
|
||||
const int stride) {
|
||||
__m128i buf0[32];
|
||||
__m128i buf1[32];
|
||||
const int32_t *cospi;
|
||||
|
||||
int startidx = 0 * stride;
|
||||
int endidx = 31 * stride;
|
||||
// stage 0
|
||||
// stage 1
|
||||
buf1[0] = _mm_add_epi32(input[0], input[31]);
|
||||
buf1[31] = _mm_sub_epi32(input[0], input[31]);
|
||||
buf1[1] = _mm_add_epi32(input[1], input[30]);
|
||||
buf1[30] = _mm_sub_epi32(input[1], input[30]);
|
||||
buf1[2] = _mm_add_epi32(input[2], input[29]);
|
||||
buf1[29] = _mm_sub_epi32(input[2], input[29]);
|
||||
buf1[3] = _mm_add_epi32(input[3], input[28]);
|
||||
buf1[28] = _mm_sub_epi32(input[3], input[28]);
|
||||
buf1[4] = _mm_add_epi32(input[4], input[27]);
|
||||
buf1[27] = _mm_sub_epi32(input[4], input[27]);
|
||||
buf1[5] = _mm_add_epi32(input[5], input[26]);
|
||||
buf1[26] = _mm_sub_epi32(input[5], input[26]);
|
||||
buf1[6] = _mm_add_epi32(input[6], input[25]);
|
||||
buf1[25] = _mm_sub_epi32(input[6], input[25]);
|
||||
buf1[7] = _mm_add_epi32(input[7], input[24]);
|
||||
buf1[24] = _mm_sub_epi32(input[7], input[24]);
|
||||
buf1[8] = _mm_add_epi32(input[8], input[23]);
|
||||
buf1[23] = _mm_sub_epi32(input[8], input[23]);
|
||||
buf1[9] = _mm_add_epi32(input[9], input[22]);
|
||||
buf1[22] = _mm_sub_epi32(input[9], input[22]);
|
||||
buf1[10] = _mm_add_epi32(input[10], input[21]);
|
||||
buf1[21] = _mm_sub_epi32(input[10], input[21]);
|
||||
buf1[11] = _mm_add_epi32(input[11], input[20]);
|
||||
buf1[20] = _mm_sub_epi32(input[11], input[20]);
|
||||
buf1[12] = _mm_add_epi32(input[12], input[19]);
|
||||
buf1[19] = _mm_sub_epi32(input[12], input[19]);
|
||||
buf1[13] = _mm_add_epi32(input[13], input[18]);
|
||||
buf1[18] = _mm_sub_epi32(input[13], input[18]);
|
||||
buf1[14] = _mm_add_epi32(input[14], input[17]);
|
||||
buf1[17] = _mm_sub_epi32(input[14], input[17]);
|
||||
buf1[15] = _mm_add_epi32(input[15], input[16]);
|
||||
buf1[16] = _mm_sub_epi32(input[15], input[16]);
|
||||
buf1[0] = _mm_add_epi32(input[startidx], input[endidx]);
|
||||
buf1[31] = _mm_sub_epi32(input[startidx], input[endidx]);
|
||||
startidx += stride;
|
||||
endidx -= stride;
|
||||
buf1[1] = _mm_add_epi32(input[startidx], input[endidx]);
|
||||
buf1[30] = _mm_sub_epi32(input[startidx], input[endidx]);
|
||||
startidx += stride;
|
||||
endidx -= stride;
|
||||
buf1[2] = _mm_add_epi32(input[startidx], input[endidx]);
|
||||
buf1[29] = _mm_sub_epi32(input[startidx], input[endidx]);
|
||||
startidx += stride;
|
||||
endidx -= stride;
|
||||
buf1[3] = _mm_add_epi32(input[startidx], input[endidx]);
|
||||
buf1[28] = _mm_sub_epi32(input[startidx], input[endidx]);
|
||||
startidx += stride;
|
||||
endidx -= stride;
|
||||
buf1[4] = _mm_add_epi32(input[startidx], input[endidx]);
|
||||
buf1[27] = _mm_sub_epi32(input[startidx], input[endidx]);
|
||||
startidx += stride;
|
||||
endidx -= stride;
|
||||
buf1[5] = _mm_add_epi32(input[startidx], input[endidx]);
|
||||
buf1[26] = _mm_sub_epi32(input[startidx], input[endidx]);
|
||||
startidx += stride;
|
||||
endidx -= stride;
|
||||
buf1[6] = _mm_add_epi32(input[startidx], input[endidx]);
|
||||
buf1[25] = _mm_sub_epi32(input[startidx], input[endidx]);
|
||||
startidx += stride;
|
||||
endidx -= stride;
|
||||
buf1[7] = _mm_add_epi32(input[startidx], input[endidx]);
|
||||
buf1[24] = _mm_sub_epi32(input[startidx], input[endidx]);
|
||||
startidx += stride;
|
||||
endidx -= stride;
|
||||
buf1[8] = _mm_add_epi32(input[startidx], input[endidx]);
|
||||
buf1[23] = _mm_sub_epi32(input[startidx], input[endidx]);
|
||||
startidx += stride;
|
||||
endidx -= stride;
|
||||
buf1[9] = _mm_add_epi32(input[startidx], input[endidx]);
|
||||
buf1[22] = _mm_sub_epi32(input[startidx], input[endidx]);
|
||||
startidx += stride;
|
||||
endidx -= stride;
|
||||
buf1[10] = _mm_add_epi32(input[startidx], input[endidx]);
|
||||
buf1[21] = _mm_sub_epi32(input[startidx], input[endidx]);
|
||||
startidx += stride;
|
||||
endidx -= stride;
|
||||
buf1[11] = _mm_add_epi32(input[startidx], input[endidx]);
|
||||
buf1[20] = _mm_sub_epi32(input[startidx], input[endidx]);
|
||||
startidx += stride;
|
||||
endidx -= stride;
|
||||
buf1[12] = _mm_add_epi32(input[startidx], input[endidx]);
|
||||
buf1[19] = _mm_sub_epi32(input[startidx], input[endidx]);
|
||||
startidx += stride;
|
||||
endidx -= stride;
|
||||
buf1[13] = _mm_add_epi32(input[startidx], input[endidx]);
|
||||
buf1[18] = _mm_sub_epi32(input[startidx], input[endidx]);
|
||||
startidx += stride;
|
||||
endidx -= stride;
|
||||
buf1[14] = _mm_add_epi32(input[startidx], input[endidx]);
|
||||
buf1[17] = _mm_sub_epi32(input[startidx], input[endidx]);
|
||||
startidx += stride;
|
||||
endidx -= stride;
|
||||
buf1[15] = _mm_add_epi32(input[startidx], input[endidx]);
|
||||
buf1[16] = _mm_sub_epi32(input[startidx], input[endidx]);
|
||||
|
||||
// stage 2
|
||||
cospi = cospi_arr(cos_bit);
|
||||
|
|
@ -296,39 +329,71 @@ void av1_fdct32_new_sse4_1(const __m128i *input, __m128i *output,
|
|||
btf_32_sse4_1_type1(cospi[6], cospi[58], buf1[23], buf1[24], buf0[23],
|
||||
buf0[24], cos_bit);
|
||||
|
||||
startidx = 0 * stride;
|
||||
endidx = 31 * stride;
|
||||
// stage 9
|
||||
output[0] = buf0[0];
|
||||
output[1] = buf0[16];
|
||||
output[2] = buf0[8];
|
||||
output[3] = buf0[24];
|
||||
output[4] = buf0[4];
|
||||
output[5] = buf0[20];
|
||||
output[6] = buf0[12];
|
||||
output[7] = buf0[28];
|
||||
output[8] = buf0[2];
|
||||
output[9] = buf0[18];
|
||||
output[10] = buf0[10];
|
||||
output[11] = buf0[26];
|
||||
output[12] = buf0[6];
|
||||
output[13] = buf0[22];
|
||||
output[14] = buf0[14];
|
||||
output[15] = buf0[30];
|
||||
output[16] = buf0[1];
|
||||
output[17] = buf0[17];
|
||||
output[18] = buf0[9];
|
||||
output[19] = buf0[25];
|
||||
output[20] = buf0[5];
|
||||
output[21] = buf0[21];
|
||||
output[22] = buf0[13];
|
||||
output[23] = buf0[29];
|
||||
output[24] = buf0[3];
|
||||
output[25] = buf0[19];
|
||||
output[26] = buf0[11];
|
||||
output[27] = buf0[27];
|
||||
output[28] = buf0[7];
|
||||
output[29] = buf0[23];
|
||||
output[30] = buf0[15];
|
||||
output[31] = buf0[31];
|
||||
output[startidx] = buf0[0];
|
||||
output[endidx] = buf0[31];
|
||||
startidx += stride;
|
||||
endidx -= stride;
|
||||
output[startidx] = buf0[16];
|
||||
output[endidx] = buf0[15];
|
||||
startidx += stride;
|
||||
endidx -= stride;
|
||||
output[startidx] = buf0[8];
|
||||
output[endidx] = buf0[23];
|
||||
startidx += stride;
|
||||
endidx -= stride;
|
||||
output[startidx] = buf0[24];
|
||||
output[endidx] = buf0[7];
|
||||
startidx += stride;
|
||||
endidx -= stride;
|
||||
output[startidx] = buf0[4];
|
||||
output[endidx] = buf0[27];
|
||||
startidx += stride;
|
||||
endidx -= stride;
|
||||
output[startidx] = buf0[20];
|
||||
output[endidx] = buf0[11];
|
||||
startidx += stride;
|
||||
endidx -= stride;
|
||||
output[startidx] = buf0[12];
|
||||
output[endidx] = buf0[19];
|
||||
startidx += stride;
|
||||
endidx -= stride;
|
||||
output[startidx] = buf0[28];
|
||||
output[endidx] = buf0[3];
|
||||
startidx += stride;
|
||||
endidx -= stride;
|
||||
output[startidx] = buf0[2];
|
||||
output[endidx] = buf0[29];
|
||||
startidx += stride;
|
||||
endidx -= stride;
|
||||
output[startidx] = buf0[18];
|
||||
output[endidx] = buf0[13];
|
||||
startidx += stride;
|
||||
endidx -= stride;
|
||||
output[startidx] = buf0[10];
|
||||
output[endidx] = buf0[21];
|
||||
startidx += stride;
|
||||
endidx -= stride;
|
||||
output[startidx] = buf0[26];
|
||||
output[endidx] = buf0[5];
|
||||
startidx += stride;
|
||||
endidx -= stride;
|
||||
output[startidx] = buf0[6];
|
||||
output[endidx] = buf0[25];
|
||||
startidx += stride;
|
||||
endidx -= stride;
|
||||
output[startidx] = buf0[22];
|
||||
output[endidx] = buf0[9];
|
||||
startidx += stride;
|
||||
endidx -= stride;
|
||||
output[startidx] = buf0[14];
|
||||
output[endidx] = buf0[17];
|
||||
startidx += stride;
|
||||
endidx -= stride;
|
||||
output[startidx] = buf0[30];
|
||||
output[endidx] = buf0[1];
|
||||
}
|
||||
|
||||
void av1_fadst4_new_sse4_1(const __m128i *input, __m128i *output,
|
||||
|
|
@ -394,9 +459,8 @@ void av1_fadst4_new_sse4_1(const __m128i *input, __m128i *output,
|
|||
}
|
||||
}
|
||||
|
||||
void av1_fdct64_new_sse4_1(const __m128i *input, __m128i *output,
|
||||
int8_t cos_bit, const int instride,
|
||||
const int outstride) {
|
||||
void av1_fdct64_new_sse4_1(__m128i *input, __m128i *output, int8_t cos_bit,
|
||||
const int instride, const int outstride) {
|
||||
const int32_t *cospi = cospi_arr(cos_bit);
|
||||
const __m128i __rounding = _mm_set1_epi32(1 << (cos_bit - 1));
|
||||
|
||||
|
|
@ -479,72 +543,136 @@ void av1_fdct64_new_sse4_1(const __m128i *input, __m128i *output,
|
|||
__m128i cospi_p03 = _mm_set1_epi32(cospi[3]);
|
||||
__m128i cospi_p61 = _mm_set1_epi32(cospi[61]);
|
||||
|
||||
int startidx = 0 * instride;
|
||||
int endidx = 63 * instride;
|
||||
// stage 1
|
||||
__m128i x1[64];
|
||||
x1[0] = _mm_add_epi32(input[0 * instride], input[63 * instride]);
|
||||
x1[63] = _mm_sub_epi32(input[0 * instride], input[63 * instride]);
|
||||
x1[1] = _mm_add_epi32(input[1 * instride], input[62 * instride]);
|
||||
x1[62] = _mm_sub_epi32(input[1 * instride], input[62 * instride]);
|
||||
x1[2] = _mm_add_epi32(input[2 * instride], input[61 * instride]);
|
||||
x1[61] = _mm_sub_epi32(input[2 * instride], input[61 * instride]);
|
||||
x1[3] = _mm_add_epi32(input[3 * instride], input[60 * instride]);
|
||||
x1[60] = _mm_sub_epi32(input[3 * instride], input[60 * instride]);
|
||||
x1[4] = _mm_add_epi32(input[4 * instride], input[59 * instride]);
|
||||
x1[59] = _mm_sub_epi32(input[4 * instride], input[59 * instride]);
|
||||
x1[5] = _mm_add_epi32(input[5 * instride], input[58 * instride]);
|
||||
x1[58] = _mm_sub_epi32(input[5 * instride], input[58 * instride]);
|
||||
x1[6] = _mm_add_epi32(input[6 * instride], input[57 * instride]);
|
||||
x1[57] = _mm_sub_epi32(input[6 * instride], input[57 * instride]);
|
||||
x1[7] = _mm_add_epi32(input[7 * instride], input[56 * instride]);
|
||||
x1[56] = _mm_sub_epi32(input[7 * instride], input[56 * instride]);
|
||||
x1[8] = _mm_add_epi32(input[8 * instride], input[55 * instride]);
|
||||
x1[55] = _mm_sub_epi32(input[8 * instride], input[55 * instride]);
|
||||
x1[9] = _mm_add_epi32(input[9 * instride], input[54 * instride]);
|
||||
x1[54] = _mm_sub_epi32(input[9 * instride], input[54 * instride]);
|
||||
x1[10] = _mm_add_epi32(input[10 * instride], input[53 * instride]);
|
||||
x1[53] = _mm_sub_epi32(input[10 * instride], input[53 * instride]);
|
||||
x1[11] = _mm_add_epi32(input[11 * instride], input[52 * instride]);
|
||||
x1[52] = _mm_sub_epi32(input[11 * instride], input[52 * instride]);
|
||||
x1[12] = _mm_add_epi32(input[12 * instride], input[51 * instride]);
|
||||
x1[51] = _mm_sub_epi32(input[12 * instride], input[51 * instride]);
|
||||
x1[13] = _mm_add_epi32(input[13 * instride], input[50 * instride]);
|
||||
x1[50] = _mm_sub_epi32(input[13 * instride], input[50 * instride]);
|
||||
x1[14] = _mm_add_epi32(input[14 * instride], input[49 * instride]);
|
||||
x1[49] = _mm_sub_epi32(input[14 * instride], input[49 * instride]);
|
||||
x1[15] = _mm_add_epi32(input[15 * instride], input[48 * instride]);
|
||||
x1[48] = _mm_sub_epi32(input[15 * instride], input[48 * instride]);
|
||||
x1[16] = _mm_add_epi32(input[16 * instride], input[47 * instride]);
|
||||
x1[47] = _mm_sub_epi32(input[16 * instride], input[47 * instride]);
|
||||
x1[17] = _mm_add_epi32(input[17 * instride], input[46 * instride]);
|
||||
x1[46] = _mm_sub_epi32(input[17 * instride], input[46 * instride]);
|
||||
x1[18] = _mm_add_epi32(input[18 * instride], input[45 * instride]);
|
||||
x1[45] = _mm_sub_epi32(input[18 * instride], input[45 * instride]);
|
||||
x1[19] = _mm_add_epi32(input[19 * instride], input[44 * instride]);
|
||||
x1[44] = _mm_sub_epi32(input[19 * instride], input[44 * instride]);
|
||||
x1[20] = _mm_add_epi32(input[20 * instride], input[43 * instride]);
|
||||
x1[43] = _mm_sub_epi32(input[20 * instride], input[43 * instride]);
|
||||
x1[21] = _mm_add_epi32(input[21 * instride], input[42 * instride]);
|
||||
x1[42] = _mm_sub_epi32(input[21 * instride], input[42 * instride]);
|
||||
x1[22] = _mm_add_epi32(input[22 * instride], input[41 * instride]);
|
||||
x1[41] = _mm_sub_epi32(input[22 * instride], input[41 * instride]);
|
||||
x1[23] = _mm_add_epi32(input[23 * instride], input[40 * instride]);
|
||||
x1[40] = _mm_sub_epi32(input[23 * instride], input[40 * instride]);
|
||||
x1[24] = _mm_add_epi32(input[24 * instride], input[39 * instride]);
|
||||
x1[39] = _mm_sub_epi32(input[24 * instride], input[39 * instride]);
|
||||
x1[25] = _mm_add_epi32(input[25 * instride], input[38 * instride]);
|
||||
x1[38] = _mm_sub_epi32(input[25 * instride], input[38 * instride]);
|
||||
x1[26] = _mm_add_epi32(input[26 * instride], input[37 * instride]);
|
||||
x1[37] = _mm_sub_epi32(input[26 * instride], input[37 * instride]);
|
||||
x1[27] = _mm_add_epi32(input[27 * instride], input[36 * instride]);
|
||||
x1[36] = _mm_sub_epi32(input[27 * instride], input[36 * instride]);
|
||||
x1[28] = _mm_add_epi32(input[28 * instride], input[35 * instride]);
|
||||
x1[35] = _mm_sub_epi32(input[28 * instride], input[35 * instride]);
|
||||
x1[29] = _mm_add_epi32(input[29 * instride], input[34 * instride]);
|
||||
x1[34] = _mm_sub_epi32(input[29 * instride], input[34 * instride]);
|
||||
x1[30] = _mm_add_epi32(input[30 * instride], input[33 * instride]);
|
||||
x1[33] = _mm_sub_epi32(input[30 * instride], input[33 * instride]);
|
||||
x1[31] = _mm_add_epi32(input[31 * instride], input[32 * instride]);
|
||||
x1[32] = _mm_sub_epi32(input[31 * instride], input[32 * instride]);
|
||||
x1[0] = _mm_add_epi32(input[startidx], input[endidx]);
|
||||
x1[63] = _mm_sub_epi32(input[startidx], input[endidx]);
|
||||
startidx += instride;
|
||||
endidx -= instride;
|
||||
x1[1] = _mm_add_epi32(input[startidx], input[endidx]);
|
||||
x1[62] = _mm_sub_epi32(input[startidx], input[endidx]);
|
||||
startidx += instride;
|
||||
endidx -= instride;
|
||||
x1[2] = _mm_add_epi32(input[startidx], input[endidx]);
|
||||
x1[61] = _mm_sub_epi32(input[startidx], input[endidx]);
|
||||
startidx += instride;
|
||||
endidx -= instride;
|
||||
x1[3] = _mm_add_epi32(input[startidx], input[endidx]);
|
||||
x1[60] = _mm_sub_epi32(input[startidx], input[endidx]);
|
||||
startidx += instride;
|
||||
endidx -= instride;
|
||||
x1[4] = _mm_add_epi32(input[startidx], input[endidx]);
|
||||
x1[59] = _mm_sub_epi32(input[startidx], input[endidx]);
|
||||
startidx += instride;
|
||||
endidx -= instride;
|
||||
x1[5] = _mm_add_epi32(input[startidx], input[endidx]);
|
||||
x1[58] = _mm_sub_epi32(input[startidx], input[endidx]);
|
||||
startidx += instride;
|
||||
endidx -= instride;
|
||||
x1[6] = _mm_add_epi32(input[startidx], input[endidx]);
|
||||
x1[57] = _mm_sub_epi32(input[startidx], input[endidx]);
|
||||
startidx += instride;
|
||||
endidx -= instride;
|
||||
x1[7] = _mm_add_epi32(input[startidx], input[endidx]);
|
||||
x1[56] = _mm_sub_epi32(input[startidx], input[endidx]);
|
||||
startidx += instride;
|
||||
endidx -= instride;
|
||||
x1[8] = _mm_add_epi32(input[startidx], input[endidx]);
|
||||
x1[55] = _mm_sub_epi32(input[startidx], input[endidx]);
|
||||
startidx += instride;
|
||||
endidx -= instride;
|
||||
x1[9] = _mm_add_epi32(input[startidx], input[endidx]);
|
||||
x1[54] = _mm_sub_epi32(input[startidx], input[endidx]);
|
||||
startidx += instride;
|
||||
endidx -= instride;
|
||||
x1[10] = _mm_add_epi32(input[startidx], input[endidx]);
|
||||
x1[53] = _mm_sub_epi32(input[startidx], input[endidx]);
|
||||
startidx += instride;
|
||||
endidx -= instride;
|
||||
x1[11] = _mm_add_epi32(input[startidx], input[endidx]);
|
||||
x1[52] = _mm_sub_epi32(input[startidx], input[endidx]);
|
||||
startidx += instride;
|
||||
endidx -= instride;
|
||||
x1[12] = _mm_add_epi32(input[startidx], input[endidx]);
|
||||
x1[51] = _mm_sub_epi32(input[startidx], input[endidx]);
|
||||
startidx += instride;
|
||||
endidx -= instride;
|
||||
x1[13] = _mm_add_epi32(input[startidx], input[endidx]);
|
||||
x1[50] = _mm_sub_epi32(input[startidx], input[endidx]);
|
||||
startidx += instride;
|
||||
endidx -= instride;
|
||||
x1[14] = _mm_add_epi32(input[startidx], input[endidx]);
|
||||
x1[49] = _mm_sub_epi32(input[startidx], input[endidx]);
|
||||
startidx += instride;
|
||||
endidx -= instride;
|
||||
x1[15] = _mm_add_epi32(input[startidx], input[endidx]);
|
||||
x1[48] = _mm_sub_epi32(input[startidx], input[endidx]);
|
||||
startidx += instride;
|
||||
endidx -= instride;
|
||||
x1[16] = _mm_add_epi32(input[startidx], input[endidx]);
|
||||
x1[47] = _mm_sub_epi32(input[startidx], input[endidx]);
|
||||
startidx += instride;
|
||||
endidx -= instride;
|
||||
x1[17] = _mm_add_epi32(input[startidx], input[endidx]);
|
||||
x1[46] = _mm_sub_epi32(input[startidx], input[endidx]);
|
||||
startidx += instride;
|
||||
endidx -= instride;
|
||||
x1[18] = _mm_add_epi32(input[startidx], input[endidx]);
|
||||
x1[45] = _mm_sub_epi32(input[startidx], input[endidx]);
|
||||
startidx += instride;
|
||||
endidx -= instride;
|
||||
x1[19] = _mm_add_epi32(input[startidx], input[endidx]);
|
||||
x1[44] = _mm_sub_epi32(input[startidx], input[endidx]);
|
||||
startidx += instride;
|
||||
endidx -= instride;
|
||||
x1[20] = _mm_add_epi32(input[startidx], input[endidx]);
|
||||
x1[43] = _mm_sub_epi32(input[startidx], input[endidx]);
|
||||
startidx += instride;
|
||||
endidx -= instride;
|
||||
x1[21] = _mm_add_epi32(input[startidx], input[endidx]);
|
||||
x1[42] = _mm_sub_epi32(input[startidx], input[endidx]);
|
||||
startidx += instride;
|
||||
endidx -= instride;
|
||||
x1[22] = _mm_add_epi32(input[startidx], input[endidx]);
|
||||
x1[41] = _mm_sub_epi32(input[startidx], input[endidx]);
|
||||
startidx += instride;
|
||||
endidx -= instride;
|
||||
x1[23] = _mm_add_epi32(input[startidx], input[endidx]);
|
||||
x1[40] = _mm_sub_epi32(input[startidx], input[endidx]);
|
||||
startidx += instride;
|
||||
endidx -= instride;
|
||||
x1[24] = _mm_add_epi32(input[startidx], input[endidx]);
|
||||
x1[39] = _mm_sub_epi32(input[startidx], input[endidx]);
|
||||
startidx += instride;
|
||||
endidx -= instride;
|
||||
x1[25] = _mm_add_epi32(input[startidx], input[endidx]);
|
||||
x1[38] = _mm_sub_epi32(input[startidx], input[endidx]);
|
||||
startidx += instride;
|
||||
endidx -= instride;
|
||||
x1[26] = _mm_add_epi32(input[startidx], input[endidx]);
|
||||
x1[37] = _mm_sub_epi32(input[startidx], input[endidx]);
|
||||
startidx += instride;
|
||||
endidx -= instride;
|
||||
x1[27] = _mm_add_epi32(input[startidx], input[endidx]);
|
||||
x1[36] = _mm_sub_epi32(input[startidx], input[endidx]);
|
||||
startidx += instride;
|
||||
endidx -= instride;
|
||||
x1[28] = _mm_add_epi32(input[startidx], input[endidx]);
|
||||
x1[35] = _mm_sub_epi32(input[startidx], input[endidx]);
|
||||
startidx += instride;
|
||||
endidx -= instride;
|
||||
x1[29] = _mm_add_epi32(input[startidx], input[endidx]);
|
||||
x1[34] = _mm_sub_epi32(input[startidx], input[endidx]);
|
||||
startidx += instride;
|
||||
endidx -= instride;
|
||||
x1[30] = _mm_add_epi32(input[startidx], input[endidx]);
|
||||
x1[33] = _mm_sub_epi32(input[startidx], input[endidx]);
|
||||
startidx += instride;
|
||||
endidx -= instride;
|
||||
x1[31] = _mm_add_epi32(input[startidx], input[endidx]);
|
||||
x1[32] = _mm_sub_epi32(input[startidx], input[endidx]);
|
||||
|
||||
// stage 2
|
||||
__m128i x2[64];
|
||||
|
|
@ -1149,69 +1277,141 @@ void av1_fdct64_new_sse4_1(const __m128i *input, __m128i *output,
|
|||
btf_32_type1_sse4_1_new(cospi_p03, cospi_p61, x9[47], x9[48], x10[47],
|
||||
x10[48], __rounding, cos_bit);
|
||||
|
||||
startidx = 0 * outstride;
|
||||
endidx = 63 * outstride;
|
||||
// stage 11
|
||||
output[0 * outstride] = x10[0];
|
||||
output[1 * outstride] = x10[32];
|
||||
output[2 * outstride] = x10[16];
|
||||
output[3 * outstride] = x10[48];
|
||||
output[4 * outstride] = x10[8];
|
||||
output[5 * outstride] = x10[40];
|
||||
output[6 * outstride] = x10[24];
|
||||
output[7 * outstride] = x10[56];
|
||||
output[8 * outstride] = x10[4];
|
||||
output[9 * outstride] = x10[36];
|
||||
output[10 * outstride] = x10[20];
|
||||
output[11 * outstride] = x10[52];
|
||||
output[12 * outstride] = x10[12];
|
||||
output[13 * outstride] = x10[44];
|
||||
output[14 * outstride] = x10[28];
|
||||
output[15 * outstride] = x10[60];
|
||||
output[16 * outstride] = x10[2];
|
||||
output[17 * outstride] = x10[34];
|
||||
output[18 * outstride] = x10[18];
|
||||
output[19 * outstride] = x10[50];
|
||||
output[20 * outstride] = x10[10];
|
||||
output[21 * outstride] = x10[42];
|
||||
output[22 * outstride] = x10[26];
|
||||
output[23 * outstride] = x10[58];
|
||||
output[24 * outstride] = x10[6];
|
||||
output[25 * outstride] = x10[38];
|
||||
output[26 * outstride] = x10[22];
|
||||
output[27 * outstride] = x10[54];
|
||||
output[28 * outstride] = x10[14];
|
||||
output[29 * outstride] = x10[46];
|
||||
output[30 * outstride] = x10[30];
|
||||
output[31 * outstride] = x10[62];
|
||||
output[32 * outstride] = x10[1];
|
||||
output[33 * outstride] = x10[33];
|
||||
output[34 * outstride] = x10[17];
|
||||
output[35 * outstride] = x10[49];
|
||||
output[36 * outstride] = x10[9];
|
||||
output[37 * outstride] = x10[41];
|
||||
output[38 * outstride] = x10[25];
|
||||
output[39 * outstride] = x10[57];
|
||||
output[40 * outstride] = x10[5];
|
||||
output[41 * outstride] = x10[37];
|
||||
output[42 * outstride] = x10[21];
|
||||
output[43 * outstride] = x10[53];
|
||||
output[44 * outstride] = x10[13];
|
||||
output[45 * outstride] = x10[45];
|
||||
output[46 * outstride] = x10[29];
|
||||
output[47 * outstride] = x10[61];
|
||||
output[48 * outstride] = x10[3];
|
||||
output[49 * outstride] = x10[35];
|
||||
output[50 * outstride] = x10[19];
|
||||
output[51 * outstride] = x10[51];
|
||||
output[52 * outstride] = x10[11];
|
||||
output[53 * outstride] = x10[43];
|
||||
output[54 * outstride] = x10[27];
|
||||
output[55 * outstride] = x10[59];
|
||||
output[56 * outstride] = x10[7];
|
||||
output[57 * outstride] = x10[39];
|
||||
output[58 * outstride] = x10[23];
|
||||
output[59 * outstride] = x10[55];
|
||||
output[60 * outstride] = x10[15];
|
||||
output[61 * outstride] = x10[47];
|
||||
output[62 * outstride] = x10[31];
|
||||
output[63 * outstride] = x10[63];
|
||||
output[startidx] = x10[0];
|
||||
output[endidx] = x10[63];
|
||||
startidx += outstride;
|
||||
endidx -= outstride;
|
||||
output[startidx] = x10[32];
|
||||
output[endidx] = x10[31];
|
||||
startidx += outstride;
|
||||
endidx -= outstride;
|
||||
output[startidx] = x10[16];
|
||||
output[endidx] = x10[47];
|
||||
startidx += outstride;
|
||||
endidx -= outstride;
|
||||
output[startidx] = x10[48];
|
||||
output[endidx] = x10[15];
|
||||
startidx += outstride;
|
||||
endidx -= outstride;
|
||||
output[startidx] = x10[8];
|
||||
output[endidx] = x10[55];
|
||||
startidx += outstride;
|
||||
endidx -= outstride;
|
||||
output[startidx] = x10[40];
|
||||
output[endidx] = x10[23];
|
||||
startidx += outstride;
|
||||
endidx -= outstride;
|
||||
output[startidx] = x10[24];
|
||||
output[endidx] = x10[39];
|
||||
startidx += outstride;
|
||||
endidx -= outstride;
|
||||
output[startidx] = x10[56];
|
||||
output[endidx] = x10[7];
|
||||
startidx += outstride;
|
||||
endidx -= outstride;
|
||||
output[startidx] = x10[4];
|
||||
output[endidx] = x10[59];
|
||||
startidx += outstride;
|
||||
endidx -= outstride;
|
||||
output[startidx] = x10[36];
|
||||
output[endidx] = x10[27];
|
||||
startidx += outstride;
|
||||
endidx -= outstride;
|
||||
output[startidx] = x10[20];
|
||||
output[endidx] = x10[43];
|
||||
startidx += outstride;
|
||||
endidx -= outstride;
|
||||
output[startidx] = x10[52];
|
||||
output[endidx] = x10[11];
|
||||
startidx += outstride;
|
||||
endidx -= outstride;
|
||||
output[startidx] = x10[12];
|
||||
output[endidx] = x10[51];
|
||||
startidx += outstride;
|
||||
endidx -= outstride;
|
||||
output[startidx] = x10[44];
|
||||
output[endidx] = x10[19];
|
||||
startidx += outstride;
|
||||
endidx -= outstride;
|
||||
output[startidx] = x10[28];
|
||||
output[endidx] = x10[35];
|
||||
startidx += outstride;
|
||||
endidx -= outstride;
|
||||
output[startidx] = x10[60];
|
||||
output[endidx] = x10[3];
|
||||
startidx += outstride;
|
||||
endidx -= outstride;
|
||||
output[startidx] = x10[2];
|
||||
output[endidx] = x10[61];
|
||||
startidx += outstride;
|
||||
endidx -= outstride;
|
||||
output[startidx] = x10[34];
|
||||
output[endidx] = x10[29];
|
||||
startidx += outstride;
|
||||
endidx -= outstride;
|
||||
output[startidx] = x10[18];
|
||||
output[endidx] = x10[45];
|
||||
startidx += outstride;
|
||||
endidx -= outstride;
|
||||
output[startidx] = x10[50];
|
||||
output[endidx] = x10[13];
|
||||
startidx += outstride;
|
||||
endidx -= outstride;
|
||||
output[startidx] = x10[10];
|
||||
output[endidx] = x10[53];
|
||||
startidx += outstride;
|
||||
endidx -= outstride;
|
||||
output[startidx] = x10[42];
|
||||
output[endidx] = x10[21];
|
||||
startidx += outstride;
|
||||
endidx -= outstride;
|
||||
output[startidx] = x10[26];
|
||||
output[endidx] = x10[37];
|
||||
startidx += outstride;
|
||||
endidx -= outstride;
|
||||
output[startidx] = x10[58];
|
||||
output[endidx] = x10[5];
|
||||
startidx += outstride;
|
||||
endidx -= outstride;
|
||||
output[startidx] = x10[6];
|
||||
output[endidx] = x10[57];
|
||||
startidx += outstride;
|
||||
endidx -= outstride;
|
||||
output[startidx] = x10[38];
|
||||
output[endidx] = x10[25];
|
||||
startidx += outstride;
|
||||
endidx -= outstride;
|
||||
output[startidx] = x10[22];
|
||||
output[endidx] = x10[41];
|
||||
startidx += outstride;
|
||||
endidx -= outstride;
|
||||
output[startidx] = x10[54];
|
||||
output[endidx] = x10[9];
|
||||
startidx += outstride;
|
||||
endidx -= outstride;
|
||||
output[startidx] = x10[14];
|
||||
output[endidx] = x10[49];
|
||||
startidx += outstride;
|
||||
endidx -= outstride;
|
||||
output[startidx] = x10[46];
|
||||
output[endidx] = x10[17];
|
||||
startidx += outstride;
|
||||
endidx -= outstride;
|
||||
output[startidx] = x10[30];
|
||||
output[endidx] = x10[33];
|
||||
startidx += outstride;
|
||||
endidx -= outstride;
|
||||
output[startidx] = x10[62];
|
||||
output[endidx] = x10[1];
|
||||
}
|
||||
|
||||
void av1_idtx32_new_sse4_1(__m128i *input, __m128i *output, int cos_bit,
|
||||
const int col_num) {
|
||||
(void)cos_bit;
|
||||
for (int i = 0; i < 32; i++) {
|
||||
output[i * col_num] = _mm_slli_epi32(input[i * col_num], 2);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1436,45 +1436,6 @@ static INLINE void fidentity16x32_new_avx2(const __m256i *input,
|
|||
}
|
||||
}
|
||||
|
||||
static INLINE void av1_round_shift_array_32_avx2(__m256i *input,
|
||||
__m256i *output,
|
||||
const int size,
|
||||
const int bit) {
|
||||
if (bit > 0) {
|
||||
int i;
|
||||
for (i = 0; i < size; i++) {
|
||||
output[i] = av1_round_shift_32_avx2(input[i], bit);
|
||||
}
|
||||
} else {
|
||||
int i;
|
||||
for (i = 0; i < size; i++) {
|
||||
output[i] = _mm256_slli_epi32(input[i], -bit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static INLINE void av1_round_shift_rect_array_32_avx2(__m256i *input,
|
||||
__m256i *output,
|
||||
const int size,
|
||||
const int bit) {
|
||||
const __m256i sqrt2 = _mm256_set1_epi32(NewSqrt2);
|
||||
if (bit > 0) {
|
||||
int i;
|
||||
for (i = 0; i < size; i++) {
|
||||
const __m256i r0 = av1_round_shift_32_avx2(input[i], bit);
|
||||
const __m256i r1 = _mm256_mullo_epi32(sqrt2, r0);
|
||||
output[i] = av1_round_shift_32_avx2(r1, NewSqrt2Bits);
|
||||
}
|
||||
} else {
|
||||
int i;
|
||||
for (i = 0; i < size; i++) {
|
||||
const __m256i r0 = _mm256_slli_epi32(input[i], -bit);
|
||||
const __m256i r1 = _mm256_mullo_epi32(sqrt2, r0);
|
||||
output[i] = av1_round_shift_32_avx2(r1, NewSqrt2Bits);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static INLINE void transpose_32_8x8_avx2(int stride, const __m256i *inputA,
|
||||
__m256i *output) {
|
||||
__m256i temp0 = _mm256_unpacklo_epi32(inputA[0], inputA[2]);
|
||||
|
|
@ -1540,6 +1501,9 @@ static INLINE void store_rect_buffer_16bit_to_32bit_w16_avx2(
|
|||
}
|
||||
}
|
||||
|
||||
typedef void (*transform_1d_avx2)(const __m256i *input, __m256i *output,
|
||||
int8_t cos_bit);
|
||||
|
||||
static const transform_1d_avx2 col_txfm16x32_arr[TX_TYPES] = {
|
||||
fdct16x32_new_avx2, // DCT_DCT
|
||||
NULL, // ADST_DCT
|
||||
|
|
@ -1885,8 +1849,8 @@ static void lowbd_fwd_txfm2d_64x32_avx2(const int16_t *input, int32_t *output,
|
|||
}
|
||||
av1_fdct64_new_avx2(bufA, bufA, cos_bit_row);
|
||||
av1_fdct64_new_avx2(bufB, bufB, cos_bit_row);
|
||||
av1_round_shift_rect_array_32_avx2(bufA, bufA, 32, -shift[2]);
|
||||
av1_round_shift_rect_array_32_avx2(bufB, bufB, 32, -shift[2]);
|
||||
av1_round_shift_rect_array_32_avx2(bufA, bufA, 32, -shift[2], NewSqrt2);
|
||||
av1_round_shift_rect_array_32_avx2(bufB, bufB, 32, -shift[2], NewSqrt2);
|
||||
|
||||
int32_t *output8 = output + 16 * 32 * i;
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
|
|
@ -1935,8 +1899,8 @@ static void lowbd_fwd_txfm2d_32x64_avx2(const int16_t *input, int32_t *output,
|
|||
}
|
||||
av1_fdct32_new_avx2(bufA, bufA, cos_bit_row);
|
||||
av1_fdct32_new_avx2(bufB, bufB, cos_bit_row);
|
||||
av1_round_shift_rect_array_32_avx2(bufA, bufA, 32, -shift[2]);
|
||||
av1_round_shift_rect_array_32_avx2(bufB, bufB, 32, -shift[2]);
|
||||
av1_round_shift_rect_array_32_avx2(bufA, bufA, 32, -shift[2], NewSqrt2);
|
||||
av1_round_shift_rect_array_32_avx2(bufB, bufB, 32, -shift[2], NewSqrt2);
|
||||
|
||||
int32_t *output8 = output + 16 * 32 * i;
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
|
|
|
|||
|
|
@ -29,31 +29,22 @@ static INLINE void int16_array_with_stride_to_int32_array_without_stride(
|
|||
}
|
||||
}
|
||||
|
||||
typedef void (*TxfmFuncSSE2)(const __m128i *input, __m128i *output,
|
||||
typedef void (*TxfmFuncSSE2)(__m128i *input, __m128i *output,
|
||||
const int8_t cos_bit, const int8_t *stage_range);
|
||||
|
||||
static void fdct32_new_sse4_1(const __m128i *input, __m128i *output,
|
||||
static void fdct32_new_sse4_1(__m128i *input, __m128i *output,
|
||||
const int8_t cos_bit, const int8_t *stage_range) {
|
||||
const int txfm_size = 32;
|
||||
const int num_per_128 = 4;
|
||||
__m128i buf0[32];
|
||||
__m128i buf1[32];
|
||||
int col_num = txfm_size / num_per_128;
|
||||
int col;
|
||||
(void)stage_range;
|
||||
for (col = 0; col < col_num; col++) {
|
||||
int j;
|
||||
for (j = 0; j < 32; ++j) {
|
||||
buf0[j] = input[j * col_num + col];
|
||||
}
|
||||
av1_fdct32_new_sse4_1(buf0, buf1, cos_bit);
|
||||
for (j = 0; j < 32; ++j) {
|
||||
output[j * col_num + col] = buf1[j];
|
||||
}
|
||||
av1_fdct32_new_sse4_1((input + col), (output + col), cos_bit, col_num);
|
||||
}
|
||||
}
|
||||
|
||||
static void fdct64_new_sse4_1(const __m128i *input, __m128i *output,
|
||||
static void fdct64_new_sse4_1(__m128i *input, __m128i *output,
|
||||
const int8_t cos_bit, const int8_t *stage_range) {
|
||||
const int txfm_size = 64;
|
||||
const int num_per_128 = 4;
|
||||
|
|
@ -64,11 +55,20 @@ static void fdct64_new_sse4_1(const __m128i *input, __m128i *output,
|
|||
col_num);
|
||||
}
|
||||
}
|
||||
static void idtx32x32_sse4_1(__m128i *input, __m128i *output,
|
||||
const int8_t cos_bit, const int8_t *stage_range) {
|
||||
(void)stage_range;
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
av1_idtx32_new_sse4_1(&input[i * 32], &output[i * 32], cos_bit, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static INLINE TxfmFuncSSE2 fwd_txfm_type_to_func(TXFM_TYPE txfm_type) {
|
||||
switch (txfm_type) {
|
||||
case TXFM_TYPE_DCT32: return fdct32_new_sse4_1; break;
|
||||
case TXFM_TYPE_DCT64: return fdct64_new_sse4_1; break;
|
||||
case TXFM_TYPE_IDENTITY32: return idtx32x32_sse4_1; break;
|
||||
default: assert(0);
|
||||
}
|
||||
return NULL;
|
||||
|
|
@ -142,7 +142,7 @@ static INLINE void fwd_txfm2d_64x64_sse4_1(const int16_t *input,
|
|||
|
||||
txfm2d_size_128 = (col_num >> 1) * (txfm_size >> 1);
|
||||
av1_round_shift_array_32_sse4_1(out_128, buf_128, txfm2d_size_128, -shift[2]);
|
||||
transpose_32x32(buf_128, out_128);
|
||||
transpose_8nx8n(buf_128, out_128, 32, 32);
|
||||
}
|
||||
|
||||
void av1_fwd_txfm2d_32x32_sse4_1(const int16_t *input, int32_t *output,
|
||||
|
|
@ -317,8 +317,8 @@ static void lowbd_fwd_txfm2d_32x64_sse4_1(const int16_t *input, int32_t *output,
|
|||
bufA[j] = _mm_cvtepi16_epi32(buf[j]);
|
||||
bufB[j] = _mm_cvtepi16_epi32(_mm_unpackhi_epi64(buf[j], buf[j]));
|
||||
}
|
||||
av1_fdct32_new_sse4_1(bufA, bufA, cos_bit_row);
|
||||
av1_fdct32_new_sse4_1(bufB, bufB, cos_bit_row);
|
||||
av1_fdct32_new_sse4_1(bufA, bufA, cos_bit_row, 1);
|
||||
av1_fdct32_new_sse4_1(bufB, bufB, cos_bit_row, 1);
|
||||
av1_round_shift_rect_array_32_sse4_1(bufA, bufA, 32, -shift[2], NewSqrt2);
|
||||
av1_round_shift_rect_array_32_sse4_1(bufB, bufB, 32, -shift[2], NewSqrt2);
|
||||
|
||||
|
|
|
|||
|
|
@ -13,13 +13,6 @@
|
|||
#define AOM_AV1_ENCODER_X86_AV1_FWD_TXFM_AVX2_H_
|
||||
#include <immintrin.h>
|
||||
|
||||
static INLINE __m256i av1_round_shift_32_avx2(__m256i vec, int bit) {
|
||||
__m256i tmp, round;
|
||||
round = _mm256_set1_epi32(1 << (bit - 1));
|
||||
tmp = _mm256_add_epi32(vec, round);
|
||||
return _mm256_srai_epi32(tmp, bit);
|
||||
}
|
||||
|
||||
// out0 = in0*w0 + in1*w1
|
||||
// out1 = -in1*w0 + in0*w1
|
||||
static INLINE void btf_32_avx2_type0(const int32_t w0, const int32_t w1,
|
||||
|
|
|
|||
|
|
@ -26,12 +26,10 @@ void av1_fdct8_new_sse4_1(const __m128i *input, __m128i *output,
|
|||
const int8_t cos_bit, const int8_t *stage_range);
|
||||
void av1_fdct16_new_sse4_1(const __m128i *input, __m128i *output,
|
||||
const int8_t cos_bit, const int8_t *stage_range);
|
||||
void av1_fdct32_new_sse4_1(const __m128i *input, __m128i *output,
|
||||
int8_t cos_bit);
|
||||
void av1_fdct64_new_sse4_1(const __m128i *input, __m128i *output,
|
||||
int8_t cos_bit, const int instride,
|
||||
const int outstride);
|
||||
|
||||
void av1_fdct32_new_sse4_1(__m128i *input, __m128i *output, int cos_bit,
|
||||
const int stride);
|
||||
void av1_fdct64_new_sse4_1(__m128i *input, __m128i *output, int8_t cos_bit,
|
||||
const int instride, const int outstride);
|
||||
void av1_fadst4_new_sse4_1(const __m128i *input, __m128i *output,
|
||||
const int8_t cos_bit, const int8_t *stage_range);
|
||||
void av1_fadst8_new_sse4_1(const __m128i *input, __m128i *output,
|
||||
|
|
@ -56,6 +54,10 @@ void av1_iadst8_new_sse4_1(const __m128i *input, __m128i *output,
|
|||
const int8_t cos_bit, const int8_t *stage_range);
|
||||
void av1_iadst16_new_sse4_1(const __m128i *input, __m128i *output,
|
||||
const int8_t cos_bit, const int8_t *stage_range);
|
||||
|
||||
void av1_idtx32_new_sse4_1(__m128i *input, __m128i *output, int cos_bit,
|
||||
const int col_num);
|
||||
|
||||
static INLINE void transpose_32_4x4(int stride, const __m128i *input,
|
||||
__m128i *output) {
|
||||
__m128i temp0 = _mm_unpacklo_epi32(input[0 * stride], input[2 * stride]);
|
||||
|
|
|
|||
82
third_party/aom/av1/encoder/x86/corner_match_avx2.c
vendored
Normal file
82
third_party/aom/av1/encoder/x86/corner_match_avx2.c
vendored
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <memory.h>
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <immintrin.h>
|
||||
#include "config/av1_rtcd.h"
|
||||
|
||||
#include "aom_ports/mem.h"
|
||||
#include "av1/encoder/corner_match.h"
|
||||
|
||||
DECLARE_ALIGNED(16, static const uint8_t, byte_mask[16]) = {
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0
|
||||
};
|
||||
#if MATCH_SZ != 13
|
||||
#error "Need to change byte_mask in corner_match_sse4.c if MATCH_SZ != 13"
|
||||
#endif
|
||||
|
||||
/* Compute corr(im1, im2) * MATCH_SZ * stddev(im1), where the
|
||||
correlation/standard deviation are taken over MATCH_SZ by MATCH_SZ windows
|
||||
of each image, centered at (x1, y1) and (x2, y2) respectively.
|
||||
*/
|
||||
double compute_cross_correlation_avx2(unsigned char *im1, int stride1, int x1,
|
||||
int y1, unsigned char *im2, int stride2,
|
||||
int x2, int y2) {
|
||||
int i, stride1_i = 0, stride2_i = 0;
|
||||
__m256i temp1, sum_vec, sumsq2_vec, cross_vec, v, v1_1, v2_1;
|
||||
const __m128i mask = _mm_load_si128((__m128i *)byte_mask);
|
||||
const __m256i zero = _mm256_setzero_si256();
|
||||
__m128i v1, v2;
|
||||
|
||||
sum_vec = zero;
|
||||
sumsq2_vec = zero;
|
||||
cross_vec = zero;
|
||||
|
||||
im1 += (y1 - MATCH_SZ_BY2) * stride1 + (x1 - MATCH_SZ_BY2);
|
||||
im2 += (y2 - MATCH_SZ_BY2) * stride2 + (x2 - MATCH_SZ_BY2);
|
||||
|
||||
for (i = 0; i < MATCH_SZ; ++i) {
|
||||
v1 = _mm_and_si128(_mm_loadu_si128((__m128i *)&im1[stride1_i]), mask);
|
||||
v1_1 = _mm256_cvtepu8_epi16(v1);
|
||||
v2 = _mm_and_si128(_mm_loadu_si128((__m128i *)&im2[stride2_i]), mask);
|
||||
v2_1 = _mm256_cvtepu8_epi16(v2);
|
||||
|
||||
v = _mm256_insertf128_si256(_mm256_castsi128_si256(v1), v2, 1);
|
||||
sumsq2_vec = _mm256_add_epi32(sumsq2_vec, _mm256_madd_epi16(v2_1, v2_1));
|
||||
|
||||
sum_vec = _mm256_add_epi16(sum_vec, _mm256_sad_epu8(v, zero));
|
||||
cross_vec = _mm256_add_epi32(cross_vec, _mm256_madd_epi16(v1_1, v2_1));
|
||||
stride1_i += stride1;
|
||||
stride2_i += stride2;
|
||||
}
|
||||
__m256i sum_vec1 = _mm256_srli_si256(sum_vec, 8);
|
||||
sum_vec = _mm256_add_epi32(sum_vec, sum_vec1);
|
||||
int sum1_acc = _mm_cvtsi128_si32(_mm256_castsi256_si128(sum_vec));
|
||||
int sum2_acc = _mm256_extract_epi32(sum_vec, 4);
|
||||
|
||||
__m256i unp_low = _mm256_unpacklo_epi64(sumsq2_vec, cross_vec);
|
||||
__m256i unp_hig = _mm256_unpackhi_epi64(sumsq2_vec, cross_vec);
|
||||
temp1 = _mm256_add_epi32(unp_low, unp_hig);
|
||||
|
||||
__m128i low_sumsq = _mm256_castsi256_si128(temp1);
|
||||
low_sumsq = _mm_add_epi32(low_sumsq, _mm256_extractf128_si256(temp1, 1));
|
||||
low_sumsq = _mm_add_epi32(low_sumsq, _mm_srli_epi64(low_sumsq, 32));
|
||||
int sumsq2_acc = _mm_cvtsi128_si32(low_sumsq);
|
||||
int cross_acc = _mm_extract_epi32(low_sumsq, 2);
|
||||
|
||||
int var2 = sumsq2_acc * MATCH_SZ_SQ - sum2_acc * sum2_acc;
|
||||
int cov = cross_acc * MATCH_SZ_SQ - sum1_acc * sum2_acc;
|
||||
return cov / sqrt((double)var2);
|
||||
}
|
||||
|
|
@ -26,14 +26,6 @@ void av1_txb_init_levels_avx2(const tran_low_t *const coeff, const int width,
|
|||
const int stride = width + TX_PAD_HOR;
|
||||
const __m256i y_zeros = _mm256_setzero_si256();
|
||||
|
||||
const int32_t pre_len = sizeof(*levels) * TX_PAD_TOP * stride;
|
||||
uint8_t *pre_buf = levels - TX_PAD_TOP * stride;
|
||||
uint8_t *pre_buf_end = pre_buf + pre_len;
|
||||
do {
|
||||
yy_storeu_256(pre_buf, y_zeros);
|
||||
pre_buf += 32;
|
||||
} while (pre_buf < pre_buf_end);
|
||||
|
||||
const int32_t bottom_len = sizeof(*levels) * (TX_PAD_BOTTOM * stride);
|
||||
uint8_t *bottom_buf_end = levels + (height + TX_PAD_BOTTOM) * stride;
|
||||
uint8_t *bottom_buf = bottom_buf_end - ((bottom_len + 31) & (~31));
|
||||
|
|
|
|||
|
|
@ -23,14 +23,6 @@ void av1_txb_init_levels_sse4_1(const tran_low_t *const coeff, const int width,
|
|||
const int stride = width + TX_PAD_HOR;
|
||||
const __m128i zeros = _mm_setzero_si128();
|
||||
|
||||
const int32_t pre_len = sizeof(*levels) * TX_PAD_TOP * stride;
|
||||
uint8_t *pre_buf = levels - TX_PAD_TOP * stride;
|
||||
uint8_t *pre_buf_end = pre_buf + pre_len;
|
||||
do {
|
||||
_mm_storeu_si128((__m128i *)(pre_buf), zeros);
|
||||
pre_buf += 16;
|
||||
} while (pre_buf < pre_buf_end);
|
||||
|
||||
const int32_t bottom_len = sizeof(*levels) * (TX_PAD_BOTTOM * stride);
|
||||
uint8_t *bottom_buf = levels + stride * height;
|
||||
uint8_t *bottom_buf_end = bottom_buf + bottom_len;
|
||||
|
|
|
|||
3170
third_party/aom/av1/encoder/x86/highbd_fwd_txfm_avx2.c
vendored
Normal file
3170
third_party/aom/av1/encoder/x86/highbd_fwd_txfm_avx2.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
1225
third_party/aom/av1/encoder/x86/highbd_fwd_txfm_sse4.c
vendored
1225
third_party/aom/av1/encoder/x86/highbd_fwd_txfm_sse4.c
vendored
File diff suppressed because it is too large
Load diff
243
third_party/aom/av1/encoder/x86/ml_sse3.c
vendored
Normal file
243
third_party/aom/av1/encoder/x86/ml_sse3.c
vendored
Normal file
|
|
@ -0,0 +1,243 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
#include <pmmintrin.h>
|
||||
|
||||
#include "config/av1_rtcd.h"
|
||||
#include "av1/encoder/ml.h"
|
||||
|
||||
// In order to avoid the high-latency of swapping between FPU and SIMD
|
||||
// operations, we keep the result in a 128-bit register even though we only
|
||||
// care about a single value.
|
||||
static void nn_propagate_8to1(const float *const inputs,
|
||||
const float *const weights,
|
||||
__m128 *const output) {
|
||||
const __m128 inputs_h = _mm_loadu_ps(&inputs[4]);
|
||||
const __m128 inputs_l = _mm_loadu_ps(inputs);
|
||||
|
||||
const __m128 weights_h = _mm_loadu_ps(&weights[4]);
|
||||
const __m128 weights_l = _mm_loadu_ps(weights);
|
||||
|
||||
const __m128 mul_h = _mm_mul_ps(inputs_h, weights_h);
|
||||
const __m128 mul_l = _mm_mul_ps(inputs_l, weights_l);
|
||||
// [7 6 5 4] [3 2 1 0] (weight and input indices)
|
||||
|
||||
const __m128 vadd = _mm_add_ps(mul_l, mul_h);
|
||||
// [7+3 6+2 5+1 4+0]
|
||||
const __m128 hadd1 = _mm_hadd_ps(vadd, vadd);
|
||||
// [7+6+3+2 5+4+1+0 7+6+3+2 5+4+1+0]
|
||||
const __m128 hadd2 = _mm_hadd_ps(hadd1, hadd1);
|
||||
// [7+6+5+4+3+2+1+0 7+6+5+4+3+2+1+0 7+6+5+4+3+2+1+0 7+6+5+4+3+2+1+0]
|
||||
*output = _mm_add_ps(*output, hadd2);
|
||||
}
|
||||
|
||||
static void nn_propagate_4to1(const float *const inputs,
|
||||
const float *const weights,
|
||||
__m128 *const output) {
|
||||
const __m128 inputs128 = _mm_loadu_ps(inputs);
|
||||
|
||||
const __m128 weights128 = _mm_loadu_ps(weights);
|
||||
|
||||
const __m128 mul = _mm_mul_ps(inputs128, weights128);
|
||||
// [3 2 1 0] (weight and input indices)
|
||||
|
||||
const __m128 hadd1 = _mm_hadd_ps(mul, mul);
|
||||
// [3+2 1+0 3+2 1+0]
|
||||
const __m128 hadd2 = _mm_hadd_ps(hadd1, hadd1);
|
||||
// [3+2+1+0 3+2+1+0 3+2+1+0 3+2+1+0]
|
||||
*output = _mm_add_ps(*output, hadd2);
|
||||
}
|
||||
|
||||
static void nn_propagate_4to4(const float *const inputs,
|
||||
const float *const weights, __m128 *const outputs,
|
||||
const int num_inputs) {
|
||||
const __m128 inputs128 = _mm_loadu_ps(inputs);
|
||||
|
||||
__m128 hadd[2];
|
||||
for (int i = 0; i < 2; i++) { // For each pair of outputs
|
||||
const __m128 weight0 = _mm_loadu_ps(&weights[2 * i * num_inputs]);
|
||||
const __m128 mul0 = _mm_mul_ps(weight0, inputs128);
|
||||
const __m128 weight1 = _mm_loadu_ps(&weights[(2 * i + 1) * num_inputs]);
|
||||
const __m128 mul1 = _mm_mul_ps(weight1, inputs128);
|
||||
hadd[i] = _mm_hadd_ps(mul0, mul1);
|
||||
}
|
||||
// hadd[0] = [7+6 5+4 3+2 1+0] (weight indices)
|
||||
// hadd[1] = [15+14 13+12 11+10 9+8]
|
||||
|
||||
const __m128 hh = _mm_hadd_ps(hadd[0], hadd[1]);
|
||||
// [15+14+13+12 11+10+9+8 7+6+5+4 3+2+1+0]
|
||||
|
||||
*outputs = _mm_add_ps(*outputs, hh);
|
||||
}
|
||||
|
||||
static void nn_propagate_4to8(const float *const inputs,
|
||||
const float *const weights, __m128 *const out_h,
|
||||
__m128 *const out_l, const int num_inputs) {
|
||||
const __m128 inputs128 = _mm_loadu_ps(inputs);
|
||||
|
||||
__m128 hadd[4];
|
||||
for (int i = 0; i < 4; i++) { // For each pair of outputs
|
||||
const __m128 weight0 = _mm_loadu_ps(&weights[2 * i * num_inputs]);
|
||||
const __m128 weight1 = _mm_loadu_ps(&weights[(2 * i + 1) * num_inputs]);
|
||||
const __m128 mul0 = _mm_mul_ps(inputs128, weight0);
|
||||
const __m128 mul1 = _mm_mul_ps(inputs128, weight1);
|
||||
hadd[i] = _mm_hadd_ps(mul0, mul1);
|
||||
}
|
||||
// hadd[0] = [7+6 5+4 3+2 1+0] (weight indices)
|
||||
// hadd[1] = [15+14 13+12 11+10 9+8]
|
||||
// hadd[2] = [23+22 21+20 19+18 17+16]
|
||||
// hadd[3] = [31+30 29+28 27+26 25+24]
|
||||
|
||||
const __m128 hh0 = _mm_hadd_ps(hadd[0], hadd[1]);
|
||||
// [15+14+13+12 11+10+9+8 7+6+5+4 3+2+1+0]
|
||||
const __m128 hh1 = _mm_hadd_ps(hadd[2], hadd[3]);
|
||||
// [31+30+29+28 27+26+25+24 23+22+21+20 19+18+17+16]
|
||||
|
||||
*out_h = _mm_add_ps(*out_h, hh1);
|
||||
*out_l = _mm_add_ps(*out_l, hh0);
|
||||
}
|
||||
|
||||
static void nn_propagate_8to4(const float *const inputs,
|
||||
const float *const weights, __m128 *const outputs,
|
||||
const int num_inputs) {
|
||||
const __m128 inputs_h = _mm_loadu_ps(inputs + 4);
|
||||
const __m128 inputs_l = _mm_loadu_ps(inputs);
|
||||
// [7 6 5 4] [3 2 1 0] (input indices)
|
||||
|
||||
__m128 add[4];
|
||||
for (int i = 0; i < 4; i++) { // For each output:
|
||||
const __m128 weight_h = _mm_loadu_ps(&weights[i * num_inputs + 4]);
|
||||
const __m128 weight_l = _mm_loadu_ps(&weights[i * num_inputs]);
|
||||
const __m128 mul_h = _mm_mul_ps(inputs_h, weight_h);
|
||||
const __m128 mul_l = _mm_mul_ps(inputs_l, weight_l);
|
||||
add[i] = _mm_add_ps(mul_l, mul_h);
|
||||
}
|
||||
// add[0] = [7+3 6+2 5+1 4+0]
|
||||
// add[1] = [15+11 14+10 13+9 12+8]
|
||||
// add[2] = [23+19 22+18 21+17 20+16]
|
||||
// add[3] = [31+27 30+26 29+25 28+24]
|
||||
|
||||
const __m128 hadd_h = _mm_hadd_ps(add[2], add[3]);
|
||||
// [31+30+27+26 29+28+25+24 23+22+19+18 21+20+17+16]
|
||||
const __m128 hadd_l = _mm_hadd_ps(add[0], add[1]);
|
||||
// [15+14+11+10 13+12+9+8 7+6+3+2 5+4+1+0]
|
||||
|
||||
const __m128 haddhadd = _mm_hadd_ps(hadd_l, hadd_h);
|
||||
// [31+30+29+28+27+26+25+24 23+22+21+20+19+18+17+16
|
||||
// 15+14+13+12+11+10+9+8 7+6+5+4+3+2+1+0]
|
||||
|
||||
*outputs = _mm_add_ps(*outputs, haddhadd);
|
||||
}
|
||||
|
||||
static void nn_activate8(__m128 *out_h, __m128 *out_l) {
|
||||
const __m128 zero = _mm_setzero_ps();
|
||||
*out_h = _mm_max_ps(*out_h, zero);
|
||||
*out_l = _mm_max_ps(*out_l, zero);
|
||||
}
|
||||
|
||||
static void nn_activate4(__m128 *x) { *x = _mm_max_ps(*x, _mm_setzero_ps()); }
|
||||
|
||||
// Calculate prediction based on the given input features and neural net config.
|
||||
// Assume there are no more than NN_MAX_NODES_PER_LAYER nodes in each hidden
|
||||
// layer.
|
||||
void av1_nn_predict_sse3(const float *input_nodes,
|
||||
const NN_CONFIG *const nn_config,
|
||||
float *const output) {
|
||||
float buf[2][NN_MAX_NODES_PER_LAYER];
|
||||
int buf_index = 0;
|
||||
int num_inputs = nn_config->num_inputs;
|
||||
|
||||
// Hidden layers, except the final iteration is the output layer.
|
||||
for (int layer = 0; layer <= nn_config->num_hidden_layers; layer++) {
|
||||
const float *layer_weights = nn_config->weights[layer];
|
||||
const float *layer_bias = nn_config->bias[layer];
|
||||
bool output_layer = (layer == nn_config->num_hidden_layers);
|
||||
float *const output_nodes = output_layer ? output : buf[buf_index];
|
||||
const int num_outputs = output_layer ? nn_config->num_outputs
|
||||
: nn_config->num_hidden_nodes[layer];
|
||||
|
||||
if (num_inputs % 4 == 0 && num_outputs % 8 == 0) {
|
||||
for (int out = 0; out < num_outputs; out += 8) {
|
||||
__m128 out_h = _mm_loadu_ps(&layer_bias[out + 4]);
|
||||
__m128 out_l = _mm_loadu_ps(&layer_bias[out]);
|
||||
for (int in = 0; in < num_inputs; in += 4) {
|
||||
nn_propagate_4to8(&input_nodes[in],
|
||||
&layer_weights[out * num_inputs + in], &out_h,
|
||||
&out_l, num_inputs);
|
||||
}
|
||||
if (!output_layer) nn_activate8(&out_h, &out_l);
|
||||
_mm_storeu_ps(&output_nodes[out + 4], out_h);
|
||||
_mm_storeu_ps(&output_nodes[out], out_l);
|
||||
}
|
||||
} else if (num_inputs % 8 == 0 && num_outputs % 4 == 0) {
|
||||
for (int out = 0; out < num_outputs; out += 4) {
|
||||
__m128 outputs = _mm_loadu_ps(&layer_bias[out]);
|
||||
for (int in = 0; in < num_inputs; in += 8) {
|
||||
nn_propagate_8to4(&input_nodes[in],
|
||||
&layer_weights[out * num_inputs + in], &outputs,
|
||||
num_inputs);
|
||||
}
|
||||
if (!output_layer) nn_activate4(&outputs);
|
||||
_mm_storeu_ps(&output_nodes[out], outputs);
|
||||
}
|
||||
} else if (num_inputs % 4 == 0 && num_outputs % 4 == 0) {
|
||||
for (int out = 0; out < num_outputs; out += 4) {
|
||||
__m128 outputs = _mm_loadu_ps(&layer_bias[out]);
|
||||
for (int in = 0; in < num_inputs; in += 4) {
|
||||
nn_propagate_4to4(&input_nodes[in],
|
||||
&layer_weights[out * num_inputs + in], &outputs,
|
||||
num_inputs);
|
||||
}
|
||||
if (!output_layer) nn_activate4(&outputs);
|
||||
_mm_storeu_ps(&output_nodes[out], outputs);
|
||||
}
|
||||
} else if (num_inputs % 8 == 0) {
|
||||
for (int out = 0; out < num_outputs; out++) {
|
||||
__m128 total = _mm_load1_ps(&layer_bias[out]);
|
||||
for (int in = 0; in < num_inputs; in += 8) {
|
||||
nn_propagate_8to1(&input_nodes[in],
|
||||
&layer_weights[out * num_inputs + in], &total);
|
||||
}
|
||||
if (!output_layer) nn_activate4(&total);
|
||||
output_nodes[out] = _mm_cvtss_f32(total);
|
||||
}
|
||||
} else if (num_inputs % 4 == 0) {
|
||||
for (int out = 0; out < num_outputs; out++) {
|
||||
__m128 total = _mm_load1_ps(&layer_bias[out]);
|
||||
for (int in = 0; in < num_inputs; in += 4) {
|
||||
nn_propagate_4to1(&input_nodes[in],
|
||||
&layer_weights[out * num_inputs + in], &total);
|
||||
}
|
||||
if (!output_layer) nn_activate4(&total);
|
||||
output_nodes[out] = _mm_cvtss_f32(total);
|
||||
}
|
||||
} else {
|
||||
// Use SSE instructions for scalar operations to avoid the latency of
|
||||
// swapping between SIMD and FPU modes.
|
||||
for (int out = 0; out < num_outputs; out++) {
|
||||
__m128 total = _mm_load1_ps(&layer_bias[out]);
|
||||
for (int in_node = 0; in_node < num_inputs; in_node++) {
|
||||
__m128 input = _mm_load1_ps(&input_nodes[in_node]);
|
||||
__m128 weight =
|
||||
_mm_load1_ps(&layer_weights[num_inputs * out + in_node]);
|
||||
total = _mm_add_ps(total, _mm_mul_ps(input, weight));
|
||||
}
|
||||
if (!output_layer) nn_activate4(&total);
|
||||
output_nodes[out] = _mm_cvtss_f32(total);
|
||||
}
|
||||
}
|
||||
input_nodes = output_nodes;
|
||||
num_inputs = num_outputs;
|
||||
buf_index = 1 - buf_index;
|
||||
}
|
||||
}
|
||||
576
third_party/aom/av1/encoder/x86/pickrst_avx2.c
vendored
576
third_party/aom/av1/encoder/x86/pickrst_avx2.c
vendored
|
|
@ -64,14 +64,13 @@ static INLINE void acc_stat_win7_one_line_avx2(
|
|||
|
||||
static INLINE void compute_stats_win7_opt_avx2(
|
||||
const uint8_t *dgd, const uint8_t *src, int h_start, int h_end, int v_start,
|
||||
int v_end, int dgd_stride, int src_stride, double *M, double *H) {
|
||||
int v_end, int dgd_stride, int src_stride, int64_t *M, int64_t *H) {
|
||||
int i, j, k, l, m, n;
|
||||
const int wiener_win = WIENER_WIN;
|
||||
const int pixel_count = (h_end - h_start) * (v_end - v_start);
|
||||
const int wiener_win2 = wiener_win * wiener_win;
|
||||
const int wiener_halfwin = (wiener_win >> 1);
|
||||
const double avg =
|
||||
find_average(dgd, h_start, h_end, v_start, v_end, dgd_stride);
|
||||
uint8_t avg = find_average(dgd, h_start, h_end, v_start, v_end, dgd_stride);
|
||||
|
||||
int32_t M_int32[WIENER_WIN][WIENER_WIN] = { { 0 } };
|
||||
int64_t M_int64[WIENER_WIN][WIENER_WIN] = { { 0 } };
|
||||
|
|
@ -103,23 +102,281 @@ static INLINE void compute_stats_win7_opt_avx2(
|
|||
}
|
||||
}
|
||||
|
||||
const double avg_square_sum = avg * avg * pixel_count;
|
||||
const int64_t avg_square_sum = (int64_t)avg * (int64_t)avg * pixel_count;
|
||||
for (k = 0; k < wiener_win; k++) {
|
||||
for (l = 0; l < wiener_win; l++) {
|
||||
const int32_t idx0 = l * wiener_win + k;
|
||||
M[idx0] = M_int64[k][l] + avg_square_sum - avg * (sumX + sumY[k][l]);
|
||||
double *H_ = H + idx0 * wiener_win2;
|
||||
M[idx0] =
|
||||
M_int64[k][l] + (avg_square_sum - (int64_t)avg * (sumX + sumY[k][l]));
|
||||
int64_t *H_ = H + idx0 * wiener_win2;
|
||||
int64_t *H_int_ = &H_int64[idx0][0];
|
||||
for (m = 0; m < wiener_win; m++) {
|
||||
for (n = 0; n < wiener_win; n++) {
|
||||
H_[m * wiener_win + n] = H_int_[n * 8 + m] + avg_square_sum -
|
||||
avg * (sumY[k][l] + sumY[n][m]);
|
||||
(int64_t)avg * (sumY[k][l] + sumY[n][m]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static INLINE void acc_stat_highbd_avx2(int64_t *dst, const uint16_t *dgd,
|
||||
const __m256i *shuffle,
|
||||
const __m256i *dgd_ijkl) {
|
||||
// Load two 128-bit chunks from dgd
|
||||
const __m256i s0 = _mm256_inserti128_si256(
|
||||
_mm256_castsi128_si256(_mm_loadu_si128((__m128i *)dgd)),
|
||||
_mm_loadu_si128((__m128i *)(dgd + 4)), 1);
|
||||
// s0 = [11 10 9 8 7 6 5 4] [7 6 5 4 3 2 1 0] as u16 (values are dgd indices)
|
||||
// The weird order is so the shuffle stays within 128-bit lanes
|
||||
|
||||
// Shuffle 16x u16 values within lanes according to the mask:
|
||||
// [0 1 1 2 2 3 3 4] [0 1 1 2 2 3 3 4]
|
||||
// (Actually we shuffle u8 values as there's no 16-bit shuffle)
|
||||
const __m256i s1 = _mm256_shuffle_epi8(s0, *shuffle);
|
||||
// s1 = [8 7 7 6 6 5 5 4] [4 3 3 2 2 1 1 0] as u16 (values are dgd indices)
|
||||
|
||||
// Multiply 16x 16-bit integers in dgd_ijkl and s1, resulting in 16x 32-bit
|
||||
// integers then horizontally add pairs of these integers resulting in 8x
|
||||
// 32-bit integers
|
||||
const __m256i d0 = _mm256_madd_epi16(*dgd_ijkl, s1);
|
||||
// d0 = [a b c d] [e f g h] as u32
|
||||
|
||||
// Take the lower-half of d0, extend to u64, add it on to dst (H)
|
||||
const __m256i d0l = _mm256_cvtepu32_epi64(_mm256_extracti128_si256(d0, 0));
|
||||
// d0l = [a b] [c d] as u64
|
||||
const __m256i dst0 = yy_loadu_256(dst);
|
||||
yy_storeu_256(dst, _mm256_add_epi64(d0l, dst0));
|
||||
|
||||
// Take the upper-half of d0, extend to u64, add it on to dst (H)
|
||||
const __m256i d0h = _mm256_cvtepu32_epi64(_mm256_extracti128_si256(d0, 1));
|
||||
// d0h = [e f] [g h] as u64
|
||||
const __m256i dst1 = yy_loadu_256(dst + 4);
|
||||
yy_storeu_256(dst + 4, _mm256_add_epi64(d0h, dst1));
|
||||
}
|
||||
|
||||
static INLINE void acc_stat_highbd_win7_one_line_avx2(
|
||||
const uint16_t *dgd, const uint16_t *src, int h_start, int h_end,
|
||||
int dgd_stride, const __m256i *shuffle, int32_t *sumX,
|
||||
int32_t sumY[WIENER_WIN][WIENER_WIN], int64_t M_int[WIENER_WIN][WIENER_WIN],
|
||||
int64_t H_int[WIENER_WIN2][WIENER_WIN * 8]) {
|
||||
int j, k, l;
|
||||
const int wiener_win = WIENER_WIN;
|
||||
for (j = h_start; j < h_end; j += 2) {
|
||||
const uint16_t X1 = src[j];
|
||||
const uint16_t X2 = src[j + 1];
|
||||
*sumX += X1 + X2;
|
||||
const uint16_t *dgd_ij = dgd + j;
|
||||
for (k = 0; k < wiener_win; k++) {
|
||||
const uint16_t *dgd_ijk = dgd_ij + k * dgd_stride;
|
||||
for (l = 0; l < wiener_win; l++) {
|
||||
int64_t *H_ = &H_int[(l * wiener_win + k)][0];
|
||||
const uint16_t D1 = dgd_ijk[l];
|
||||
const uint16_t D2 = dgd_ijk[l + 1];
|
||||
sumY[k][l] += D1 + D2;
|
||||
M_int[k][l] += D1 * X1 + D2 * X2;
|
||||
|
||||
// Load two u16 values from dgd_ijkl combined as a u32,
|
||||
// then broadcast to 8x u32 slots of a 256
|
||||
const __m256i dgd_ijkl =
|
||||
_mm256_set1_epi32(*((uint32_t *)(dgd_ijk + l)));
|
||||
// dgd_ijkl = [y x y x y x y x] [y x y x y x y x] where each is a u16
|
||||
|
||||
acc_stat_highbd_avx2(H_ + 0 * 8, dgd_ij + 0 * dgd_stride, shuffle,
|
||||
&dgd_ijkl);
|
||||
acc_stat_highbd_avx2(H_ + 1 * 8, dgd_ij + 1 * dgd_stride, shuffle,
|
||||
&dgd_ijkl);
|
||||
acc_stat_highbd_avx2(H_ + 2 * 8, dgd_ij + 2 * dgd_stride, shuffle,
|
||||
&dgd_ijkl);
|
||||
acc_stat_highbd_avx2(H_ + 3 * 8, dgd_ij + 3 * dgd_stride, shuffle,
|
||||
&dgd_ijkl);
|
||||
acc_stat_highbd_avx2(H_ + 4 * 8, dgd_ij + 4 * dgd_stride, shuffle,
|
||||
&dgd_ijkl);
|
||||
acc_stat_highbd_avx2(H_ + 5 * 8, dgd_ij + 5 * dgd_stride, shuffle,
|
||||
&dgd_ijkl);
|
||||
acc_stat_highbd_avx2(H_ + 6 * 8, dgd_ij + 6 * dgd_stride, shuffle,
|
||||
&dgd_ijkl);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static INLINE void compute_stats_highbd_win7_opt_avx2(
|
||||
const uint8_t *dgd8, const uint8_t *src8, int h_start, int h_end,
|
||||
int v_start, int v_end, int dgd_stride, int src_stride, int64_t *M,
|
||||
int64_t *H, aom_bit_depth_t bit_depth) {
|
||||
int i, j, k, l, m, n;
|
||||
const int wiener_win = WIENER_WIN;
|
||||
const int pixel_count = (h_end - h_start) * (v_end - v_start);
|
||||
const int wiener_win2 = wiener_win * wiener_win;
|
||||
const int wiener_halfwin = (wiener_win >> 1);
|
||||
const uint16_t *src = CONVERT_TO_SHORTPTR(src8);
|
||||
const uint16_t *dgd = CONVERT_TO_SHORTPTR(dgd8);
|
||||
const uint16_t avg =
|
||||
find_average_highbd(dgd, h_start, h_end, v_start, v_end, dgd_stride);
|
||||
|
||||
int64_t M_int[WIENER_WIN][WIENER_WIN] = { { 0 } };
|
||||
int64_t H_int[WIENER_WIN2][WIENER_WIN * 8] = { { 0 } };
|
||||
int32_t sumY[WIENER_WIN][WIENER_WIN] = { { 0 } };
|
||||
int32_t sumX = 0;
|
||||
const uint16_t *dgd_win = dgd - wiener_halfwin * dgd_stride - wiener_halfwin;
|
||||
|
||||
const __m256i shuffle = yy_loadu_256(g_shuffle_stats_highbd_data);
|
||||
for (j = v_start; j < v_end; j += 64) {
|
||||
const int vert_end = AOMMIN(64, v_end - j) + j;
|
||||
for (i = j; i < vert_end; i++) {
|
||||
acc_stat_highbd_win7_one_line_avx2(
|
||||
dgd_win + i * dgd_stride, src + i * src_stride, h_start, h_end,
|
||||
dgd_stride, &shuffle, &sumX, sumY, M_int, H_int);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t bit_depth_divider = 1;
|
||||
if (bit_depth == AOM_BITS_12)
|
||||
bit_depth_divider = 16;
|
||||
else if (bit_depth == AOM_BITS_10)
|
||||
bit_depth_divider = 4;
|
||||
|
||||
const int64_t avg_square_sum = (int64_t)avg * (int64_t)avg * pixel_count;
|
||||
for (k = 0; k < wiener_win; k++) {
|
||||
for (l = 0; l < wiener_win; l++) {
|
||||
const int32_t idx0 = l * wiener_win + k;
|
||||
M[idx0] = (M_int[k][l] +
|
||||
(avg_square_sum - (int64_t)avg * (sumX + sumY[k][l]))) /
|
||||
bit_depth_divider;
|
||||
int64_t *H_ = H + idx0 * wiener_win2;
|
||||
int64_t *H_int_ = &H_int[idx0][0];
|
||||
for (m = 0; m < wiener_win; m++) {
|
||||
for (n = 0; n < wiener_win; n++) {
|
||||
H_[m * wiener_win + n] =
|
||||
(H_int_[n * 8 + m] +
|
||||
(avg_square_sum - (int64_t)avg * (sumY[k][l] + sumY[n][m]))) /
|
||||
bit_depth_divider;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static INLINE void acc_stat_highbd_win5_one_line_avx2(
|
||||
const uint16_t *dgd, const uint16_t *src, int h_start, int h_end,
|
||||
int dgd_stride, const __m256i *shuffle, int32_t *sumX,
|
||||
int32_t sumY[WIENER_WIN_CHROMA][WIENER_WIN_CHROMA],
|
||||
int64_t M_int[WIENER_WIN_CHROMA][WIENER_WIN_CHROMA],
|
||||
int64_t H_int[WIENER_WIN2_CHROMA][WIENER_WIN_CHROMA * 8]) {
|
||||
int j, k, l;
|
||||
const int wiener_win = WIENER_WIN_CHROMA;
|
||||
for (j = h_start; j < h_end; j += 2) {
|
||||
const uint16_t X1 = src[j];
|
||||
const uint16_t X2 = src[j + 1];
|
||||
*sumX += X1 + X2;
|
||||
const uint16_t *dgd_ij = dgd + j;
|
||||
for (k = 0; k < wiener_win; k++) {
|
||||
const uint16_t *dgd_ijk = dgd_ij + k * dgd_stride;
|
||||
for (l = 0; l < wiener_win; l++) {
|
||||
int64_t *H_ = &H_int[(l * wiener_win + k)][0];
|
||||
const uint16_t D1 = dgd_ijk[l];
|
||||
const uint16_t D2 = dgd_ijk[l + 1];
|
||||
sumY[k][l] += D1 + D2;
|
||||
M_int[k][l] += D1 * X1 + D2 * X2;
|
||||
|
||||
// Load two u16 values from dgd_ijkl combined as a u32,
|
||||
// then broadcast to 8x u32 slots of a 256
|
||||
const __m256i dgd_ijkl =
|
||||
_mm256_set1_epi32(*((uint32_t *)(dgd_ijk + l)));
|
||||
// dgd_ijkl = [x y x y x y x y] [x y x y x y x y] where each is a u16
|
||||
|
||||
acc_stat_highbd_avx2(H_ + 0 * 8, dgd_ij + 0 * dgd_stride, shuffle,
|
||||
&dgd_ijkl);
|
||||
acc_stat_highbd_avx2(H_ + 1 * 8, dgd_ij + 1 * dgd_stride, shuffle,
|
||||
&dgd_ijkl);
|
||||
acc_stat_highbd_avx2(H_ + 2 * 8, dgd_ij + 2 * dgd_stride, shuffle,
|
||||
&dgd_ijkl);
|
||||
acc_stat_highbd_avx2(H_ + 3 * 8, dgd_ij + 3 * dgd_stride, shuffle,
|
||||
&dgd_ijkl);
|
||||
acc_stat_highbd_avx2(H_ + 4 * 8, dgd_ij + 4 * dgd_stride, shuffle,
|
||||
&dgd_ijkl);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static INLINE void compute_stats_highbd_win5_opt_avx2(
|
||||
const uint8_t *dgd8, const uint8_t *src8, int h_start, int h_end,
|
||||
int v_start, int v_end, int dgd_stride, int src_stride, int64_t *M,
|
||||
int64_t *H, aom_bit_depth_t bit_depth) {
|
||||
int i, j, k, l, m, n;
|
||||
const int wiener_win = WIENER_WIN_CHROMA;
|
||||
const int pixel_count = (h_end - h_start) * (v_end - v_start);
|
||||
const int wiener_win2 = wiener_win * wiener_win;
|
||||
const int wiener_halfwin = (wiener_win >> 1);
|
||||
const uint16_t *src = CONVERT_TO_SHORTPTR(src8);
|
||||
const uint16_t *dgd = CONVERT_TO_SHORTPTR(dgd8);
|
||||
const uint16_t avg =
|
||||
find_average_highbd(dgd, h_start, h_end, v_start, v_end, dgd_stride);
|
||||
|
||||
int64_t M_int64[WIENER_WIN_CHROMA][WIENER_WIN_CHROMA] = { { 0 } };
|
||||
int64_t H_int64[WIENER_WIN2_CHROMA][WIENER_WIN_CHROMA * 8] = { { 0 } };
|
||||
int32_t sumY[WIENER_WIN_CHROMA][WIENER_WIN_CHROMA] = { { 0 } };
|
||||
int32_t sumX = 0;
|
||||
const uint16_t *dgd_win = dgd - wiener_halfwin * dgd_stride - wiener_halfwin;
|
||||
|
||||
const __m256i shuffle = yy_loadu_256(g_shuffle_stats_highbd_data);
|
||||
for (j = v_start; j < v_end; j += 64) {
|
||||
const int vert_end = AOMMIN(64, v_end - j) + j;
|
||||
for (i = j; i < vert_end; i++) {
|
||||
acc_stat_highbd_win5_one_line_avx2(
|
||||
dgd_win + i * dgd_stride, src + i * src_stride, h_start, h_end,
|
||||
dgd_stride, &shuffle, &sumX, sumY, M_int64, H_int64);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t bit_depth_divider = 1;
|
||||
if (bit_depth == AOM_BITS_12)
|
||||
bit_depth_divider = 16;
|
||||
else if (bit_depth == AOM_BITS_10)
|
||||
bit_depth_divider = 4;
|
||||
|
||||
const int64_t avg_square_sum = (int64_t)avg * (int64_t)avg * pixel_count;
|
||||
for (k = 0; k < wiener_win; k++) {
|
||||
for (l = 0; l < wiener_win; l++) {
|
||||
const int32_t idx0 = l * wiener_win + k;
|
||||
M[idx0] = (M_int64[k][l] +
|
||||
(avg_square_sum - (int64_t)avg * (sumX + sumY[k][l]))) /
|
||||
bit_depth_divider;
|
||||
int64_t *H_ = H + idx0 * wiener_win2;
|
||||
int64_t *H_int_ = &H_int64[idx0][0];
|
||||
for (m = 0; m < wiener_win; m++) {
|
||||
for (n = 0; n < wiener_win; n++) {
|
||||
H_[m * wiener_win + n] =
|
||||
(H_int_[n * 8 + m] +
|
||||
(avg_square_sum - (int64_t)avg * (sumY[k][l] + sumY[n][m]))) /
|
||||
bit_depth_divider;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void av1_compute_stats_highbd_avx2(int wiener_win, const uint8_t *dgd8,
|
||||
const uint8_t *src8, int h_start, int h_end,
|
||||
int v_start, int v_end, int dgd_stride,
|
||||
int src_stride, int64_t *M, int64_t *H,
|
||||
aom_bit_depth_t bit_depth) {
|
||||
if (wiener_win == WIENER_WIN) {
|
||||
compute_stats_highbd_win7_opt_avx2(dgd8, src8, h_start, h_end, v_start,
|
||||
v_end, dgd_stride, src_stride, M, H,
|
||||
bit_depth);
|
||||
} else if (wiener_win == WIENER_WIN_CHROMA) {
|
||||
compute_stats_highbd_win5_opt_avx2(dgd8, src8, h_start, h_end, v_start,
|
||||
v_end, dgd_stride, src_stride, M, H,
|
||||
bit_depth);
|
||||
} else {
|
||||
av1_compute_stats_highbd_c(wiener_win, dgd8, src8, h_start, h_end, v_start,
|
||||
v_end, dgd_stride, src_stride, M, H, bit_depth);
|
||||
}
|
||||
}
|
||||
|
||||
static INLINE void acc_stat_win5_one_line_avx2(
|
||||
const uint8_t *dgd, const uint8_t *src, int h_start, int h_end,
|
||||
int dgd_stride, const __m128i *shuffle, int32_t *sumX,
|
||||
|
|
@ -156,14 +413,13 @@ static INLINE void acc_stat_win5_one_line_avx2(
|
|||
|
||||
static INLINE void compute_stats_win5_opt_avx2(
|
||||
const uint8_t *dgd, const uint8_t *src, int h_start, int h_end, int v_start,
|
||||
int v_end, int dgd_stride, int src_stride, double *M, double *H) {
|
||||
int v_end, int dgd_stride, int src_stride, int64_t *M, int64_t *H) {
|
||||
int i, j, k, l, m, n;
|
||||
const int wiener_win = WIENER_WIN_CHROMA;
|
||||
const int pixel_count = (h_end - h_start) * (v_end - v_start);
|
||||
const int wiener_win2 = wiener_win * wiener_win;
|
||||
const int wiener_halfwin = (wiener_win >> 1);
|
||||
const double avg =
|
||||
find_average(dgd, h_start, h_end, v_start, v_end, dgd_stride);
|
||||
uint8_t avg = find_average(dgd, h_start, h_end, v_start, v_end, dgd_stride);
|
||||
|
||||
int32_t M_int32[WIENER_WIN_CHROMA][WIENER_WIN_CHROMA] = { { 0 } };
|
||||
int64_t M_int64[WIENER_WIN_CHROMA][WIENER_WIN_CHROMA] = { { 0 } };
|
||||
|
|
@ -195,17 +451,18 @@ static INLINE void compute_stats_win5_opt_avx2(
|
|||
}
|
||||
}
|
||||
|
||||
const double avg_square_sum = avg * avg * pixel_count;
|
||||
const int64_t avg_square_sum = (int64_t)avg * (int64_t)avg * pixel_count;
|
||||
for (k = 0; k < wiener_win; k++) {
|
||||
for (l = 0; l < wiener_win; l++) {
|
||||
const int32_t idx0 = l * wiener_win + k;
|
||||
M[idx0] = M_int64[k][l] + avg_square_sum - avg * (sumX + sumY[k][l]);
|
||||
double *H_ = H + idx0 * wiener_win2;
|
||||
M[idx0] =
|
||||
M_int64[k][l] + (avg_square_sum - (int64_t)avg * (sumX + sumY[k][l]));
|
||||
int64_t *H_ = H + idx0 * wiener_win2;
|
||||
int64_t *H_int_ = &H_int64[idx0][0];
|
||||
for (m = 0; m < wiener_win; m++) {
|
||||
for (n = 0; n < wiener_win; n++) {
|
||||
H_[m * wiener_win + n] = H_int_[n * 8 + m] + avg_square_sum -
|
||||
avg * (sumY[k][l] + sumY[n][m]);
|
||||
(int64_t)avg * (sumY[k][l] + sumY[n][m]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -215,7 +472,7 @@ static INLINE void compute_stats_win5_opt_avx2(
|
|||
void av1_compute_stats_avx2(int wiener_win, const uint8_t *dgd,
|
||||
const uint8_t *src, int h_start, int h_end,
|
||||
int v_start, int v_end, int dgd_stride,
|
||||
int src_stride, double *M, double *H) {
|
||||
int src_stride, int64_t *M, int64_t *H) {
|
||||
if (wiener_win == WIENER_WIN) {
|
||||
compute_stats_win7_opt_avx2(dgd, src, h_start, h_end, v_start, v_end,
|
||||
dgd_stride, src_stride, M, H);
|
||||
|
|
@ -279,7 +536,7 @@ int64_t av1_lowbd_pixel_proj_error_avx2(
|
|||
const int32_t u = (int32_t)(dat[k] << SGRPROJ_RST_BITS);
|
||||
int32_t v = xq[0] * (flt0[k] - u) + xq[1] * (flt1[k] - u);
|
||||
const int32_t e = ROUND_POWER_OF_TWO(v, shift) + dat[k] - src[k];
|
||||
err += e * e;
|
||||
err += ((int64_t)e * e);
|
||||
}
|
||||
dat += dat_stride;
|
||||
src += src_stride;
|
||||
|
|
@ -292,22 +549,25 @@ int64_t av1_lowbd_pixel_proj_error_avx2(
|
|||
sum64 = _mm256_add_epi64(sum64, sum64_0);
|
||||
sum64 = _mm256_add_epi64(sum64, sum64_1);
|
||||
}
|
||||
} else if (params->r[0] > 0) {
|
||||
__m256i xq_coeff =
|
||||
pair_set_epi16(xq[0], (-xq[0] * (1 << SGRPROJ_RST_BITS)));
|
||||
} else if (params->r[0] > 0 || params->r[1] > 0) {
|
||||
const int xq_active = (params->r[0] > 0) ? xq[0] : xq[1];
|
||||
const __m256i xq_coeff =
|
||||
pair_set_epi16(xq_active, (-xq_active * (1 << SGRPROJ_RST_BITS)));
|
||||
const int32_t *flt = (params->r[0] > 0) ? flt0 : flt1;
|
||||
const int flt_stride = (params->r[0] > 0) ? flt0_stride : flt1_stride;
|
||||
for (i = 0; i < height; ++i) {
|
||||
__m256i sum32 = _mm256_setzero_si256();
|
||||
for (j = 0; j <= width - 16; j += 16) {
|
||||
const __m256i d0 = _mm256_cvtepu8_epi16(xx_loadu_128(dat + j));
|
||||
const __m256i s0 = _mm256_cvtepu8_epi16(xx_loadu_128(src + j));
|
||||
const __m256i flt0_16b = _mm256_permute4x64_epi64(
|
||||
_mm256_packs_epi32(yy_loadu_256(flt0 + j),
|
||||
yy_loadu_256(flt0 + j + 8)),
|
||||
const __m256i flt_16b = _mm256_permute4x64_epi64(
|
||||
_mm256_packs_epi32(yy_loadu_256(flt + j),
|
||||
yy_loadu_256(flt + j + 8)),
|
||||
0xd8);
|
||||
const __m256i v0 =
|
||||
_mm256_madd_epi16(xq_coeff, _mm256_unpacklo_epi16(flt0_16b, d0));
|
||||
_mm256_madd_epi16(xq_coeff, _mm256_unpacklo_epi16(flt_16b, d0));
|
||||
const __m256i v1 =
|
||||
_mm256_madd_epi16(xq_coeff, _mm256_unpackhi_epi16(flt0_16b, d0));
|
||||
_mm256_madd_epi16(xq_coeff, _mm256_unpackhi_epi16(flt_16b, d0));
|
||||
const __m256i vr0 =
|
||||
_mm256_srai_epi32(_mm256_add_epi32(v0, rounding), shift);
|
||||
const __m256i vr1 =
|
||||
|
|
@ -319,53 +579,13 @@ int64_t av1_lowbd_pixel_proj_error_avx2(
|
|||
}
|
||||
for (k = j; k < width; ++k) {
|
||||
const int32_t u = (int32_t)(dat[k] << SGRPROJ_RST_BITS);
|
||||
int32_t v = xq[0] * (flt0[k] - u);
|
||||
int32_t v = xq_active * (flt[k] - u);
|
||||
const int32_t e = ROUND_POWER_OF_TWO(v, shift) + dat[k] - src[k];
|
||||
err += e * e;
|
||||
err += ((int64_t)e * e);
|
||||
}
|
||||
dat += dat_stride;
|
||||
src += src_stride;
|
||||
flt0 += flt0_stride;
|
||||
const __m256i sum64_0 =
|
||||
_mm256_cvtepi32_epi64(_mm256_castsi256_si128(sum32));
|
||||
const __m256i sum64_1 =
|
||||
_mm256_cvtepi32_epi64(_mm256_extracti128_si256(sum32, 1));
|
||||
sum64 = _mm256_add_epi64(sum64, sum64_0);
|
||||
sum64 = _mm256_add_epi64(sum64, sum64_1);
|
||||
}
|
||||
} else if (params->r[1] > 0) {
|
||||
__m256i xq_coeff = pair_set_epi16(xq[1], -(xq[1] << SGRPROJ_RST_BITS));
|
||||
for (i = 0; i < height; ++i) {
|
||||
__m256i sum32 = _mm256_setzero_si256();
|
||||
for (j = 0; j <= width - 16; j += 16) {
|
||||
const __m256i d0 = _mm256_cvtepu8_epi16(xx_loadu_128(dat + j));
|
||||
const __m256i s0 = _mm256_cvtepu8_epi16(xx_loadu_128(src + j));
|
||||
const __m256i flt1_16b = _mm256_permute4x64_epi64(
|
||||
_mm256_packs_epi32(yy_loadu_256(flt1 + j),
|
||||
yy_loadu_256(flt1 + j + 8)),
|
||||
0xd8);
|
||||
const __m256i v0 =
|
||||
_mm256_madd_epi16(xq_coeff, _mm256_unpacklo_epi16(flt1_16b, d0));
|
||||
const __m256i v1 =
|
||||
_mm256_madd_epi16(xq_coeff, _mm256_unpackhi_epi16(flt1_16b, d0));
|
||||
const __m256i vr0 =
|
||||
_mm256_srai_epi32(_mm256_add_epi32(v0, rounding), shift);
|
||||
const __m256i vr1 =
|
||||
_mm256_srai_epi32(_mm256_add_epi32(v1, rounding), shift);
|
||||
const __m256i e0 = _mm256_sub_epi16(
|
||||
_mm256_add_epi16(_mm256_packs_epi32(vr0, vr1), d0), s0);
|
||||
const __m256i err0 = _mm256_madd_epi16(e0, e0);
|
||||
sum32 = _mm256_add_epi32(sum32, err0);
|
||||
}
|
||||
for (k = j; k < width; ++k) {
|
||||
const int32_t u = (int32_t)(dat[k] << SGRPROJ_RST_BITS);
|
||||
int32_t v = xq[1] * (flt1[k] - u);
|
||||
const int32_t e = ROUND_POWER_OF_TWO(v, shift) + dat[k] - src[k];
|
||||
err += e * e;
|
||||
}
|
||||
dat += dat_stride;
|
||||
src += src_stride;
|
||||
flt1 += flt1_stride;
|
||||
flt += flt_stride;
|
||||
const __m256i sum64_0 =
|
||||
_mm256_cvtepi32_epi64(_mm256_castsi256_si128(sum32));
|
||||
const __m256i sum64_1 =
|
||||
|
|
@ -385,7 +605,7 @@ int64_t av1_lowbd_pixel_proj_error_avx2(
|
|||
}
|
||||
for (k = j; k < width; ++k) {
|
||||
const int32_t e = (int32_t)(dat[k]) - src[k];
|
||||
err += e * e;
|
||||
err += ((int64_t)e * e);
|
||||
}
|
||||
dat += dat_stride;
|
||||
src += src_stride;
|
||||
|
|
@ -401,3 +621,223 @@ int64_t av1_lowbd_pixel_proj_error_avx2(
|
|||
err += sum[0] + sum[1] + sum[2] + sum[3];
|
||||
return err;
|
||||
}
|
||||
|
||||
int64_t av1_highbd_pixel_proj_error_avx2(
|
||||
const uint8_t *src8, int width, int height, int src_stride,
|
||||
const uint8_t *dat8, int dat_stride, int32_t *flt0, int flt0_stride,
|
||||
int32_t *flt1, int flt1_stride, int xq[2], const sgr_params_type *params) {
|
||||
int i, j, k;
|
||||
const int32_t shift = SGRPROJ_RST_BITS + SGRPROJ_PRJ_BITS;
|
||||
const __m256i rounding = _mm256_set1_epi32(1 << (shift - 1));
|
||||
__m256i sum64 = _mm256_setzero_si256();
|
||||
const uint16_t *src = CONVERT_TO_SHORTPTR(src8);
|
||||
const uint16_t *dat = CONVERT_TO_SHORTPTR(dat8);
|
||||
int64_t err = 0;
|
||||
if (params->r[0] > 0 && params->r[1] > 0) { // Both filters are enabled
|
||||
const __m256i xq0 = _mm256_set1_epi32(xq[0]);
|
||||
const __m256i xq1 = _mm256_set1_epi32(xq[1]);
|
||||
for (i = 0; i < height; ++i) {
|
||||
__m256i sum32 = _mm256_setzero_si256();
|
||||
for (j = 0; j <= width - 16; j += 16) { // Process 16 pixels at a time
|
||||
// Load 16 pixels each from source image and corrupted image
|
||||
const __m256i s0 = yy_loadu_256(src + j);
|
||||
const __m256i d0 = yy_loadu_256(dat + j);
|
||||
// s0 = [15 14 13 12 11 10 9 8] [7 6 5 4 3 2 1 0] as u16 (indices)
|
||||
|
||||
// Shift-up each pixel to match filtered image scaling
|
||||
const __m256i u0 = _mm256_slli_epi16(d0, SGRPROJ_RST_BITS);
|
||||
|
||||
// Split u0 into two halves and pad each from u16 to i32
|
||||
const __m256i u0l = _mm256_cvtepu16_epi32(_mm256_castsi256_si128(u0));
|
||||
const __m256i u0h =
|
||||
_mm256_cvtepu16_epi32(_mm256_extracti128_si256(u0, 1));
|
||||
// u0h, u0l = [15 14 13 12] [11 10 9 8], [7 6 5 4] [3 2 1 0] as u32
|
||||
|
||||
// Load 16 pixels from each filtered image
|
||||
const __m256i flt0l = yy_loadu_256(flt0 + j);
|
||||
const __m256i flt0h = yy_loadu_256(flt0 + j + 8);
|
||||
const __m256i flt1l = yy_loadu_256(flt1 + j);
|
||||
const __m256i flt1h = yy_loadu_256(flt1 + j + 8);
|
||||
// flt?l, flt?h = [15 14 13 12] [11 10 9 8], [7 6 5 4] [3 2 1 0] as u32
|
||||
|
||||
// Subtract shifted corrupt image from each filtered image
|
||||
const __m256i flt0l_subu = _mm256_sub_epi32(flt0l, u0l);
|
||||
const __m256i flt0h_subu = _mm256_sub_epi32(flt0h, u0h);
|
||||
const __m256i flt1l_subu = _mm256_sub_epi32(flt1l, u0l);
|
||||
const __m256i flt1h_subu = _mm256_sub_epi32(flt1h, u0h);
|
||||
|
||||
// Multiply basis vectors by appropriate coefficients
|
||||
const __m256i v0l = _mm256_mullo_epi32(flt0l_subu, xq0);
|
||||
const __m256i v0h = _mm256_mullo_epi32(flt0h_subu, xq0);
|
||||
const __m256i v1l = _mm256_mullo_epi32(flt1l_subu, xq1);
|
||||
const __m256i v1h = _mm256_mullo_epi32(flt1h_subu, xq1);
|
||||
|
||||
// Add together the contributions from the two basis vectors
|
||||
const __m256i vl = _mm256_add_epi32(v0l, v1l);
|
||||
const __m256i vh = _mm256_add_epi32(v0h, v1h);
|
||||
|
||||
// Right-shift v with appropriate rounding
|
||||
const __m256i vrl =
|
||||
_mm256_srai_epi32(_mm256_add_epi32(vl, rounding), shift);
|
||||
const __m256i vrh =
|
||||
_mm256_srai_epi32(_mm256_add_epi32(vh, rounding), shift);
|
||||
// vrh, vrl = [15 14 13 12] [11 10 9 8], [7 6 5 4] [3 2 1 0]
|
||||
|
||||
// Saturate each i32 to an i16 then combine both halves
|
||||
// The permute (control=[3 1 2 0]) fixes weird ordering from AVX lanes
|
||||
const __m256i vr =
|
||||
_mm256_permute4x64_epi64(_mm256_packs_epi32(vrl, vrh), 0xd8);
|
||||
// intermediate = [15 14 13 12 7 6 5 4] [11 10 9 8 3 2 1 0]
|
||||
// vr = [15 14 13 12 11 10 9 8] [7 6 5 4 3 2 1 0]
|
||||
|
||||
// Add twin-subspace-sgr-filter to corrupt image then subtract source
|
||||
const __m256i e0 = _mm256_sub_epi16(_mm256_add_epi16(vr, d0), s0);
|
||||
|
||||
// Calculate squared error and add adjacent values
|
||||
const __m256i err0 = _mm256_madd_epi16(e0, e0);
|
||||
|
||||
sum32 = _mm256_add_epi32(sum32, err0);
|
||||
}
|
||||
|
||||
const __m256i sum32l =
|
||||
_mm256_cvtepu32_epi64(_mm256_castsi256_si128(sum32));
|
||||
sum64 = _mm256_add_epi64(sum64, sum32l);
|
||||
const __m256i sum32h =
|
||||
_mm256_cvtepu32_epi64(_mm256_extracti128_si256(sum32, 1));
|
||||
sum64 = _mm256_add_epi64(sum64, sum32h);
|
||||
|
||||
// Process remaining pixels in this row (modulo 16)
|
||||
for (k = j; k < width; ++k) {
|
||||
const int32_t u = (int32_t)(dat[k] << SGRPROJ_RST_BITS);
|
||||
int32_t v = xq[0] * (flt0[k] - u) + xq[1] * (flt1[k] - u);
|
||||
const int32_t e = ROUND_POWER_OF_TWO(v, shift) + dat[k] - src[k];
|
||||
err += ((int64_t)e * e);
|
||||
}
|
||||
dat += dat_stride;
|
||||
src += src_stride;
|
||||
flt0 += flt0_stride;
|
||||
flt1 += flt1_stride;
|
||||
}
|
||||
} else if (params->r[0] > 0 || params->r[1] > 0) { // Only one filter enabled
|
||||
const int32_t xq_on = (params->r[0] > 0) ? xq[0] : xq[1];
|
||||
const __m256i xq_active = _mm256_set1_epi32(xq_on);
|
||||
const __m256i xq_inactive =
|
||||
_mm256_set1_epi32(-xq_on * (1 << SGRPROJ_RST_BITS));
|
||||
const int32_t *flt = (params->r[0] > 0) ? flt0 : flt1;
|
||||
const int flt_stride = (params->r[0] > 0) ? flt0_stride : flt1_stride;
|
||||
for (i = 0; i < height; ++i) {
|
||||
__m256i sum32 = _mm256_setzero_si256();
|
||||
for (j = 0; j <= width - 16; j += 16) {
|
||||
// Load 16 pixels from source image
|
||||
const __m256i s0 = yy_loadu_256(src + j);
|
||||
// s0 = [15 14 13 12 11 10 9 8] [7 6 5 4 3 2 1 0] as u16
|
||||
|
||||
// Load 16 pixels from corrupted image and pad each u16 to i32
|
||||
const __m256i d0 = yy_loadu_256(dat + j);
|
||||
const __m256i d0h =
|
||||
_mm256_cvtepu16_epi32(_mm256_extracti128_si256(d0, 1));
|
||||
const __m256i d0l = _mm256_cvtepu16_epi32(_mm256_castsi256_si128(d0));
|
||||
// d0 = [15 14 13 12 11 10 9 8] [7 6 5 4 3 2 1 0] as u16
|
||||
// d0h, d0l = [15 14 13 12] [11 10 9 8], [7 6 5 4] [3 2 1 0] as i32
|
||||
|
||||
// Load 16 pixels from the filtered image
|
||||
const __m256i flth = yy_loadu_256(flt + j + 8);
|
||||
const __m256i fltl = yy_loadu_256(flt + j);
|
||||
// flth, fltl = [15 14 13 12] [11 10 9 8], [7 6 5 4] [3 2 1 0] as i32
|
||||
|
||||
const __m256i flth_xq = _mm256_mullo_epi32(flth, xq_active);
|
||||
const __m256i fltl_xq = _mm256_mullo_epi32(fltl, xq_active);
|
||||
const __m256i d0h_xq = _mm256_mullo_epi32(d0h, xq_inactive);
|
||||
const __m256i d0l_xq = _mm256_mullo_epi32(d0l, xq_inactive);
|
||||
|
||||
const __m256i vh = _mm256_add_epi32(flth_xq, d0h_xq);
|
||||
const __m256i vl = _mm256_add_epi32(fltl_xq, d0l_xq);
|
||||
|
||||
// Shift this down with appropriate rounding
|
||||
const __m256i vrh =
|
||||
_mm256_srai_epi32(_mm256_add_epi32(vh, rounding), shift);
|
||||
const __m256i vrl =
|
||||
_mm256_srai_epi32(_mm256_add_epi32(vl, rounding), shift);
|
||||
// vrh, vrl = [15 14 13 12] [11 10 9 8], [7 6 5 4] [3 2 1 0] as i32
|
||||
|
||||
// Saturate each i32 to an i16 then combine both halves
|
||||
// The permute (control=[3 1 2 0]) fixes weird ordering from AVX lanes
|
||||
const __m256i vr =
|
||||
_mm256_permute4x64_epi64(_mm256_packs_epi32(vrl, vrh), 0xd8);
|
||||
// intermediate = [15 14 13 12 7 6 5 4] [11 10 9 8 3 2 1 0] as u16
|
||||
// vr = [15 14 13 12 11 10 9 8] [7 6 5 4 3 2 1 0] as u16
|
||||
|
||||
// Subtract twin-subspace-sgr filtered from source image to get error
|
||||
const __m256i e0 = _mm256_sub_epi16(_mm256_add_epi16(vr, d0), s0);
|
||||
|
||||
// Calculate squared error and add adjacent values
|
||||
const __m256i err0 = _mm256_madd_epi16(e0, e0);
|
||||
|
||||
sum32 = _mm256_add_epi32(sum32, err0);
|
||||
}
|
||||
|
||||
const __m256i sum32l =
|
||||
_mm256_cvtepu32_epi64(_mm256_castsi256_si128(sum32));
|
||||
sum64 = _mm256_add_epi64(sum64, sum32l);
|
||||
const __m256i sum32h =
|
||||
_mm256_cvtepu32_epi64(_mm256_extracti128_si256(sum32, 1));
|
||||
sum64 = _mm256_add_epi64(sum64, sum32h);
|
||||
|
||||
// Process remaining pixels in this row (modulo 16)
|
||||
for (k = j; k < width; ++k) {
|
||||
const int32_t u = (int32_t)(dat[k] << SGRPROJ_RST_BITS);
|
||||
int32_t v = xq_on * (flt[k] - u);
|
||||
const int32_t e = ROUND_POWER_OF_TWO(v, shift) + dat[k] - src[k];
|
||||
err += ((int64_t)e * e);
|
||||
}
|
||||
dat += dat_stride;
|
||||
src += src_stride;
|
||||
flt += flt_stride;
|
||||
}
|
||||
} else { // Neither filter is enabled
|
||||
for (i = 0; i < height; ++i) {
|
||||
__m256i sum32 = _mm256_setzero_si256();
|
||||
for (j = 0; j <= width - 32; j += 32) {
|
||||
// Load 2x16 u16 from source image
|
||||
const __m256i s0l = yy_loadu_256(src + j);
|
||||
const __m256i s0h = yy_loadu_256(src + j + 16);
|
||||
|
||||
// Load 2x16 u16 from corrupted image
|
||||
const __m256i d0l = yy_loadu_256(dat + j);
|
||||
const __m256i d0h = yy_loadu_256(dat + j + 16);
|
||||
|
||||
// Subtract corrupted image from source image
|
||||
const __m256i diffl = _mm256_sub_epi16(d0l, s0l);
|
||||
const __m256i diffh = _mm256_sub_epi16(d0h, s0h);
|
||||
|
||||
// Square error and add adjacent values
|
||||
const __m256i err0l = _mm256_madd_epi16(diffl, diffl);
|
||||
const __m256i err0h = _mm256_madd_epi16(diffh, diffh);
|
||||
|
||||
sum32 = _mm256_add_epi32(sum32, err0l);
|
||||
sum32 = _mm256_add_epi32(sum32, err0h);
|
||||
}
|
||||
|
||||
const __m256i sum32l =
|
||||
_mm256_cvtepu32_epi64(_mm256_castsi256_si128(sum32));
|
||||
sum64 = _mm256_add_epi64(sum64, sum32l);
|
||||
const __m256i sum32h =
|
||||
_mm256_cvtepu32_epi64(_mm256_extracti128_si256(sum32, 1));
|
||||
sum64 = _mm256_add_epi64(sum64, sum32h);
|
||||
|
||||
// Process remaining pixels (modulu 16)
|
||||
for (k = j; k < width; ++k) {
|
||||
const int32_t e = (int32_t)(dat[k]) - src[k];
|
||||
err += ((int64_t)e * e);
|
||||
}
|
||||
dat += dat_stride;
|
||||
src += src_stride;
|
||||
}
|
||||
}
|
||||
|
||||
// Sum 4 values from sum64l and sum64h into err
|
||||
int64_t sum[4];
|
||||
yy_storeu_256(sum, sum64);
|
||||
err += sum[0] + sum[1] + sum[2] + sum[3];
|
||||
return err;
|
||||
}
|
||||
|
|
|
|||
562
third_party/aom/av1/encoder/x86/pickrst_sse4.c
vendored
562
third_party/aom/av1/encoder/x86/pickrst_sse4.c
vendored
|
|
@ -68,13 +68,13 @@ static INLINE void acc_stat_win7_one_line_sse4_1(
|
|||
|
||||
static INLINE void compute_stats_win7_opt_sse4_1(
|
||||
const uint8_t *dgd, const uint8_t *src, int h_start, int h_end, int v_start,
|
||||
int v_end, int dgd_stride, int src_stride, double *M, double *H) {
|
||||
int v_end, int dgd_stride, int src_stride, int64_t *M, int64_t *H) {
|
||||
int i, j, k, l, m, n;
|
||||
const int wiener_win = WIENER_WIN;
|
||||
const int pixel_count = (h_end - h_start) * (v_end - v_start);
|
||||
const int wiener_win2 = wiener_win * wiener_win;
|
||||
const int wiener_halfwin = (wiener_win >> 1);
|
||||
const double avg =
|
||||
const uint8_t avg =
|
||||
find_average(dgd, h_start, h_end, v_start, v_end, dgd_stride);
|
||||
|
||||
int32_t M_int32[WIENER_WIN][WIENER_WIN] = { { 0 } };
|
||||
|
|
@ -107,23 +107,286 @@ static INLINE void compute_stats_win7_opt_sse4_1(
|
|||
}
|
||||
}
|
||||
|
||||
const double avg_square_sum = avg * avg * pixel_count;
|
||||
const int64_t avg_square_sum = (int64_t)avg * (int64_t)avg * pixel_count;
|
||||
for (k = 0; k < wiener_win; k++) {
|
||||
for (l = 0; l < wiener_win; l++) {
|
||||
const int32_t idx0 = l * wiener_win + k;
|
||||
M[idx0] = M_int64[k][l] + avg_square_sum - avg * (sumX + sumY[k][l]);
|
||||
double *H_ = H + idx0 * wiener_win2;
|
||||
M[idx0] =
|
||||
M_int64[k][l] + (avg_square_sum - (int64_t)avg * (sumX + sumY[k][l]));
|
||||
int64_t *H_ = H + idx0 * wiener_win2;
|
||||
int64_t *H_int_ = &H_int64[idx0][0];
|
||||
for (m = 0; m < wiener_win; m++) {
|
||||
for (n = 0; n < wiener_win; n++) {
|
||||
H_[m * wiener_win + n] = H_int_[n * 8 + m] + avg_square_sum -
|
||||
avg * (sumY[k][l] + sumY[n][m]);
|
||||
(int64_t)avg * (sumY[k][l] + sumY[n][m]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static INLINE void acc_stat_highbd_sse41(int64_t *dst, const uint16_t *dgd,
|
||||
const __m128i *shuffle,
|
||||
const __m128i *dgd_ijkl) {
|
||||
// Load 256 bits from dgd in two chunks
|
||||
const __m128i s0l = xx_loadu_128(dgd);
|
||||
const __m128i s0h = xx_loadu_128(dgd + 4);
|
||||
// s0l = [7 6 5 4 3 2 1 0] as u16 values (dgd indices)
|
||||
// s0h = [11 10 9 8 7 6 5 4] as u16 values (dgd indices)
|
||||
// (Slightly strange order so we can apply the same shuffle to both halves)
|
||||
|
||||
// Shuffle the u16 values in each half (actually using 8-bit shuffle mask)
|
||||
const __m128i s1l = _mm_shuffle_epi8(s0l, *shuffle);
|
||||
const __m128i s1h = _mm_shuffle_epi8(s0h, *shuffle);
|
||||
// s1l = [4 3 3 2 2 1 1 0] as u16 values (dgd indices)
|
||||
// s1h = [8 7 7 6 6 5 5 4] as u16 values (dgd indices)
|
||||
|
||||
// Multiply s1 by dgd_ijkl resulting in 8x u32 values
|
||||
// Horizontally add pairs of u32 resulting in 4x u32
|
||||
const __m128i dl = _mm_madd_epi16(*dgd_ijkl, s1l);
|
||||
const __m128i dh = _mm_madd_epi16(*dgd_ijkl, s1h);
|
||||
// dl = [d c b a] as u32 values
|
||||
// dh = [h g f e] as u32 values
|
||||
|
||||
// Add these 8x u32 results on to dst in four parts
|
||||
const __m128i dll = _mm_cvtepu32_epi64(dl);
|
||||
const __m128i dlh = _mm_cvtepu32_epi64(_mm_srli_si128(dl, 8));
|
||||
const __m128i dhl = _mm_cvtepu32_epi64(dh);
|
||||
const __m128i dhh = _mm_cvtepu32_epi64(_mm_srli_si128(dh, 8));
|
||||
// dll = [b a] as u64 values, etc.
|
||||
|
||||
const __m128i rll = _mm_add_epi64(xx_loadu_128(dst), dll);
|
||||
xx_storeu_128(dst, rll);
|
||||
const __m128i rlh = _mm_add_epi64(xx_loadu_128(dst + 2), dlh);
|
||||
xx_storeu_128(dst + 2, rlh);
|
||||
const __m128i rhl = _mm_add_epi64(xx_loadu_128(dst + 4), dhl);
|
||||
xx_storeu_128(dst + 4, rhl);
|
||||
const __m128i rhh = _mm_add_epi64(xx_loadu_128(dst + 6), dhh);
|
||||
xx_storeu_128(dst + 6, rhh);
|
||||
}
|
||||
|
||||
static INLINE void acc_stat_highbd_win7_one_line_sse4_1(
|
||||
const uint16_t *dgd, const uint16_t *src, int h_start, int h_end,
|
||||
int dgd_stride, const __m128i *shuffle, int32_t *sumX,
|
||||
int32_t sumY[WIENER_WIN][WIENER_WIN], int64_t M_int[WIENER_WIN][WIENER_WIN],
|
||||
int64_t H_int[WIENER_WIN2][WIENER_WIN * 8]) {
|
||||
int j, k, l;
|
||||
const int wiener_win = WIENER_WIN;
|
||||
for (j = h_start; j < h_end; j += 2) {
|
||||
const uint16_t X1 = src[j];
|
||||
const uint16_t X2 = src[j + 1];
|
||||
*sumX += X1 + X2;
|
||||
const uint16_t *dgd_ij = dgd + j;
|
||||
for (k = 0; k < wiener_win; k++) {
|
||||
const uint16_t *dgd_ijk = dgd_ij + k * dgd_stride;
|
||||
for (l = 0; l < wiener_win; l++) {
|
||||
int64_t *H_ = &H_int[(l * wiener_win + k)][0];
|
||||
const uint16_t D1 = dgd_ijk[l];
|
||||
const uint16_t D2 = dgd_ijk[l + 1];
|
||||
sumY[k][l] += D1 + D2;
|
||||
M_int[k][l] += D1 * X1 + D2 * X2;
|
||||
|
||||
// Load two u16 values from dgd as a single u32
|
||||
// Then broadcast to 4x u32 slots of a 128
|
||||
const __m128i dgd_ijkl = _mm_set1_epi32(*((uint32_t *)(dgd_ijk + l)));
|
||||
// dgd_ijkl = [y x y x y x y x] as u16
|
||||
|
||||
acc_stat_highbd_sse41(H_ + 0 * 8, dgd_ij + 0 * dgd_stride, shuffle,
|
||||
&dgd_ijkl);
|
||||
acc_stat_highbd_sse41(H_ + 1 * 8, dgd_ij + 1 * dgd_stride, shuffle,
|
||||
&dgd_ijkl);
|
||||
acc_stat_highbd_sse41(H_ + 2 * 8, dgd_ij + 2 * dgd_stride, shuffle,
|
||||
&dgd_ijkl);
|
||||
acc_stat_highbd_sse41(H_ + 3 * 8, dgd_ij + 3 * dgd_stride, shuffle,
|
||||
&dgd_ijkl);
|
||||
acc_stat_highbd_sse41(H_ + 4 * 8, dgd_ij + 4 * dgd_stride, shuffle,
|
||||
&dgd_ijkl);
|
||||
acc_stat_highbd_sse41(H_ + 5 * 8, dgd_ij + 5 * dgd_stride, shuffle,
|
||||
&dgd_ijkl);
|
||||
acc_stat_highbd_sse41(H_ + 6 * 8, dgd_ij + 6 * dgd_stride, shuffle,
|
||||
&dgd_ijkl);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static INLINE void compute_stats_highbd_win7_opt_sse4_1(
|
||||
const uint8_t *dgd8, const uint8_t *src8, int h_start, int h_end,
|
||||
int v_start, int v_end, int dgd_stride, int src_stride, int64_t *M,
|
||||
int64_t *H, aom_bit_depth_t bit_depth) {
|
||||
int i, j, k, l, m, n;
|
||||
const int wiener_win = WIENER_WIN;
|
||||
const int pixel_count = (h_end - h_start) * (v_end - v_start);
|
||||
const int wiener_win2 = wiener_win * wiener_win;
|
||||
const int wiener_halfwin = (wiener_win >> 1);
|
||||
const uint16_t *src = CONVERT_TO_SHORTPTR(src8);
|
||||
const uint16_t *dgd = CONVERT_TO_SHORTPTR(dgd8);
|
||||
const uint16_t avg =
|
||||
find_average_highbd(dgd, h_start, h_end, v_start, v_end, dgd_stride);
|
||||
|
||||
int64_t M_int[WIENER_WIN][WIENER_WIN] = { { 0 } };
|
||||
int64_t H_int[WIENER_WIN2][WIENER_WIN * 8] = { { 0 } };
|
||||
int32_t sumY[WIENER_WIN][WIENER_WIN] = { { 0 } };
|
||||
int32_t sumX = 0;
|
||||
const uint16_t *dgd_win = dgd - wiener_halfwin * dgd_stride - wiener_halfwin;
|
||||
|
||||
// Load just half of the 256-bit shuffle control used for the AVX2 version
|
||||
const __m128i shuffle = xx_loadu_128(g_shuffle_stats_highbd_data);
|
||||
for (j = v_start; j < v_end; j += 64) {
|
||||
const int vert_end = AOMMIN(64, v_end - j) + j;
|
||||
for (i = j; i < vert_end; i++) {
|
||||
acc_stat_highbd_win7_one_line_sse4_1(
|
||||
dgd_win + i * dgd_stride, src + i * src_stride, h_start, h_end,
|
||||
dgd_stride, &shuffle, &sumX, sumY, M_int, H_int);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t bit_depth_divider = 1;
|
||||
if (bit_depth == AOM_BITS_12)
|
||||
bit_depth_divider = 16;
|
||||
else if (bit_depth == AOM_BITS_10)
|
||||
bit_depth_divider = 4;
|
||||
|
||||
const int64_t avg_square_sum = (int64_t)avg * (int64_t)avg * pixel_count;
|
||||
for (k = 0; k < wiener_win; k++) {
|
||||
for (l = 0; l < wiener_win; l++) {
|
||||
const int32_t idx0 = l * wiener_win + k;
|
||||
M[idx0] = (M_int[k][l] +
|
||||
(avg_square_sum - (int64_t)avg * (sumX + sumY[k][l]))) /
|
||||
bit_depth_divider;
|
||||
int64_t *H_ = H + idx0 * wiener_win2;
|
||||
int64_t *H_int_ = &H_int[idx0][0];
|
||||
for (m = 0; m < wiener_win; m++) {
|
||||
for (n = 0; n < wiener_win; n++) {
|
||||
H_[m * wiener_win + n] =
|
||||
(H_int_[n * 8 + m] +
|
||||
(avg_square_sum - (int64_t)avg * (sumY[k][l] + sumY[n][m]))) /
|
||||
bit_depth_divider;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static INLINE void acc_stat_highbd_win5_one_line_sse4_1(
|
||||
const uint16_t *dgd, const uint16_t *src, int h_start, int h_end,
|
||||
int dgd_stride, const __m128i *shuffle, int32_t *sumX,
|
||||
int32_t sumY[WIENER_WIN_CHROMA][WIENER_WIN_CHROMA],
|
||||
int64_t M_int[WIENER_WIN_CHROMA][WIENER_WIN_CHROMA],
|
||||
int64_t H_int[WIENER_WIN2_CHROMA][WIENER_WIN_CHROMA * 8]) {
|
||||
int j, k, l;
|
||||
const int wiener_win = WIENER_WIN_CHROMA;
|
||||
for (j = h_start; j < h_end; j += 2) {
|
||||
const uint16_t X1 = src[j];
|
||||
const uint16_t X2 = src[j + 1];
|
||||
*sumX += X1 + X2;
|
||||
const uint16_t *dgd_ij = dgd + j;
|
||||
for (k = 0; k < wiener_win; k++) {
|
||||
const uint16_t *dgd_ijk = dgd_ij + k * dgd_stride;
|
||||
for (l = 0; l < wiener_win; l++) {
|
||||
int64_t *H_ = &H_int[(l * wiener_win + k)][0];
|
||||
const uint16_t D1 = dgd_ijk[l];
|
||||
const uint16_t D2 = dgd_ijk[l + 1];
|
||||
sumY[k][l] += D1 + D2;
|
||||
M_int[k][l] += D1 * X1 + D2 * X2;
|
||||
|
||||
// Load two u16 values from dgd as a single u32
|
||||
// then broadcast to 4x u32 slots of a 128
|
||||
const __m128i dgd_ijkl = _mm_set1_epi32(*((uint32_t *)(dgd_ijk + l)));
|
||||
// dgd_ijkl = [y x y x y x y x] as u16
|
||||
|
||||
acc_stat_highbd_sse41(H_ + 0 * 8, dgd_ij + 0 * dgd_stride, shuffle,
|
||||
&dgd_ijkl);
|
||||
acc_stat_highbd_sse41(H_ + 1 * 8, dgd_ij + 1 * dgd_stride, shuffle,
|
||||
&dgd_ijkl);
|
||||
acc_stat_highbd_sse41(H_ + 2 * 8, dgd_ij + 2 * dgd_stride, shuffle,
|
||||
&dgd_ijkl);
|
||||
acc_stat_highbd_sse41(H_ + 3 * 8, dgd_ij + 3 * dgd_stride, shuffle,
|
||||
&dgd_ijkl);
|
||||
acc_stat_highbd_sse41(H_ + 4 * 8, dgd_ij + 4 * dgd_stride, shuffle,
|
||||
&dgd_ijkl);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static INLINE void compute_stats_highbd_win5_opt_sse4_1(
|
||||
const uint8_t *dgd8, const uint8_t *src8, int h_start, int h_end,
|
||||
int v_start, int v_end, int dgd_stride, int src_stride, int64_t *M,
|
||||
int64_t *H, aom_bit_depth_t bit_depth) {
|
||||
int i, j, k, l, m, n;
|
||||
const int wiener_win = WIENER_WIN_CHROMA;
|
||||
const int pixel_count = (h_end - h_start) * (v_end - v_start);
|
||||
const int wiener_win2 = wiener_win * wiener_win;
|
||||
const int wiener_halfwin = (wiener_win >> 1);
|
||||
const uint16_t *src = CONVERT_TO_SHORTPTR(src8);
|
||||
const uint16_t *dgd = CONVERT_TO_SHORTPTR(dgd8);
|
||||
const uint16_t avg =
|
||||
find_average_highbd(dgd, h_start, h_end, v_start, v_end, dgd_stride);
|
||||
|
||||
int64_t M_int[WIENER_WIN_CHROMA][WIENER_WIN_CHROMA] = { { 0 } };
|
||||
int64_t H_int[WIENER_WIN2_CHROMA][WIENER_WIN_CHROMA * 8] = { { 0 } };
|
||||
int32_t sumY[WIENER_WIN_CHROMA][WIENER_WIN_CHROMA] = { { 0 } };
|
||||
int32_t sumX = 0;
|
||||
const uint16_t *dgd_win = dgd - wiener_halfwin * dgd_stride - wiener_halfwin;
|
||||
|
||||
// Load just half of the 256-bit shuffle control used for the AVX2 version
|
||||
const __m128i shuffle = xx_loadu_128(g_shuffle_stats_highbd_data);
|
||||
for (j = v_start; j < v_end; j += 64) {
|
||||
const int vert_end = AOMMIN(64, v_end - j) + j;
|
||||
for (i = j; i < vert_end; i++) {
|
||||
acc_stat_highbd_win5_one_line_sse4_1(
|
||||
dgd_win + i * dgd_stride, src + i * src_stride, h_start, h_end,
|
||||
dgd_stride, &shuffle, &sumX, sumY, M_int, H_int);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t bit_depth_divider = 1;
|
||||
if (bit_depth == AOM_BITS_12)
|
||||
bit_depth_divider = 16;
|
||||
else if (bit_depth == AOM_BITS_10)
|
||||
bit_depth_divider = 4;
|
||||
|
||||
const int64_t avg_square_sum = (int64_t)avg * (int64_t)avg * pixel_count;
|
||||
for (k = 0; k < wiener_win; k++) {
|
||||
for (l = 0; l < wiener_win; l++) {
|
||||
const int32_t idx0 = l * wiener_win + k;
|
||||
M[idx0] = (M_int[k][l] +
|
||||
(avg_square_sum - (int64_t)avg * (sumX + sumY[k][l]))) /
|
||||
bit_depth_divider;
|
||||
int64_t *H_ = H + idx0 * wiener_win2;
|
||||
int64_t *H_int_ = &H_int[idx0][0];
|
||||
for (m = 0; m < wiener_win; m++) {
|
||||
for (n = 0; n < wiener_win; n++) {
|
||||
H_[m * wiener_win + n] =
|
||||
(H_int_[n * 8 + m] +
|
||||
(avg_square_sum - (int64_t)avg * (sumY[k][l] + sumY[n][m]))) /
|
||||
bit_depth_divider;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void av1_compute_stats_highbd_sse4_1(int wiener_win, const uint8_t *dgd8,
|
||||
const uint8_t *src8, int h_start,
|
||||
int h_end, int v_start, int v_end,
|
||||
int dgd_stride, int src_stride, int64_t *M,
|
||||
int64_t *H, aom_bit_depth_t bit_depth) {
|
||||
if (wiener_win == WIENER_WIN) {
|
||||
compute_stats_highbd_win7_opt_sse4_1(dgd8, src8, h_start, h_end, v_start,
|
||||
v_end, dgd_stride, src_stride, M, H,
|
||||
bit_depth);
|
||||
} else if (wiener_win == WIENER_WIN_CHROMA) {
|
||||
compute_stats_highbd_win5_opt_sse4_1(dgd8, src8, h_start, h_end, v_start,
|
||||
v_end, dgd_stride, src_stride, M, H,
|
||||
bit_depth);
|
||||
} else {
|
||||
av1_compute_stats_highbd_c(wiener_win, dgd8, src8, h_start, h_end, v_start,
|
||||
v_end, dgd_stride, src_stride, M, H, bit_depth);
|
||||
}
|
||||
}
|
||||
|
||||
static INLINE void acc_stat_win5_one_line_sse4_1(
|
||||
const uint8_t *dgd, const uint8_t *src, int h_start, int h_end,
|
||||
int dgd_stride, const __m128i *shuffle, int32_t *sumX,
|
||||
|
|
@ -160,13 +423,13 @@ static INLINE void acc_stat_win5_one_line_sse4_1(
|
|||
|
||||
static INLINE void compute_stats_win5_opt_sse4_1(
|
||||
const uint8_t *dgd, const uint8_t *src, int h_start, int h_end, int v_start,
|
||||
int v_end, int dgd_stride, int src_stride, double *M, double *H) {
|
||||
int v_end, int dgd_stride, int src_stride, int64_t *M, int64_t *H) {
|
||||
int i, j, k, l, m, n;
|
||||
const int wiener_win = WIENER_WIN_CHROMA;
|
||||
const int pixel_count = (h_end - h_start) * (v_end - v_start);
|
||||
const int wiener_win2 = wiener_win * wiener_win;
|
||||
const int wiener_halfwin = (wiener_win >> 1);
|
||||
const double avg =
|
||||
const uint8_t avg =
|
||||
find_average(dgd, h_start, h_end, v_start, v_end, dgd_stride);
|
||||
|
||||
int32_t M_int32[WIENER_WIN_CHROMA][WIENER_WIN_CHROMA] = { { 0 } };
|
||||
|
|
@ -199,17 +462,18 @@ static INLINE void compute_stats_win5_opt_sse4_1(
|
|||
}
|
||||
}
|
||||
|
||||
const double avg_square_sum = avg * avg * pixel_count;
|
||||
const int64_t avg_square_sum = (int64_t)avg * (int64_t)avg * pixel_count;
|
||||
for (k = 0; k < wiener_win; k++) {
|
||||
for (l = 0; l < wiener_win; l++) {
|
||||
const int32_t idx0 = l * wiener_win + k;
|
||||
M[idx0] = M_int64[k][l] + avg_square_sum - avg * (sumX + sumY[k][l]);
|
||||
double *H_ = H + idx0 * wiener_win2;
|
||||
M[idx0] =
|
||||
M_int64[k][l] + (avg_square_sum - (int64_t)avg * (sumX + sumY[k][l]));
|
||||
int64_t *H_ = H + idx0 * wiener_win2;
|
||||
int64_t *H_int_ = &H_int64[idx0][0];
|
||||
for (m = 0; m < wiener_win; m++) {
|
||||
for (n = 0; n < wiener_win; n++) {
|
||||
H_[m * wiener_win + n] = H_int_[n * 8 + m] + avg_square_sum -
|
||||
avg * (sumY[k][l] + sumY[n][m]);
|
||||
(int64_t)avg * (sumY[k][l] + sumY[n][m]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -218,7 +482,7 @@ static INLINE void compute_stats_win5_opt_sse4_1(
|
|||
void av1_compute_stats_sse4_1(int wiener_win, const uint8_t *dgd,
|
||||
const uint8_t *src, int h_start, int h_end,
|
||||
int v_start, int v_end, int dgd_stride,
|
||||
int src_stride, double *M, double *H) {
|
||||
int src_stride, int64_t *M, int64_t *H) {
|
||||
if (wiener_win == WIENER_WIN) {
|
||||
compute_stats_win7_opt_sse4_1(dgd, src, h_start, h_end, v_start, v_end,
|
||||
dgd_stride, src_stride, M, H);
|
||||
|
|
@ -250,7 +514,7 @@ int64_t av1_lowbd_pixel_proj_error_sse4_1(
|
|||
__m128i xq_coeff = pair_set_epi16(xq[0], xq[1]);
|
||||
for (i = 0; i < height; ++i) {
|
||||
__m128i sum32 = _mm_setzero_si128();
|
||||
for (j = 0; j < width - 8; j += 8) {
|
||||
for (j = 0; j <= width - 8; j += 8) {
|
||||
const __m128i d0 = _mm_cvtepu8_epi16(xx_loadl_64(dat + j));
|
||||
const __m128i s0 = _mm_cvtepu8_epi16(xx_loadl_64(src + j));
|
||||
const __m128i flt0_16b =
|
||||
|
|
@ -275,7 +539,7 @@ int64_t av1_lowbd_pixel_proj_error_sse4_1(
|
|||
const int32_t u = (int32_t)(dat[k] << SGRPROJ_RST_BITS);
|
||||
int32_t v = xq[0] * (flt0[k] - u) + xq[1] * (flt1[k] - u);
|
||||
const int32_t e = ROUND_POWER_OF_TWO(v, shift) + dat[k] - src[k];
|
||||
err += e * e;
|
||||
err += ((int64_t)e * e);
|
||||
}
|
||||
dat += dat_stride;
|
||||
src += src_stride;
|
||||
|
|
@ -286,19 +550,23 @@ int64_t av1_lowbd_pixel_proj_error_sse4_1(
|
|||
sum64 = _mm_add_epi64(sum64, sum64_0);
|
||||
sum64 = _mm_add_epi64(sum64, sum64_1);
|
||||
}
|
||||
} else if (params->r[0] > 0) {
|
||||
__m128i xq_coeff = pair_set_epi16(xq[0], -(xq[0] << SGRPROJ_RST_BITS));
|
||||
} else if (params->r[0] > 0 || params->r[1] > 0) {
|
||||
const int xq_active = (params->r[0] > 0) ? xq[0] : xq[1];
|
||||
const __m128i xq_coeff =
|
||||
pair_set_epi16(xq_active, -(xq_active << SGRPROJ_RST_BITS));
|
||||
const int32_t *flt = (params->r[0] > 0) ? flt0 : flt1;
|
||||
const int flt_stride = (params->r[0] > 0) ? flt0_stride : flt1_stride;
|
||||
for (i = 0; i < height; ++i) {
|
||||
__m128i sum32 = _mm_setzero_si128();
|
||||
for (j = 0; j < width - 8; j += 8) {
|
||||
for (j = 0; j <= width - 8; j += 8) {
|
||||
const __m128i d0 = _mm_cvtepu8_epi16(xx_loadl_64(dat + j));
|
||||
const __m128i s0 = _mm_cvtepu8_epi16(xx_loadl_64(src + j));
|
||||
const __m128i flt0_16b =
|
||||
_mm_packs_epi32(xx_loadu_128(flt0 + j), xx_loadu_128(flt0 + j + 4));
|
||||
const __m128i flt_16b =
|
||||
_mm_packs_epi32(xx_loadu_128(flt + j), xx_loadu_128(flt + j + 4));
|
||||
const __m128i v0 =
|
||||
_mm_madd_epi16(xq_coeff, _mm_unpacklo_epi16(flt0_16b, d0));
|
||||
_mm_madd_epi16(xq_coeff, _mm_unpacklo_epi16(flt_16b, d0));
|
||||
const __m128i v1 =
|
||||
_mm_madd_epi16(xq_coeff, _mm_unpackhi_epi16(flt0_16b, d0));
|
||||
_mm_madd_epi16(xq_coeff, _mm_unpackhi_epi16(flt_16b, d0));
|
||||
const __m128i vr0 = _mm_srai_epi32(_mm_add_epi32(v0, rounding), shift);
|
||||
const __m128i vr1 = _mm_srai_epi32(_mm_add_epi32(v1, rounding), shift);
|
||||
const __m128i e0 =
|
||||
|
|
@ -308,47 +576,13 @@ int64_t av1_lowbd_pixel_proj_error_sse4_1(
|
|||
}
|
||||
for (k = j; k < width; ++k) {
|
||||
const int32_t u = (int32_t)(dat[k] << SGRPROJ_RST_BITS);
|
||||
int32_t v = xq[0] * (flt0[k] - u);
|
||||
int32_t v = xq_active * (flt[k] - u);
|
||||
const int32_t e = ROUND_POWER_OF_TWO(v, shift) + dat[k] - src[k];
|
||||
err += e * e;
|
||||
err += ((int64_t)e * e);
|
||||
}
|
||||
dat += dat_stride;
|
||||
src += src_stride;
|
||||
flt0 += flt0_stride;
|
||||
const __m128i sum64_0 = _mm_cvtepi32_epi64(sum32);
|
||||
const __m128i sum64_1 = _mm_cvtepi32_epi64(_mm_srli_si128(sum32, 8));
|
||||
sum64 = _mm_add_epi64(sum64, sum64_0);
|
||||
sum64 = _mm_add_epi64(sum64, sum64_1);
|
||||
}
|
||||
} else if (params->r[1] > 0) {
|
||||
__m128i xq_coeff = pair_set_epi16(xq[1], -(xq[1] << SGRPROJ_RST_BITS));
|
||||
for (i = 0; i < height; ++i) {
|
||||
__m128i sum32 = _mm_setzero_si128();
|
||||
for (j = 0; j < width - 8; j += 8) {
|
||||
const __m128i d0 = _mm_cvtepu8_epi16(xx_loadl_64(dat + j));
|
||||
const __m128i s0 = _mm_cvtepu8_epi16(xx_loadl_64(src + j));
|
||||
const __m128i flt1_16b =
|
||||
_mm_packs_epi32(xx_loadu_128(flt1 + j), xx_loadu_128(flt1 + j + 4));
|
||||
const __m128i v0 =
|
||||
_mm_madd_epi16(xq_coeff, _mm_unpacklo_epi16(flt1_16b, d0));
|
||||
const __m128i v1 =
|
||||
_mm_madd_epi16(xq_coeff, _mm_unpackhi_epi16(flt1_16b, d0));
|
||||
const __m128i vr0 = _mm_srai_epi32(_mm_add_epi32(v0, rounding), shift);
|
||||
const __m128i vr1 = _mm_srai_epi32(_mm_add_epi32(v1, rounding), shift);
|
||||
const __m128i e0 =
|
||||
_mm_sub_epi16(_mm_add_epi16(_mm_packs_epi32(vr0, vr1), d0), s0);
|
||||
const __m128i err0 = _mm_madd_epi16(e0, e0);
|
||||
sum32 = _mm_add_epi32(sum32, err0);
|
||||
}
|
||||
for (k = j; k < width; ++k) {
|
||||
const int32_t u = (int32_t)(dat[k] << SGRPROJ_RST_BITS);
|
||||
int32_t v = xq[1] * (flt1[k] - u);
|
||||
const int32_t e = ROUND_POWER_OF_TWO(v, shift) + dat[k] - src[k];
|
||||
err += e * e;
|
||||
}
|
||||
dat += dat_stride;
|
||||
src += src_stride;
|
||||
flt1 += flt1_stride;
|
||||
flt += flt_stride;
|
||||
const __m128i sum64_0 = _mm_cvtepi32_epi64(sum32);
|
||||
const __m128i sum64_1 = _mm_cvtepi32_epi64(_mm_srli_si128(sum32, 8));
|
||||
sum64 = _mm_add_epi64(sum64, sum64_0);
|
||||
|
|
@ -357,7 +591,7 @@ int64_t av1_lowbd_pixel_proj_error_sse4_1(
|
|||
} else {
|
||||
__m128i sum32 = _mm_setzero_si128();
|
||||
for (i = 0; i < height; ++i) {
|
||||
for (j = 0; j < width - 16; j += 16) {
|
||||
for (j = 0; j <= width - 16; j += 16) {
|
||||
const __m128i d = xx_loadu_128(dat + j);
|
||||
const __m128i s = xx_loadu_128(src + j);
|
||||
const __m128i d0 = _mm_cvtepu8_epi16(d);
|
||||
|
|
@ -373,7 +607,7 @@ int64_t av1_lowbd_pixel_proj_error_sse4_1(
|
|||
}
|
||||
for (k = j; k < width; ++k) {
|
||||
const int32_t e = (int32_t)(dat[k]) - src[k];
|
||||
err += e * e;
|
||||
err += ((int64_t)e * e);
|
||||
}
|
||||
dat += dat_stride;
|
||||
src += src_stride;
|
||||
|
|
@ -387,3 +621,209 @@ int64_t av1_lowbd_pixel_proj_error_sse4_1(
|
|||
err += sum[0] + sum[1];
|
||||
return err;
|
||||
}
|
||||
|
||||
int64_t av1_highbd_pixel_proj_error_sse4_1(
|
||||
const uint8_t *src8, int width, int height, int src_stride,
|
||||
const uint8_t *dat8, int dat_stride, int32_t *flt0, int flt0_stride,
|
||||
int32_t *flt1, int flt1_stride, int xq[2], const sgr_params_type *params) {
|
||||
int i, j, k;
|
||||
const int32_t shift = SGRPROJ_RST_BITS + SGRPROJ_PRJ_BITS;
|
||||
const __m128i rounding = _mm_set1_epi32(1 << (shift - 1));
|
||||
__m128i sum64 = _mm_setzero_si128();
|
||||
const uint16_t *src = CONVERT_TO_SHORTPTR(src8);
|
||||
const uint16_t *dat = CONVERT_TO_SHORTPTR(dat8);
|
||||
int64_t err = 0;
|
||||
if (params->r[0] > 0 && params->r[1] > 0) { // Both filters are enabled
|
||||
const __m128i xq0 = _mm_set1_epi32(xq[0]);
|
||||
const __m128i xq1 = _mm_set1_epi32(xq[1]);
|
||||
|
||||
for (i = 0; i < height; ++i) {
|
||||
__m128i sum32 = _mm_setzero_si128();
|
||||
for (j = 0; j <= width - 8; j += 8) {
|
||||
// Load 8x pixels from source image
|
||||
const __m128i s0 = xx_loadu_128(src + j);
|
||||
// s0 = [7 6 5 4 3 2 1 0] as i16 (indices of src[])
|
||||
|
||||
// Load 8x pixels from corrupted image
|
||||
const __m128i d0 = xx_loadu_128(dat + j);
|
||||
// d0 = [7 6 5 4 3 2 1 0] as i16 (indices of dat[])
|
||||
|
||||
// Shift each pixel value up by SGRPROJ_RST_BITS
|
||||
const __m128i u0 = _mm_slli_epi16(d0, SGRPROJ_RST_BITS);
|
||||
|
||||
// Split u0 into two halves and pad each from u16 to i32
|
||||
const __m128i u0l = _mm_cvtepu16_epi32(u0);
|
||||
const __m128i u0h = _mm_cvtepu16_epi32(_mm_srli_si128(u0, 8));
|
||||
// u0h = [7 6 5 4] as i32, u0l = [3 2 1 0] as i32, all dat[] indices
|
||||
|
||||
// Load 8 pixels from first and second filtered images
|
||||
const __m128i flt0l = xx_loadu_128(flt0 + j);
|
||||
const __m128i flt0h = xx_loadu_128(flt0 + j + 4);
|
||||
const __m128i flt1l = xx_loadu_128(flt1 + j);
|
||||
const __m128i flt1h = xx_loadu_128(flt1 + j + 4);
|
||||
// flt0 = [7 6 5 4] [3 2 1 0] as i32 (indices of flt0+j)
|
||||
// flt1 = [7 6 5 4] [3 2 1 0] as i32 (indices of flt1+j)
|
||||
|
||||
// Subtract shifted corrupt image from each filtered image
|
||||
// This gives our two basis vectors for the projection
|
||||
const __m128i flt0l_subu = _mm_sub_epi32(flt0l, u0l);
|
||||
const __m128i flt0h_subu = _mm_sub_epi32(flt0h, u0h);
|
||||
const __m128i flt1l_subu = _mm_sub_epi32(flt1l, u0l);
|
||||
const __m128i flt1h_subu = _mm_sub_epi32(flt1h, u0h);
|
||||
// flt?h_subu = [ f[7]-u[7] f[6]-u[6] f[5]-u[5] f[4]-u[4] ] as i32
|
||||
// flt?l_subu = [ f[3]-u[3] f[2]-u[2] f[1]-u[1] f[0]-u[0] ] as i32
|
||||
|
||||
// Multiply each basis vector by the corresponding coefficient
|
||||
const __m128i v0l = _mm_mullo_epi32(flt0l_subu, xq0);
|
||||
const __m128i v0h = _mm_mullo_epi32(flt0h_subu, xq0);
|
||||
const __m128i v1l = _mm_mullo_epi32(flt1l_subu, xq1);
|
||||
const __m128i v1h = _mm_mullo_epi32(flt1h_subu, xq1);
|
||||
|
||||
// Add together the contribution from each scaled basis vector
|
||||
const __m128i vl = _mm_add_epi32(v0l, v1l);
|
||||
const __m128i vh = _mm_add_epi32(v0h, v1h);
|
||||
|
||||
// Right-shift v with appropriate rounding
|
||||
const __m128i vrl = _mm_srai_epi32(_mm_add_epi32(vl, rounding), shift);
|
||||
const __m128i vrh = _mm_srai_epi32(_mm_add_epi32(vh, rounding), shift);
|
||||
|
||||
// Saturate each i32 value to i16 and combine lower and upper halves
|
||||
const __m128i vr = _mm_packs_epi32(vrl, vrh);
|
||||
|
||||
// Add twin-subspace-sgr-filter to corrupt image then subtract source
|
||||
const __m128i e0 = _mm_sub_epi16(_mm_add_epi16(vr, d0), s0);
|
||||
|
||||
// Calculate squared error and add adjacent values
|
||||
const __m128i err0 = _mm_madd_epi16(e0, e0);
|
||||
|
||||
sum32 = _mm_add_epi32(sum32, err0);
|
||||
}
|
||||
|
||||
const __m128i sum32l = _mm_cvtepu32_epi64(sum32);
|
||||
sum64 = _mm_add_epi64(sum64, sum32l);
|
||||
const __m128i sum32h = _mm_cvtepu32_epi64(_mm_srli_si128(sum32, 8));
|
||||
sum64 = _mm_add_epi64(sum64, sum32h);
|
||||
|
||||
// Process remaining pixels in this row (modulo 8)
|
||||
for (k = j; k < width; ++k) {
|
||||
const int32_t u = (int32_t)(dat[k] << SGRPROJ_RST_BITS);
|
||||
int32_t v = xq[0] * (flt0[k] - u) + xq[1] * (flt1[k] - u);
|
||||
const int32_t e = ROUND_POWER_OF_TWO(v, shift) + dat[k] - src[k];
|
||||
err += ((int64_t)e * e);
|
||||
}
|
||||
dat += dat_stride;
|
||||
src += src_stride;
|
||||
flt0 += flt0_stride;
|
||||
flt1 += flt1_stride;
|
||||
}
|
||||
} else if (params->r[0] > 0 || params->r[1] > 0) { // Only one filter enabled
|
||||
const int32_t xq_on = (params->r[0] > 0) ? xq[0] : xq[1];
|
||||
const __m128i xq_active = _mm_set1_epi32(xq_on);
|
||||
const __m128i xq_inactive =
|
||||
_mm_set1_epi32(-xq_on * (1 << SGRPROJ_RST_BITS));
|
||||
const int32_t *flt = (params->r[0] > 0) ? flt0 : flt1;
|
||||
const int flt_stride = (params->r[0] > 0) ? flt0_stride : flt1_stride;
|
||||
for (i = 0; i < height; ++i) {
|
||||
__m128i sum32 = _mm_setzero_si128();
|
||||
for (j = 0; j <= width - 8; j += 8) {
|
||||
// Load 8x pixels from source image
|
||||
const __m128i s0 = xx_loadu_128(src + j);
|
||||
// s0 = [7 6 5 4 3 2 1 0] as u16 (indices of src[])
|
||||
|
||||
// Load 8x pixels from corrupted image and pad each u16 to i32
|
||||
const __m128i d0 = xx_loadu_128(dat + j);
|
||||
const __m128i d0h = _mm_cvtepu16_epi32(_mm_srli_si128(d0, 8));
|
||||
const __m128i d0l = _mm_cvtepu16_epi32(d0);
|
||||
// d0h, d0l = [7 6 5 4], [3 2 1 0] as u32 (indices of dat[])
|
||||
|
||||
// Load 8 pixels from the filtered image
|
||||
const __m128i flth = xx_loadu_128(flt + j + 4);
|
||||
const __m128i fltl = xx_loadu_128(flt + j);
|
||||
// flth, fltl = [7 6 5 4], [3 2 1 0] as i32 (indices of flt+j)
|
||||
|
||||
const __m128i flth_xq = _mm_mullo_epi32(flth, xq_active);
|
||||
const __m128i fltl_xq = _mm_mullo_epi32(fltl, xq_active);
|
||||
const __m128i d0h_xq = _mm_mullo_epi32(d0h, xq_inactive);
|
||||
const __m128i d0l_xq = _mm_mullo_epi32(d0l, xq_inactive);
|
||||
|
||||
const __m128i vh = _mm_add_epi32(flth_xq, d0h_xq);
|
||||
const __m128i vl = _mm_add_epi32(fltl_xq, d0l_xq);
|
||||
// vh = [ xq0(f[7]-d[7]) xq0(f[6]-d[6]) xq0(f[5]-d[5]) xq0(f[4]-d[4]) ]
|
||||
// vl = [ xq0(f[3]-d[3]) xq0(f[2]-d[2]) xq0(f[1]-d[1]) xq0(f[0]-d[0]) ]
|
||||
|
||||
// Shift this down with appropriate rounding
|
||||
const __m128i vrh = _mm_srai_epi32(_mm_add_epi32(vh, rounding), shift);
|
||||
const __m128i vrl = _mm_srai_epi32(_mm_add_epi32(vl, rounding), shift);
|
||||
|
||||
// Saturate vr0 and vr1 from i32 to i16 then pack together
|
||||
const __m128i vr = _mm_packs_epi32(vrl, vrh);
|
||||
|
||||
// Subtract twin-subspace-sgr filtered from source image to get error
|
||||
const __m128i e0 = _mm_sub_epi16(_mm_add_epi16(vr, d0), s0);
|
||||
|
||||
// Calculate squared error and add adjacent values
|
||||
const __m128i err0 = _mm_madd_epi16(e0, e0);
|
||||
|
||||
sum32 = _mm_add_epi32(sum32, err0);
|
||||
}
|
||||
|
||||
const __m128i sum32l = _mm_cvtepu32_epi64(sum32);
|
||||
sum64 = _mm_add_epi64(sum64, sum32l);
|
||||
const __m128i sum32h = _mm_cvtepu32_epi64(_mm_srli_si128(sum32, 8));
|
||||
sum64 = _mm_add_epi64(sum64, sum32h);
|
||||
|
||||
// Process remaining pixels in this row (modulo 8)
|
||||
for (k = j; k < width; ++k) {
|
||||
const int32_t u = (int32_t)(dat[k] << SGRPROJ_RST_BITS);
|
||||
int32_t v = xq_on * (flt[k] - u);
|
||||
const int32_t e = ROUND_POWER_OF_TWO(v, shift) + dat[k] - src[k];
|
||||
err += ((int64_t)e * e);
|
||||
}
|
||||
dat += dat_stride;
|
||||
src += src_stride;
|
||||
flt += flt_stride;
|
||||
}
|
||||
} else { // Neither filter is enabled
|
||||
for (i = 0; i < height; ++i) {
|
||||
__m128i sum32 = _mm_setzero_si128();
|
||||
for (j = 0; j <= width - 16; j += 16) {
|
||||
// Load 2x8 u16 from source image
|
||||
const __m128i s0 = xx_loadu_128(src + j);
|
||||
const __m128i s1 = xx_loadu_128(src + j + 8);
|
||||
// Load 2x8 u16 from corrupted image
|
||||
const __m128i d0 = xx_loadu_128(dat + j);
|
||||
const __m128i d1 = xx_loadu_128(dat + j + 8);
|
||||
|
||||
// Subtract corrupted image from source image
|
||||
const __m128i diff0 = _mm_sub_epi16(d0, s0);
|
||||
const __m128i diff1 = _mm_sub_epi16(d1, s1);
|
||||
|
||||
// Square error and add adjacent values
|
||||
const __m128i err0 = _mm_madd_epi16(diff0, diff0);
|
||||
const __m128i err1 = _mm_madd_epi16(diff1, diff1);
|
||||
|
||||
sum32 = _mm_add_epi32(sum32, err0);
|
||||
sum32 = _mm_add_epi32(sum32, err1);
|
||||
}
|
||||
|
||||
const __m128i sum32l = _mm_cvtepu32_epi64(sum32);
|
||||
sum64 = _mm_add_epi64(sum64, sum32l);
|
||||
const __m128i sum32h = _mm_cvtepu32_epi64(_mm_srli_si128(sum32, 8));
|
||||
sum64 = _mm_add_epi64(sum64, sum32h);
|
||||
|
||||
// Process remaining pixels (modulu 8)
|
||||
for (k = j; k < width; ++k) {
|
||||
const int32_t e = (int32_t)(dat[k]) - src[k];
|
||||
err += ((int64_t)e * e);
|
||||
}
|
||||
dat += dat_stride;
|
||||
src += src_stride;
|
||||
}
|
||||
}
|
||||
|
||||
// Sum 4 values from sum64l and sum64h into err
|
||||
int64_t sum[2];
|
||||
xx_storeu_128(sum, sum64);
|
||||
err += sum[0] + sum[1];
|
||||
return err;
|
||||
}
|
||||
|
|
|
|||
256
third_party/aom/av1/encoder/x86/rdopt_avx2.c
vendored
Normal file
256
third_party/aom/av1/encoder/x86/rdopt_avx2.c
vendored
Normal file
|
|
@ -0,0 +1,256 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <immintrin.h>
|
||||
#include "aom_dsp/x86/synonyms_avx2.h"
|
||||
#include "aom_ports/system_state.h"
|
||||
|
||||
#include "config/av1_rtcd.h"
|
||||
#include "av1/encoder/rdopt.h"
|
||||
|
||||
// Process horizontal and vertical correlations in a 4x4 block of pixels.
|
||||
// We actually use the 4x4 pixels to calculate correlations corresponding to
|
||||
// the top-left 3x3 pixels, so this function must be called with 1x1 overlap,
|
||||
// moving the window along/down by 3 pixels at a time.
|
||||
INLINE static void horver_correlation_4x4(const int16_t *diff, int stride,
|
||||
__m256i *xy_sum_32,
|
||||
__m256i *xz_sum_32, __m256i *x_sum_32,
|
||||
__m256i *x2_sum_32) {
|
||||
// Pixels in this 4x4 [ a b c d ]
|
||||
// are referred to as: [ e f g h ]
|
||||
// [ i j k l ]
|
||||
// [ m n o p ]
|
||||
|
||||
const __m256i pixels = _mm256_set_epi64x(
|
||||
*(uint64_t *)&diff[0 * stride], *(uint64_t *)&diff[1 * stride],
|
||||
*(uint64_t *)&diff[2 * stride], *(uint64_t *)&diff[3 * stride]);
|
||||
// pixels = [d c b a h g f e] [l k j i p o n m] as i16
|
||||
|
||||
const __m256i slli = _mm256_slli_epi64(pixels, 16);
|
||||
// slli = [c b a 0 g f e 0] [k j i 0 o n m 0] as i16
|
||||
|
||||
const __m256i madd_xy = _mm256_madd_epi16(pixels, slli);
|
||||
// madd_xy = [bc+cd ab fg+gh ef] [jk+kl ij no+op mn] as i32
|
||||
*xy_sum_32 = _mm256_add_epi32(*xy_sum_32, madd_xy);
|
||||
|
||||
// Permute control [3 2] [1 0] => [2 1] [0 0], 0b10010000 = 0x90
|
||||
const __m256i perm = _mm256_permute4x64_epi64(slli, 0x90);
|
||||
// perm = [g f e 0 k j i 0] [o n m 0 o n m 0] as i16
|
||||
|
||||
const __m256i madd_xz = _mm256_madd_epi16(slli, perm);
|
||||
// madd_xz = [cg+bf ae gk+fj ei] [ko+jn im oo+nn mm] as i32
|
||||
*xz_sum_32 = _mm256_add_epi32(*xz_sum_32, madd_xz);
|
||||
|
||||
// Sum every element in slli (and then also their squares)
|
||||
const __m256i madd1_slli = _mm256_madd_epi16(slli, _mm256_set1_epi16(1));
|
||||
// madd1_slli = [c+b a g+f e] [k+j i o+n m] as i32
|
||||
*x_sum_32 = _mm256_add_epi32(*x_sum_32, madd1_slli);
|
||||
|
||||
const __m256i madd_slli = _mm256_madd_epi16(slli, slli);
|
||||
// madd_slli = [cc+bb aa gg+ff ee] [kk+jj ii oo+nn mm] as i32
|
||||
*x2_sum_32 = _mm256_add_epi32(*x2_sum_32, madd_slli);
|
||||
}
|
||||
|
||||
void av1_get_horver_correlation_full_avx2(const int16_t *diff, int stride,
|
||||
int width, int height, float *hcorr,
|
||||
float *vcorr) {
|
||||
// The following notation is used:
|
||||
// x - current pixel
|
||||
// y - right neighbour pixel
|
||||
// z - below neighbour pixel
|
||||
// w - down-right neighbour pixel
|
||||
int64_t xy_sum = 0, xz_sum = 0;
|
||||
int64_t x_sum = 0, x2_sum = 0;
|
||||
|
||||
// Process horizontal and vertical correlations through the body in 4x4
|
||||
// blocks. This excludes the final row and column and possibly one extra
|
||||
// column depending how 3 divides into width and height
|
||||
int32_t xy_xz_tmp[8] = { 0 }, x_x2_tmp[8] = { 0 };
|
||||
__m256i xy_sum_32 = _mm256_setzero_si256();
|
||||
__m256i xz_sum_32 = _mm256_setzero_si256();
|
||||
__m256i x_sum_32 = _mm256_setzero_si256();
|
||||
__m256i x2_sum_32 = _mm256_setzero_si256();
|
||||
for (int i = 0; i <= height - 4; i += 3) {
|
||||
for (int j = 0; j <= width - 4; j += 3) {
|
||||
horver_correlation_4x4(&diff[i * stride + j], stride, &xy_sum_32,
|
||||
&xz_sum_32, &x_sum_32, &x2_sum_32);
|
||||
}
|
||||
const __m256i hadd_xy_xz = _mm256_hadd_epi32(xy_sum_32, xz_sum_32);
|
||||
// hadd_xy_xz = [ae+bf+cg ei+fj+gk ab+bc+cd ef+fg+gh]
|
||||
// [im+jn+ko mm+nn+oo ij+jk+kl mn+no+op] as i32
|
||||
yy_storeu_256(xy_xz_tmp, hadd_xy_xz);
|
||||
xy_sum += (int64_t)xy_xz_tmp[5] + xy_xz_tmp[4] + xy_xz_tmp[1];
|
||||
xz_sum += (int64_t)xy_xz_tmp[7] + xy_xz_tmp[6] + xy_xz_tmp[3];
|
||||
|
||||
const __m256i hadd_x_x2 = _mm256_hadd_epi32(x_sum_32, x2_sum_32);
|
||||
// hadd_x_x2 = [aa+bb+cc ee+ff+gg a+b+c e+f+g]
|
||||
// [ii+jj+kk mm+nn+oo i+j+k m+n+o] as i32
|
||||
yy_storeu_256(x_x2_tmp, hadd_x_x2);
|
||||
x_sum += (int64_t)x_x2_tmp[5] + x_x2_tmp[4] + x_x2_tmp[1];
|
||||
x2_sum += (int64_t)x_x2_tmp[7] + x_x2_tmp[6] + x_x2_tmp[3];
|
||||
|
||||
xy_sum_32 = _mm256_setzero_si256();
|
||||
xz_sum_32 = _mm256_setzero_si256();
|
||||
x_sum_32 = _mm256_setzero_si256();
|
||||
x2_sum_32 = _mm256_setzero_si256();
|
||||
}
|
||||
|
||||
// x_sum now covers every pixel except the final 1-2 rows and 1-2 cols
|
||||
int64_t x_finalrow = 0, x_finalcol = 0, x2_finalrow = 0, x2_finalcol = 0;
|
||||
|
||||
// Do we have 2 rows remaining or just the one? Note that width and height
|
||||
// are powers of 2, so each modulo 3 must be 1 or 2.
|
||||
if (height % 3 == 1) { // Just horiz corrs on the final row
|
||||
const int16_t x0 = diff[(height - 1) * stride];
|
||||
x_sum += x0;
|
||||
x_finalrow += x0;
|
||||
x2_sum += x0 * x0;
|
||||
x2_finalrow += x0 * x0;
|
||||
for (int j = 0; j < width - 1; ++j) {
|
||||
const int16_t x = diff[(height - 1) * stride + j];
|
||||
const int16_t y = diff[(height - 1) * stride + j + 1];
|
||||
xy_sum += x * y;
|
||||
x_sum += y;
|
||||
x2_sum += y * y;
|
||||
x_finalrow += y;
|
||||
x2_finalrow += y * y;
|
||||
}
|
||||
} else { // Two rows remaining to do
|
||||
const int16_t x0 = diff[(height - 2) * stride];
|
||||
const int16_t z0 = diff[(height - 1) * stride];
|
||||
x_sum += x0 + z0;
|
||||
x2_sum += x0 * x0 + z0 * z0;
|
||||
x_finalrow += z0;
|
||||
x2_finalrow += z0 * z0;
|
||||
for (int j = 0; j < width - 1; ++j) {
|
||||
const int16_t x = diff[(height - 2) * stride + j];
|
||||
const int16_t y = diff[(height - 2) * stride + j + 1];
|
||||
const int16_t z = diff[(height - 1) * stride + j];
|
||||
const int16_t w = diff[(height - 1) * stride + j + 1];
|
||||
|
||||
// Horizontal and vertical correlations for the penultimate row:
|
||||
xy_sum += x * y;
|
||||
xz_sum += x * z;
|
||||
|
||||
// Now just horizontal correlations for the final row:
|
||||
xy_sum += z * w;
|
||||
|
||||
x_sum += y + w;
|
||||
x2_sum += y * y + w * w;
|
||||
x_finalrow += w;
|
||||
x2_finalrow += w * w;
|
||||
}
|
||||
}
|
||||
|
||||
// Do we have 2 columns remaining or just the one?
|
||||
if (width % 3 == 1) { // Just vert corrs on the final col
|
||||
const int16_t x0 = diff[width - 1];
|
||||
x_sum += x0;
|
||||
x_finalcol += x0;
|
||||
x2_sum += x0 * x0;
|
||||
x2_finalcol += x0 * x0;
|
||||
for (int i = 0; i < height - 1; ++i) {
|
||||
const int16_t x = diff[i * stride + width - 1];
|
||||
const int16_t z = diff[(i + 1) * stride + width - 1];
|
||||
xz_sum += x * z;
|
||||
x_finalcol += z;
|
||||
x2_finalcol += z * z;
|
||||
// So the bottom-right elements don't get counted twice:
|
||||
if (i < height - (height % 3 == 1 ? 2 : 3)) {
|
||||
x_sum += z;
|
||||
x2_sum += z * z;
|
||||
}
|
||||
}
|
||||
} else { // Two cols remaining
|
||||
const int16_t x0 = diff[width - 2];
|
||||
const int16_t y0 = diff[width - 1];
|
||||
x_sum += x0 + y0;
|
||||
x2_sum += x0 * x0 + y0 * y0;
|
||||
x_finalcol += y0;
|
||||
x2_finalcol += y0 * y0;
|
||||
for (int i = 0; i < height - 1; ++i) {
|
||||
const int16_t x = diff[i * stride + width - 2];
|
||||
const int16_t y = diff[i * stride + width - 1];
|
||||
const int16_t z = diff[(i + 1) * stride + width - 2];
|
||||
const int16_t w = diff[(i + 1) * stride + width - 1];
|
||||
|
||||
// Horizontal and vertical correlations for the penultimate col:
|
||||
// Skip these on the last iteration of this loop if we also had two
|
||||
// rows remaining, otherwise the final horizontal and vertical correlation
|
||||
// get erroneously processed twice
|
||||
if (i < height - 2 || height % 3 == 1) {
|
||||
xy_sum += x * y;
|
||||
xz_sum += x * z;
|
||||
}
|
||||
|
||||
x_finalcol += w;
|
||||
x2_finalcol += w * w;
|
||||
// So the bottom-right elements don't get counted twice:
|
||||
if (i < height - (height % 3 == 1 ? 2 : 3)) {
|
||||
x_sum += z + w;
|
||||
x2_sum += z * z + w * w;
|
||||
}
|
||||
|
||||
// Now just vertical correlations for the final column:
|
||||
xz_sum += y * w;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the simple sums and squared-sums
|
||||
int64_t x_firstrow = 0, x_firstcol = 0;
|
||||
int64_t x2_firstrow = 0, x2_firstcol = 0;
|
||||
|
||||
for (int j = 0; j < width; ++j) {
|
||||
x_firstrow += diff[j];
|
||||
x2_firstrow += diff[j] * diff[j];
|
||||
}
|
||||
for (int i = 0; i < height; ++i) {
|
||||
x_firstcol += diff[i * stride];
|
||||
x2_firstcol += diff[i * stride] * diff[i * stride];
|
||||
}
|
||||
|
||||
int64_t xhor_sum = x_sum - x_finalcol;
|
||||
int64_t xver_sum = x_sum - x_finalrow;
|
||||
int64_t y_sum = x_sum - x_firstcol;
|
||||
int64_t z_sum = x_sum - x_firstrow;
|
||||
int64_t x2hor_sum = x2_sum - x2_finalcol;
|
||||
int64_t x2ver_sum = x2_sum - x2_finalrow;
|
||||
int64_t y2_sum = x2_sum - x2_firstcol;
|
||||
int64_t z2_sum = x2_sum - x2_firstrow;
|
||||
|
||||
aom_clear_system_state();
|
||||
|
||||
const float num_hor = (float)(height * (width - 1));
|
||||
const float num_ver = (float)((height - 1) * width);
|
||||
|
||||
const float xhor_var_n = x2hor_sum - (xhor_sum * xhor_sum) / num_hor;
|
||||
const float xver_var_n = x2ver_sum - (xver_sum * xver_sum) / num_ver;
|
||||
|
||||
const float y_var_n = y2_sum - (y_sum * y_sum) / num_hor;
|
||||
const float z_var_n = z2_sum - (z_sum * z_sum) / num_ver;
|
||||
|
||||
const float xy_var_n = xy_sum - (xhor_sum * y_sum) / num_hor;
|
||||
const float xz_var_n = xz_sum - (xver_sum * z_sum) / num_ver;
|
||||
|
||||
if (xhor_var_n > 0 && y_var_n > 0) {
|
||||
*hcorr = xy_var_n / sqrtf(xhor_var_n * y_var_n);
|
||||
*hcorr = *hcorr < 0 ? 0 : *hcorr;
|
||||
} else {
|
||||
*hcorr = 1.0;
|
||||
}
|
||||
if (xver_var_n > 0 && z_var_n > 0) {
|
||||
*vcorr = xz_var_n / sqrtf(xver_var_n * z_var_n);
|
||||
*vcorr = *vcorr < 0 ? 0 : *vcorr;
|
||||
} else {
|
||||
*vcorr = 1.0;
|
||||
}
|
||||
}
|
||||
275
third_party/aom/av1/encoder/x86/rdopt_sse4.c
vendored
Normal file
275
third_party/aom/av1/encoder/x86/rdopt_sse4.c
vendored
Normal file
|
|
@ -0,0 +1,275 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <emmintrin.h>
|
||||
#include "aom_dsp/x86/synonyms.h"
|
||||
#include "aom_ports/system_state.h"
|
||||
|
||||
#include "config/av1_rtcd.h"
|
||||
#include "av1/encoder/rdopt.h"
|
||||
|
||||
// Process horizontal and vertical correlations in a 4x4 block of pixels.
|
||||
// We actually use the 4x4 pixels to calculate correlations corresponding to
|
||||
// the top-left 3x3 pixels, so this function must be called with 1x1 overlap,
|
||||
// moving the window along/down by 3 pixels at a time.
|
||||
INLINE static void horver_correlation_4x4(const int16_t *diff, int stride,
|
||||
__m128i *xy_sum_32,
|
||||
__m128i *xz_sum_32, __m128i *x_sum_32,
|
||||
__m128i *x2_sum_32) {
|
||||
// Pixels in this 4x4 [ a b c d ]
|
||||
// are referred to as: [ e f g h ]
|
||||
// [ i j k l ]
|
||||
// [ m n o p ]
|
||||
|
||||
const __m128i pixelsa = _mm_set_epi64x(*(uint64_t *)&diff[0 * stride],
|
||||
*(uint64_t *)&diff[2 * stride]);
|
||||
const __m128i pixelsb = _mm_set_epi64x(*(uint64_t *)&diff[1 * stride],
|
||||
*(uint64_t *)&diff[3 * stride]);
|
||||
// pixelsa = [d c b a l k j i] as i16
|
||||
// pixelsb = [h g f e p o n m] as i16
|
||||
|
||||
const __m128i slli_a = _mm_slli_epi64(pixelsa, 16);
|
||||
const __m128i slli_b = _mm_slli_epi64(pixelsb, 16);
|
||||
// slli_a = [c b a 0 k j i 0] as i16
|
||||
// slli_b = [g f e 0 o n m 0] as i16
|
||||
|
||||
const __m128i xy_madd_a = _mm_madd_epi16(pixelsa, slli_a);
|
||||
const __m128i xy_madd_b = _mm_madd_epi16(pixelsb, slli_b);
|
||||
// xy_madd_a = [bc+cd ab jk+kl ij] as i32
|
||||
// xy_madd_b = [fg+gh ef no+op mn] as i32
|
||||
|
||||
const __m128i xy32 = _mm_hadd_epi32(xy_madd_b, xy_madd_a);
|
||||
// xy32 = [ab+bc+cd ij+jk+kl ef+fg+gh mn+no+op] as i32
|
||||
*xy_sum_32 = _mm_add_epi32(*xy_sum_32, xy32);
|
||||
|
||||
const __m128i xz_madd_a = _mm_madd_epi16(slli_a, slli_b);
|
||||
// xz_madd_a = [bf+cg ae jn+ko im] i32
|
||||
|
||||
const __m128i swap_b = _mm_srli_si128(slli_b, 8);
|
||||
// swap_b = [0 0 0 0 g f e 0] as i16
|
||||
const __m128i xz_madd_b = _mm_madd_epi16(slli_a, swap_b);
|
||||
// xz_madd_b = [0 0 gk+fj ei] i32
|
||||
|
||||
const __m128i xz32 = _mm_hadd_epi32(xz_madd_b, xz_madd_a);
|
||||
// xz32 = [ae+bf+cg im+jn+ko 0 ei+fj+gk] i32
|
||||
*xz_sum_32 = _mm_add_epi32(*xz_sum_32, xz32);
|
||||
|
||||
// Now calculate the straight sums, x_sum += a+b+c+e+f+g+i+j+k
|
||||
// (sum up every element in slli_a and swap_b)
|
||||
const __m128i sum_slli_a = _mm_hadd_epi16(slli_a, slli_a);
|
||||
const __m128i sum_slli_a32 = _mm_cvtepi16_epi32(sum_slli_a);
|
||||
// sum_slli_a32 = [c+b a k+j i] as i32
|
||||
const __m128i swap_b32 = _mm_cvtepi16_epi32(swap_b);
|
||||
// swap_b32 = [g f e 0] as i32
|
||||
*x_sum_32 = _mm_add_epi32(*x_sum_32, sum_slli_a32);
|
||||
*x_sum_32 = _mm_add_epi32(*x_sum_32, swap_b32);
|
||||
// sum = [c+b+g a+f k+j+e i] as i32
|
||||
|
||||
// Also sum their squares
|
||||
const __m128i slli_a_2 = _mm_madd_epi16(slli_a, slli_a);
|
||||
const __m128i swap_b_2 = _mm_madd_epi16(swap_b, swap_b);
|
||||
// slli_a_2 = [c2+b2 a2 k2+j2 i2]
|
||||
// swap_b_2 = [0 0 g2+f2 e2]
|
||||
const __m128i sum2 = _mm_hadd_epi32(slli_a_2, swap_b_2);
|
||||
// sum2 = [0 g2+f2+e2 c2+b2+a2 k2+j2+i2]
|
||||
*x2_sum_32 = _mm_add_epi32(*x2_sum_32, sum2);
|
||||
}
|
||||
|
||||
void av1_get_horver_correlation_full_sse4_1(const int16_t *diff, int stride,
|
||||
int width, int height, float *hcorr,
|
||||
float *vcorr) {
|
||||
// The following notation is used:
|
||||
// x - current pixel
|
||||
// y - right neighbour pixel
|
||||
// z - below neighbour pixel
|
||||
// w - down-right neighbour pixel
|
||||
int64_t xy_sum = 0, xz_sum = 0;
|
||||
int64_t x_sum = 0, x2_sum = 0;
|
||||
|
||||
// Process horizontal and vertical correlations through the body in 4x4
|
||||
// blocks. This excludes the final row and column and possibly one extra
|
||||
// column depending how 3 divides into width and height
|
||||
int32_t xy_tmp[4] = { 0 }, xz_tmp[4] = { 0 };
|
||||
int32_t x_tmp[4] = { 0 }, x2_tmp[4] = { 0 };
|
||||
__m128i xy_sum_32 = _mm_setzero_si128();
|
||||
__m128i xz_sum_32 = _mm_setzero_si128();
|
||||
__m128i x_sum_32 = _mm_setzero_si128();
|
||||
__m128i x2_sum_32 = _mm_setzero_si128();
|
||||
for (int i = 0; i <= height - 4; i += 3) {
|
||||
for (int j = 0; j <= width - 4; j += 3) {
|
||||
horver_correlation_4x4(&diff[i * stride + j], stride, &xy_sum_32,
|
||||
&xz_sum_32, &x_sum_32, &x2_sum_32);
|
||||
}
|
||||
xx_storeu_128(xy_tmp, xy_sum_32);
|
||||
xx_storeu_128(xz_tmp, xz_sum_32);
|
||||
xx_storeu_128(x_tmp, x_sum_32);
|
||||
xx_storeu_128(x2_tmp, x2_sum_32);
|
||||
xy_sum += (int64_t)xy_tmp[3] + xy_tmp[2] + xy_tmp[1];
|
||||
xz_sum += (int64_t)xz_tmp[3] + xz_tmp[2] + xz_tmp[0];
|
||||
x_sum += (int64_t)x_tmp[3] + x_tmp[2] + x_tmp[1] + x_tmp[0];
|
||||
x2_sum += (int64_t)x2_tmp[2] + x2_tmp[1] + x2_tmp[0];
|
||||
xy_sum_32 = _mm_setzero_si128();
|
||||
xz_sum_32 = _mm_setzero_si128();
|
||||
x_sum_32 = _mm_setzero_si128();
|
||||
x2_sum_32 = _mm_setzero_si128();
|
||||
}
|
||||
|
||||
// x_sum now covers every pixel except the final 1-2 rows and 1-2 cols
|
||||
int64_t x_finalrow = 0, x_finalcol = 0, x2_finalrow = 0, x2_finalcol = 0;
|
||||
|
||||
// Do we have 2 rows remaining or just the one? Note that width and height
|
||||
// are powers of 2, so each modulo 3 must be 1 or 2.
|
||||
if (height % 3 == 1) { // Just horiz corrs on the final row
|
||||
const int16_t x0 = diff[(height - 1) * stride];
|
||||
x_sum += x0;
|
||||
x_finalrow += x0;
|
||||
x2_sum += x0 * x0;
|
||||
x2_finalrow += x0 * x0;
|
||||
for (int j = 0; j < width - 1; ++j) {
|
||||
const int16_t x = diff[(height - 1) * stride + j];
|
||||
const int16_t y = diff[(height - 1) * stride + j + 1];
|
||||
xy_sum += x * y;
|
||||
x_sum += y;
|
||||
x2_sum += y * y;
|
||||
x_finalrow += y;
|
||||
x2_finalrow += y * y;
|
||||
}
|
||||
} else { // Two rows remaining to do
|
||||
const int16_t x0 = diff[(height - 2) * stride];
|
||||
const int16_t z0 = diff[(height - 1) * stride];
|
||||
x_sum += x0 + z0;
|
||||
x2_sum += x0 * x0 + z0 * z0;
|
||||
x_finalrow += z0;
|
||||
x2_finalrow += z0 * z0;
|
||||
for (int j = 0; j < width - 1; ++j) {
|
||||
const int16_t x = diff[(height - 2) * stride + j];
|
||||
const int16_t y = diff[(height - 2) * stride + j + 1];
|
||||
const int16_t z = diff[(height - 1) * stride + j];
|
||||
const int16_t w = diff[(height - 1) * stride + j + 1];
|
||||
|
||||
// Horizontal and vertical correlations for the penultimate row:
|
||||
xy_sum += x * y;
|
||||
xz_sum += x * z;
|
||||
|
||||
// Now just horizontal correlations for the final row:
|
||||
xy_sum += z * w;
|
||||
|
||||
x_sum += y + w;
|
||||
x2_sum += y * y + w * w;
|
||||
x_finalrow += w;
|
||||
x2_finalrow += w * w;
|
||||
}
|
||||
}
|
||||
|
||||
// Do we have 2 columns remaining or just the one?
|
||||
if (width % 3 == 1) { // Just vert corrs on the final col
|
||||
const int16_t x0 = diff[width - 1];
|
||||
x_sum += x0;
|
||||
x_finalcol += x0;
|
||||
x2_sum += x0 * x0;
|
||||
x2_finalcol += x0 * x0;
|
||||
for (int i = 0; i < height - 1; ++i) {
|
||||
const int16_t x = diff[i * stride + width - 1];
|
||||
const int16_t z = diff[(i + 1) * stride + width - 1];
|
||||
xz_sum += x * z;
|
||||
x_finalcol += z;
|
||||
x2_finalcol += z * z;
|
||||
// So the bottom-right elements don't get counted twice:
|
||||
if (i < height - (height % 3 == 1 ? 2 : 3)) {
|
||||
x_sum += z;
|
||||
x2_sum += z * z;
|
||||
}
|
||||
}
|
||||
} else { // Two cols remaining
|
||||
const int16_t x0 = diff[width - 2];
|
||||
const int16_t y0 = diff[width - 1];
|
||||
x_sum += x0 + y0;
|
||||
x2_sum += x0 * x0 + y0 * y0;
|
||||
x_finalcol += y0;
|
||||
x2_finalcol += y0 * y0;
|
||||
for (int i = 0; i < height - 1; ++i) {
|
||||
const int16_t x = diff[i * stride + width - 2];
|
||||
const int16_t y = diff[i * stride + width - 1];
|
||||
const int16_t z = diff[(i + 1) * stride + width - 2];
|
||||
const int16_t w = diff[(i + 1) * stride + width - 1];
|
||||
|
||||
// Horizontal and vertical correlations for the penultimate col:
|
||||
// Skip these on the last iteration of this loop if we also had two
|
||||
// rows remaining, otherwise the final horizontal and vertical correlation
|
||||
// get erroneously processed twice
|
||||
if (i < height - 2 || height % 3 == 1) {
|
||||
xy_sum += x * y;
|
||||
xz_sum += x * z;
|
||||
}
|
||||
|
||||
x_finalcol += w;
|
||||
x2_finalcol += w * w;
|
||||
// So the bottom-right elements don't get counted twice:
|
||||
if (i < height - (height % 3 == 1 ? 2 : 3)) {
|
||||
x_sum += z + w;
|
||||
x2_sum += z * z + w * w;
|
||||
}
|
||||
|
||||
// Now just vertical correlations for the final column:
|
||||
xz_sum += y * w;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the simple sums and squared-sums
|
||||
int64_t x_firstrow = 0, x_firstcol = 0;
|
||||
int64_t x2_firstrow = 0, x2_firstcol = 0;
|
||||
|
||||
for (int j = 0; j < width; ++j) {
|
||||
x_firstrow += diff[j];
|
||||
x2_firstrow += diff[j] * diff[j];
|
||||
}
|
||||
for (int i = 0; i < height; ++i) {
|
||||
x_firstcol += diff[i * stride];
|
||||
x2_firstcol += diff[i * stride] * diff[i * stride];
|
||||
}
|
||||
|
||||
int64_t xhor_sum = x_sum - x_finalcol;
|
||||
int64_t xver_sum = x_sum - x_finalrow;
|
||||
int64_t y_sum = x_sum - x_firstcol;
|
||||
int64_t z_sum = x_sum - x_firstrow;
|
||||
int64_t x2hor_sum = x2_sum - x2_finalcol;
|
||||
int64_t x2ver_sum = x2_sum - x2_finalrow;
|
||||
int64_t y2_sum = x2_sum - x2_firstcol;
|
||||
int64_t z2_sum = x2_sum - x2_firstrow;
|
||||
|
||||
aom_clear_system_state();
|
||||
|
||||
const float num_hor = (float)(height * (width - 1));
|
||||
const float num_ver = (float)((height - 1) * width);
|
||||
|
||||
const float xhor_var_n = x2hor_sum - (xhor_sum * xhor_sum) / num_hor;
|
||||
const float xver_var_n = x2ver_sum - (xver_sum * xver_sum) / num_ver;
|
||||
|
||||
const float y_var_n = y2_sum - (y_sum * y_sum) / num_hor;
|
||||
const float z_var_n = z2_sum - (z_sum * z_sum) / num_ver;
|
||||
|
||||
const float xy_var_n = xy_sum - (xhor_sum * y_sum) / num_hor;
|
||||
const float xz_var_n = xz_sum - (xver_sum * z_sum) / num_ver;
|
||||
|
||||
if (xhor_var_n > 0 && y_var_n > 0) {
|
||||
*hcorr = xy_var_n / sqrtf(xhor_var_n * y_var_n);
|
||||
*hcorr = *hcorr < 0 ? 0 : *hcorr;
|
||||
} else {
|
||||
*hcorr = 1.0;
|
||||
}
|
||||
if (xver_var_n > 0 && z_var_n > 0) {
|
||||
*vcorr = xz_var_n / sqrtf(xver_var_n * z_var_n);
|
||||
*vcorr = *vcorr < 0 ? 0 : *vcorr;
|
||||
} else {
|
||||
*vcorr = 1.0;
|
||||
}
|
||||
}
|
||||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
SECTION .text
|
||||
|
||||
; TODO(yunqing) The following optimization is not used since the c code changes.
|
||||
; void av1_temporal_filter_apply_sse2 | arg
|
||||
; (unsigned char *frame1, | 0
|
||||
; unsigned int stride, | 1
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue