270 lines
9.6 KiB
C
270 lines
9.6 KiB
C
/*
|
|
* Copyright (c) 2020, 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_MODEL_RD_H_
|
|
#define AOM_AV1_ENCODER_MODEL_RD_H_
|
|
|
|
#include "aom/aom_integer.h"
|
|
#include "av1/encoder/block.h"
|
|
#include "av1/encoder/encoder.h"
|
|
#include "av1/encoder/pustats.h"
|
|
#include "av1/encoder/rdopt_utils.h"
|
|
#include "config/aom_dsp_rtcd.h"
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
// 0: Legacy model
|
|
// 1: Curve fit model
|
|
// 2: Surface fit model
|
|
// 3: DNN regression model
|
|
// 4: Full rd model
|
|
#define MODELRD_TYPE_INTERP_FILTER 1
|
|
#define MODELRD_TYPE_TX_SEARCH_PRUNE 1
|
|
#define MODELRD_TYPE_MASKED_COMPOUND 1
|
|
#define MODELRD_TYPE_INTERINTRA 1
|
|
#define MODELRD_TYPE_INTRA 1
|
|
#define MODELRD_TYPE_MOTION_MODE_RD 1
|
|
|
|
typedef void (*model_rd_for_sb_type)(
|
|
const AV1_COMP *const cpi, BLOCK_SIZE bsize, MACROBLOCK *x, MACROBLOCKD *xd,
|
|
int plane_from, int plane_to, int *out_rate_sum, int64_t *out_dist_sum,
|
|
uint8_t *skip_txfm_sb, int64_t *skip_sse_sb, int *plane_rate,
|
|
int64_t *plane_sse, int64_t *plane_dist);
|
|
typedef void (*model_rd_from_sse_type)(const AV1_COMP *const cpi,
|
|
const MACROBLOCK *const x,
|
|
BLOCK_SIZE plane_bsize, int plane,
|
|
int64_t sse, int num_samples, int *rate,
|
|
int64_t *dist);
|
|
|
|
static int64_t calculate_sse(MACROBLOCKD *const xd,
|
|
const struct macroblock_plane *p,
|
|
struct macroblockd_plane *pd, const int bw,
|
|
const int bh) {
|
|
int64_t sse = 0;
|
|
const int shift = xd->bd - 8;
|
|
#if CONFIG_AV1_HIGHBITDEPTH
|
|
if (is_cur_buf_hbd(xd)) {
|
|
sse = aom_highbd_sse(p->src.buf, p->src.stride, pd->dst.buf, pd->dst.stride,
|
|
bw, bh);
|
|
} else {
|
|
sse =
|
|
aom_sse(p->src.buf, p->src.stride, pd->dst.buf, pd->dst.stride, bw, bh);
|
|
}
|
|
#else
|
|
sse = aom_sse(p->src.buf, p->src.stride, pd->dst.buf, pd->dst.stride, bw, bh);
|
|
#endif
|
|
sse = ROUND_POWER_OF_TWO(sse, shift * 2);
|
|
return sse;
|
|
}
|
|
|
|
static AOM_INLINE int64_t compute_sse_plane(MACROBLOCK *x, MACROBLOCKD *xd,
|
|
int plane, const BLOCK_SIZE bsize) {
|
|
struct macroblockd_plane *const pd = &xd->plane[plane];
|
|
const BLOCK_SIZE plane_bsize =
|
|
get_plane_block_size(bsize, pd->subsampling_x, pd->subsampling_y);
|
|
int bw, bh;
|
|
const struct macroblock_plane *const p = &x->plane[plane];
|
|
get_txb_dimensions(xd, plane, plane_bsize, 0, 0, plane_bsize, NULL, NULL, &bw,
|
|
&bh);
|
|
|
|
int64_t sse = calculate_sse(xd, p, pd, bw, bh);
|
|
|
|
return sse;
|
|
}
|
|
|
|
static AOM_INLINE void model_rd_from_sse(const AV1_COMP *const cpi,
|
|
const MACROBLOCK *const x,
|
|
BLOCK_SIZE plane_bsize, int plane,
|
|
int64_t sse, int num_samples,
|
|
int *rate, int64_t *dist) {
|
|
(void)num_samples;
|
|
const MACROBLOCKD *const xd = &x->e_mbd;
|
|
const struct macroblock_plane *const p = &x->plane[plane];
|
|
const int dequant_shift = (is_cur_buf_hbd(xd)) ? xd->bd - 5 : 3;
|
|
|
|
// Fast approximate the modelling function.
|
|
if (cpi->sf.rd_sf.simple_model_rd_from_var) {
|
|
const int64_t square_error = sse;
|
|
int quantizer = p->dequant_QTX[1] >> dequant_shift;
|
|
if (quantizer < 120)
|
|
*rate = (int)AOMMIN(
|
|
(square_error * (280 - quantizer)) >> (16 - AV1_PROB_COST_SHIFT),
|
|
INT_MAX);
|
|
else
|
|
*rate = 0;
|
|
assert(*rate >= 0);
|
|
*dist = (square_error * quantizer) >> 8;
|
|
} else {
|
|
av1_model_rd_from_var_lapndz(sse, num_pels_log2_lookup[plane_bsize],
|
|
p->dequant_QTX[1] >> dequant_shift, rate,
|
|
dist);
|
|
}
|
|
*dist <<= 4;
|
|
}
|
|
|
|
// Fits a curve for rate and distortion using as feature:
|
|
// log2(sse_norm/qstep^2)
|
|
static AOM_INLINE void model_rd_with_curvfit(const AV1_COMP *const cpi,
|
|
const MACROBLOCK *const x,
|
|
BLOCK_SIZE plane_bsize, int plane,
|
|
int64_t sse, int num_samples,
|
|
int *rate, int64_t *dist) {
|
|
(void)cpi;
|
|
(void)plane_bsize;
|
|
const MACROBLOCKD *const xd = &x->e_mbd;
|
|
const struct macroblock_plane *const p = &x->plane[plane];
|
|
const int dequant_shift = (is_cur_buf_hbd(xd)) ? xd->bd - 5 : 3;
|
|
const int qstep = AOMMAX(p->dequant_QTX[1] >> dequant_shift, 1);
|
|
|
|
if (sse == 0) {
|
|
if (rate) *rate = 0;
|
|
if (dist) *dist = 0;
|
|
return;
|
|
}
|
|
const double sse_norm = (double)sse / num_samples;
|
|
const double qstepsqr = (double)qstep * qstep;
|
|
const double xqr = log2(sse_norm / qstepsqr);
|
|
double rate_f, dist_by_sse_norm_f;
|
|
av1_model_rd_curvfit(plane_bsize, sse_norm, xqr, &rate_f,
|
|
&dist_by_sse_norm_f);
|
|
|
|
const double dist_f = dist_by_sse_norm_f * sse_norm;
|
|
int rate_i = (int)(AOMMAX(0.0, rate_f * num_samples) + 0.5);
|
|
int64_t dist_i = (int64_t)(AOMMAX(0.0, dist_f * num_samples) + 0.5);
|
|
|
|
// Check if skip is better
|
|
if (rate_i == 0) {
|
|
dist_i = sse << 4;
|
|
} else if (RDCOST(x->rdmult, rate_i, dist_i) >=
|
|
RDCOST(x->rdmult, 0, sse << 4)) {
|
|
rate_i = 0;
|
|
dist_i = sse << 4;
|
|
}
|
|
|
|
if (rate) *rate = rate_i;
|
|
if (dist) *dist = dist_i;
|
|
}
|
|
|
|
static AOM_INLINE void model_rd_for_sb(
|
|
const AV1_COMP *const cpi, BLOCK_SIZE bsize, MACROBLOCK *x, MACROBLOCKD *xd,
|
|
int plane_from, int plane_to, int *out_rate_sum, int64_t *out_dist_sum,
|
|
uint8_t *skip_txfm_sb, int64_t *skip_sse_sb, int *plane_rate,
|
|
int64_t *plane_sse, int64_t *plane_dist) {
|
|
// Note our transform coeffs are 8 times an orthogonal transform.
|
|
// Hence quantizer step is also 8 times. To get effective quantizer
|
|
// we need to divide by 8 before sending to modeling function.
|
|
int plane;
|
|
const int ref = xd->mi[0]->ref_frame[0];
|
|
|
|
int64_t rate_sum = 0;
|
|
int64_t dist_sum = 0;
|
|
int64_t total_sse = 0;
|
|
|
|
assert(bsize < BLOCK_SIZES_ALL);
|
|
|
|
for (plane = plane_from; plane <= plane_to; ++plane) {
|
|
if (plane && !xd->is_chroma_ref) break;
|
|
struct macroblock_plane *const p = &x->plane[plane];
|
|
struct macroblockd_plane *const pd = &xd->plane[plane];
|
|
const BLOCK_SIZE plane_bsize =
|
|
get_plane_block_size(bsize, pd->subsampling_x, pd->subsampling_y);
|
|
assert(plane_bsize < BLOCK_SIZES_ALL);
|
|
const int bw = block_size_wide[plane_bsize];
|
|
const int bh = block_size_high[plane_bsize];
|
|
int64_t sse;
|
|
int rate;
|
|
int64_t dist;
|
|
|
|
sse = calculate_sse(xd, p, pd, bw, bh);
|
|
|
|
model_rd_from_sse(cpi, x, plane_bsize, plane, sse, bw * bh, &rate, &dist);
|
|
|
|
if (plane == 0) x->pred_sse[ref] = (unsigned int)AOMMIN(sse, UINT_MAX);
|
|
|
|
total_sse += sse;
|
|
rate_sum += rate;
|
|
dist_sum += dist;
|
|
if (plane_rate) plane_rate[plane] = rate;
|
|
if (plane_sse) plane_sse[plane] = sse;
|
|
if (plane_dist) plane_dist[plane] = dist;
|
|
assert(rate_sum >= 0);
|
|
}
|
|
|
|
if (skip_txfm_sb) *skip_txfm_sb = total_sse == 0;
|
|
if (skip_sse_sb) *skip_sse_sb = total_sse << 4;
|
|
rate_sum = AOMMIN(rate_sum, INT_MAX);
|
|
*out_rate_sum = (int)rate_sum;
|
|
*out_dist_sum = dist_sum;
|
|
}
|
|
|
|
static AOM_INLINE void model_rd_for_sb_with_curvfit(
|
|
const AV1_COMP *const cpi, BLOCK_SIZE bsize, MACROBLOCK *x, MACROBLOCKD *xd,
|
|
int plane_from, int plane_to, int *out_rate_sum, int64_t *out_dist_sum,
|
|
uint8_t *skip_txfm_sb, int64_t *skip_sse_sb, int *plane_rate,
|
|
int64_t *plane_sse, int64_t *plane_dist) {
|
|
// Note our transform coeffs are 8 times an orthogonal transform.
|
|
// Hence quantizer step is also 8 times. To get effective quantizer
|
|
// we need to divide by 8 before sending to modeling function.
|
|
const int ref = xd->mi[0]->ref_frame[0];
|
|
|
|
int64_t rate_sum = 0;
|
|
int64_t dist_sum = 0;
|
|
int64_t total_sse = 0;
|
|
|
|
for (int plane = plane_from; plane <= plane_to; ++plane) {
|
|
if (plane && !xd->is_chroma_ref) break;
|
|
struct macroblockd_plane *const pd = &xd->plane[plane];
|
|
const BLOCK_SIZE plane_bsize =
|
|
get_plane_block_size(bsize, pd->subsampling_x, pd->subsampling_y);
|
|
int64_t dist, sse;
|
|
int rate;
|
|
int bw, bh;
|
|
const struct macroblock_plane *const p = &x->plane[plane];
|
|
get_txb_dimensions(xd, plane, plane_bsize, 0, 0, plane_bsize, NULL, NULL,
|
|
&bw, &bh);
|
|
|
|
sse = calculate_sse(xd, p, pd, bw, bh);
|
|
model_rd_with_curvfit(cpi, x, plane_bsize, plane, sse, bw * bh, &rate,
|
|
&dist);
|
|
|
|
if (plane == 0) x->pred_sse[ref] = (unsigned int)AOMMIN(sse, UINT_MAX);
|
|
|
|
total_sse += sse;
|
|
rate_sum += rate;
|
|
dist_sum += dist;
|
|
|
|
if (plane_rate) plane_rate[plane] = rate;
|
|
if (plane_sse) plane_sse[plane] = sse;
|
|
if (plane_dist) plane_dist[plane] = dist;
|
|
}
|
|
|
|
if (skip_txfm_sb) *skip_txfm_sb = rate_sum == 0;
|
|
if (skip_sse_sb) *skip_sse_sb = total_sse << 4;
|
|
*out_rate_sum = (int)rate_sum;
|
|
*out_dist_sum = dist_sum;
|
|
}
|
|
|
|
enum { MODELRD_LEGACY, MODELRD_CURVFIT, MODELRD_TYPES } UENUM1BYTE(ModelRdType);
|
|
|
|
static const model_rd_for_sb_type model_rd_sb_fn[MODELRD_TYPES] = {
|
|
model_rd_for_sb, model_rd_for_sb_with_curvfit
|
|
};
|
|
|
|
static const model_rd_from_sse_type model_rd_sse_fn[MODELRD_TYPES] = {
|
|
model_rd_from_sse, model_rd_with_curvfit
|
|
};
|
|
|
|
#ifdef __cplusplus
|
|
} // extern "C"
|
|
#endif
|
|
#endif // AOM_AV1_ENCODER_MODEL_RD_H_
|