
Rename MI_BLOCK_SIZE.* -> MAX_MIB_SIZE.* (MIB is for MI Block). Rename MI_MASK.* -> MAX_MIB_MASK.* There are no functional changes. This is in preparation for coding the superblock size at the frame level, which will require some of these constants to become variables. The new names better reflect future semantics, and hence make the code clearer. Change-Id: Iee08d97554cf4cc16a5dc166a3ffd1ab91529992
821 lines
28 KiB
C
821 lines
28 KiB
C
/*
|
|
* Copyright (c) 2010 The WebM project authors. All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license
|
|
* that can be found in the LICENSE file in the root of the source
|
|
* tree. An additional intellectual property rights grant can be found
|
|
* in the file PATENTS. All contributing project authors may
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
*/
|
|
|
|
|
|
#include "./vp10_rtcd.h"
|
|
#include "./vpx_config.h"
|
|
#include "./vpx_dsp_rtcd.h"
|
|
|
|
#include "vpx_dsp/quantize.h"
|
|
#include "vpx_mem/vpx_mem.h"
|
|
#include "vpx_ports/mem.h"
|
|
|
|
#include "vp10/common/idct.h"
|
|
#include "vp10/common/reconinter.h"
|
|
#include "vp10/common/reconintra.h"
|
|
#include "vp10/common/scan.h"
|
|
|
|
#include "vp10/encoder/encodemb.h"
|
|
#include "vp10/encoder/hybrid_fwd_txfm.h"
|
|
#include "vp10/encoder/quantize.h"
|
|
#include "vp10/encoder/rd.h"
|
|
#include "vp10/encoder/tokenize.h"
|
|
|
|
struct optimize_ctx {
|
|
ENTROPY_CONTEXT ta[MAX_MB_PLANE][2 * MAX_MIB_SIZE];
|
|
ENTROPY_CONTEXT tl[MAX_MB_PLANE][2 * MAX_MIB_SIZE];
|
|
};
|
|
|
|
void vp10_subtract_plane(MACROBLOCK *x, BLOCK_SIZE bsize, int plane) {
|
|
struct macroblock_plane *const p = &x->plane[plane];
|
|
const struct macroblockd_plane *const pd = &x->e_mbd.plane[plane];
|
|
const BLOCK_SIZE plane_bsize = get_plane_block_size(bsize, pd);
|
|
const int bw = 4 * num_4x4_blocks_wide_lookup[plane_bsize];
|
|
const int bh = 4 * num_4x4_blocks_high_lookup[plane_bsize];
|
|
|
|
#if CONFIG_VP9_HIGHBITDEPTH
|
|
if (x->e_mbd.cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) {
|
|
vpx_highbd_subtract_block(bh, bw, p->src_diff, bw, p->src.buf,
|
|
p->src.stride, pd->dst.buf, pd->dst.stride,
|
|
x->e_mbd.bd);
|
|
return;
|
|
}
|
|
#endif // CONFIG_VP9_HIGHBITDEPTH
|
|
vpx_subtract_block(bh, bw, p->src_diff, bw, p->src.buf, p->src.stride,
|
|
pd->dst.buf, pd->dst.stride);
|
|
}
|
|
|
|
#define RDTRUNC(RM, DM, R, D) \
|
|
(((1 << (VP9_PROB_COST_SHIFT - 1)) + (R) * (RM)) & \
|
|
((1 << VP9_PROB_COST_SHIFT) - 1))
|
|
|
|
typedef struct vp10_token_state {
|
|
int rate;
|
|
int error;
|
|
int next;
|
|
int16_t token;
|
|
short qc;
|
|
} vp10_token_state;
|
|
|
|
// TODO(jimbankoski): experiment to find optimal RD numbers.
|
|
static const int plane_rd_mult[PLANE_TYPES] = { 4, 2 };
|
|
|
|
#define UPDATE_RD_COST()\
|
|
{\
|
|
rd_cost0 = RDCOST(rdmult, rddiv, rate0, error0);\
|
|
rd_cost1 = RDCOST(rdmult, rddiv, rate1, error1);\
|
|
if (rd_cost0 == rd_cost1) {\
|
|
rd_cost0 = RDTRUNC(rdmult, rddiv, rate0, error0);\
|
|
rd_cost1 = RDTRUNC(rdmult, rddiv, rate1, error1);\
|
|
}\
|
|
}
|
|
|
|
// This function is a place holder for now but may ultimately need
|
|
// to scan previous tokens to work out the correct context.
|
|
static int trellis_get_coeff_context(const int16_t *scan,
|
|
const int16_t *nb,
|
|
int idx, int token,
|
|
uint8_t *token_cache) {
|
|
int bak = token_cache[scan[idx]], pt;
|
|
token_cache[scan[idx]] = vp10_pt_energy_class[token];
|
|
pt = get_coef_context(nb, token_cache, idx + 1);
|
|
token_cache[scan[idx]] = bak;
|
|
return pt;
|
|
}
|
|
|
|
static int optimize_b(MACROBLOCK *mb, int plane, int block,
|
|
TX_SIZE tx_size, int ctx) {
|
|
MACROBLOCKD *const xd = &mb->e_mbd;
|
|
struct macroblock_plane *const p = &mb->plane[plane];
|
|
struct macroblockd_plane *const pd = &xd->plane[plane];
|
|
const int ref = is_inter_block(&xd->mi[0]->mbmi);
|
|
vp10_token_state tokens[MAX_TX_SQUARE+1][2];
|
|
unsigned best_index[MAX_TX_SQUARE+1][2];
|
|
uint8_t token_cache[MAX_TX_SQUARE];
|
|
const tran_low_t *const coeff = BLOCK_OFFSET(mb->plane[plane].coeff, block);
|
|
tran_low_t *const qcoeff = BLOCK_OFFSET(p->qcoeff, block);
|
|
tran_low_t *const dqcoeff = BLOCK_OFFSET(pd->dqcoeff, block);
|
|
const int eob = p->eobs[block];
|
|
const PLANE_TYPE type = pd->plane_type;
|
|
const int default_eob = 16 << (tx_size << 1);
|
|
int mul;
|
|
const int16_t *dequant_ptr = pd->dequant;
|
|
const uint8_t *const band_translate = get_band_translate(tx_size);
|
|
TX_TYPE tx_type = get_tx_type(type, xd, block, tx_size);
|
|
const scan_order *const so =
|
|
get_scan(tx_size, tx_type, is_inter_block(&xd->mi[0]->mbmi));
|
|
const int16_t *const scan = so->scan;
|
|
const int16_t *const nb = so->neighbors;
|
|
int next = eob, sz = 0;
|
|
int64_t rdmult = mb->rdmult * plane_rd_mult[type], rddiv = mb->rddiv;
|
|
int64_t rd_cost0, rd_cost1;
|
|
int rate0, rate1, error0, error1;
|
|
int16_t t0, t1;
|
|
EXTRABIT e0;
|
|
int best, band, pt, i, final_eob;
|
|
#if CONFIG_VP9_HIGHBITDEPTH
|
|
const int *cat6_high_cost = vp10_get_high_cost_table(xd->bd);
|
|
#else
|
|
const int *cat6_high_cost = vp10_get_high_cost_table(8);
|
|
#endif
|
|
|
|
assert((!type && !plane) || (type && plane));
|
|
assert(eob <= default_eob);
|
|
|
|
#if CONFIG_VP9_HIGHBITDEPTH
|
|
if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH && xd->bd == BITDEPTH_10) {
|
|
mul = 1;
|
|
} else {
|
|
mul = 1 + (tx_size == TX_32X32);
|
|
}
|
|
#else
|
|
mul = 1 + (tx_size == TX_32X32);
|
|
#endif
|
|
|
|
/* Now set up a Viterbi trellis to evaluate alternative roundings. */
|
|
if (!ref)
|
|
rdmult = (rdmult * 9) >> 4;
|
|
|
|
/* Initialize the sentinel node of the trellis. */
|
|
tokens[eob][0].rate = 0;
|
|
tokens[eob][0].error = 0;
|
|
tokens[eob][0].next = default_eob;
|
|
tokens[eob][0].token = EOB_TOKEN;
|
|
tokens[eob][0].qc = 0;
|
|
tokens[eob][1] = tokens[eob][0];
|
|
|
|
for (i = 0; i < eob; i++)
|
|
token_cache[scan[i]] =
|
|
vp10_pt_energy_class[vp10_get_token(qcoeff[scan[i]])];
|
|
|
|
for (i = eob; i-- > 0;) {
|
|
int base_bits, d2, dx;
|
|
const int rc = scan[i];
|
|
int x = qcoeff[rc];
|
|
/* Only add a trellis state for non-zero coefficients. */
|
|
if (x) {
|
|
int shortcut = 0;
|
|
error0 = tokens[next][0].error;
|
|
error1 = tokens[next][1].error;
|
|
/* Evaluate the first possibility for this state. */
|
|
rate0 = tokens[next][0].rate;
|
|
rate1 = tokens[next][1].rate;
|
|
vp10_get_token_extra(x, &t0, &e0);
|
|
/* Consider both possible successor states. */
|
|
if (next < default_eob) {
|
|
band = band_translate[i + 1];
|
|
pt = trellis_get_coeff_context(scan, nb, i, t0, token_cache);
|
|
rate0 += mb->token_costs[tx_size][type][ref][band][0][pt]
|
|
[tokens[next][0].token];
|
|
rate1 += mb->token_costs[tx_size][type][ref][band][0][pt]
|
|
[tokens[next][1].token];
|
|
}
|
|
UPDATE_RD_COST();
|
|
/* And pick the best. */
|
|
best = rd_cost1 < rd_cost0;
|
|
base_bits = vp10_get_cost(t0, e0, cat6_high_cost);
|
|
dx = mul * (dqcoeff[rc] - coeff[rc]);
|
|
#if CONFIG_VP9_HIGHBITDEPTH
|
|
if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) {
|
|
dx >>= xd->bd - 8;
|
|
}
|
|
#endif // CONFIG_VP9_HIGHBITDEPTH
|
|
d2 = dx * dx;
|
|
tokens[i][0].rate = base_bits + (best ? rate1 : rate0);
|
|
tokens[i][0].error = d2 + (best ? error1 : error0);
|
|
tokens[i][0].next = next;
|
|
tokens[i][0].token = t0;
|
|
tokens[i][0].qc = x;
|
|
best_index[i][0] = best;
|
|
|
|
/* Evaluate the second possibility for this state. */
|
|
rate0 = tokens[next][0].rate;
|
|
rate1 = tokens[next][1].rate;
|
|
|
|
if ((abs(x) * dequant_ptr[rc != 0] > abs(coeff[rc]) * mul) &&
|
|
(abs(x) * dequant_ptr[rc != 0] < abs(coeff[rc]) * mul +
|
|
dequant_ptr[rc != 0]))
|
|
shortcut = 1;
|
|
else
|
|
shortcut = 0;
|
|
|
|
if (shortcut) {
|
|
sz = -(x < 0);
|
|
x -= 2 * sz + 1;
|
|
}
|
|
|
|
/* Consider both possible successor states. */
|
|
if (!x) {
|
|
/* If we reduced this coefficient to zero, check to see if
|
|
* we need to move the EOB back here.
|
|
*/
|
|
t0 = tokens[next][0].token == EOB_TOKEN ? EOB_TOKEN : ZERO_TOKEN;
|
|
t1 = tokens[next][1].token == EOB_TOKEN ? EOB_TOKEN : ZERO_TOKEN;
|
|
e0 = 0;
|
|
} else {
|
|
vp10_get_token_extra(x, &t0, &e0);
|
|
t1 = t0;
|
|
}
|
|
if (next < default_eob) {
|
|
band = band_translate[i + 1];
|
|
if (t0 != EOB_TOKEN) {
|
|
pt = trellis_get_coeff_context(scan, nb, i, t0, token_cache);
|
|
rate0 += mb->token_costs[tx_size][type][ref][band][!x][pt]
|
|
[tokens[next][0].token];
|
|
}
|
|
if (t1 != EOB_TOKEN) {
|
|
pt = trellis_get_coeff_context(scan, nb, i, t1, token_cache);
|
|
rate1 += mb->token_costs[tx_size][type][ref][band][!x][pt]
|
|
[tokens[next][1].token];
|
|
}
|
|
}
|
|
|
|
UPDATE_RD_COST();
|
|
/* And pick the best. */
|
|
best = rd_cost1 < rd_cost0;
|
|
base_bits = vp10_get_cost(t0, e0, cat6_high_cost);
|
|
|
|
if (shortcut) {
|
|
#if CONFIG_VP9_HIGHBITDEPTH
|
|
if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) {
|
|
dx -= ((dequant_ptr[rc != 0] >> (xd->bd - 8)) + sz) ^ sz;
|
|
} else {
|
|
dx -= (dequant_ptr[rc != 0] + sz) ^ sz;
|
|
}
|
|
#else
|
|
dx -= (dequant_ptr[rc != 0] + sz) ^ sz;
|
|
#endif // CONFIG_VP9_HIGHBITDEPTH
|
|
d2 = dx * dx;
|
|
}
|
|
tokens[i][1].rate = base_bits + (best ? rate1 : rate0);
|
|
tokens[i][1].error = d2 + (best ? error1 : error0);
|
|
tokens[i][1].next = next;
|
|
tokens[i][1].token = best ? t1 : t0;
|
|
tokens[i][1].qc = x;
|
|
best_index[i][1] = best;
|
|
/* Finally, make this the new head of the trellis. */
|
|
next = i;
|
|
} else {
|
|
/* There's no choice to make for a zero coefficient, so we don't
|
|
* add a new trellis node, but we do need to update the costs.
|
|
*/
|
|
band = band_translate[i + 1];
|
|
t0 = tokens[next][0].token;
|
|
t1 = tokens[next][1].token;
|
|
/* Update the cost of each path if we're past the EOB token. */
|
|
if (t0 != EOB_TOKEN) {
|
|
tokens[next][0].rate +=
|
|
mb->token_costs[tx_size][type][ref][band][1][0][t0];
|
|
tokens[next][0].token = ZERO_TOKEN;
|
|
}
|
|
if (t1 != EOB_TOKEN) {
|
|
tokens[next][1].rate +=
|
|
mb->token_costs[tx_size][type][ref][band][1][0][t1];
|
|
tokens[next][1].token = ZERO_TOKEN;
|
|
}
|
|
best_index[i][0] = best_index[i][1] = 0;
|
|
/* Don't update next, because we didn't add a new node. */
|
|
}
|
|
}
|
|
|
|
/* Now pick the best path through the whole trellis. */
|
|
band = band_translate[i + 1];
|
|
rate0 = tokens[next][0].rate;
|
|
rate1 = tokens[next][1].rate;
|
|
error0 = tokens[next][0].error;
|
|
error1 = tokens[next][1].error;
|
|
t0 = tokens[next][0].token;
|
|
t1 = tokens[next][1].token;
|
|
rate0 += mb->token_costs[tx_size][type][ref][band][0][ctx][t0];
|
|
rate1 += mb->token_costs[tx_size][type][ref][band][0][ctx][t1];
|
|
UPDATE_RD_COST();
|
|
best = rd_cost1 < rd_cost0;
|
|
final_eob = -1;
|
|
memset(qcoeff, 0, sizeof(*qcoeff) * (16 << (tx_size * 2)));
|
|
memset(dqcoeff, 0, sizeof(*dqcoeff) * (16 << (tx_size * 2)));
|
|
for (i = next; i < eob; i = next) {
|
|
const int x = tokens[i][best].qc;
|
|
const int rc = scan[i];
|
|
if (x) {
|
|
final_eob = i;
|
|
}
|
|
|
|
qcoeff[rc] = x;
|
|
dqcoeff[rc] = (x * dequant_ptr[rc != 0]) / mul;
|
|
|
|
next = tokens[i][best].next;
|
|
best = best_index[i][best];
|
|
}
|
|
final_eob++;
|
|
|
|
mb->plane[plane].eobs[block] = final_eob;
|
|
assert(final_eob <= default_eob);
|
|
return final_eob;
|
|
}
|
|
|
|
#if CONFIG_VP9_HIGHBITDEPTH
|
|
typedef enum QUANT_FUNC {
|
|
QUANT_FUNC_LOWBD = 0,
|
|
QUANT_FUNC_LOWBD_32 = 1,
|
|
QUANT_FUNC_HIGHBD = 2,
|
|
QUANT_FUNC_HIGHBD_32 = 3,
|
|
QUANT_FUNC_LAST = 4
|
|
} QUANT_FUNC;
|
|
|
|
static VP10_QUANT_FACADE
|
|
quant_func_list[VP10_XFORM_QUANT_LAST][QUANT_FUNC_LAST] = {
|
|
{vp10_quantize_fp_facade, vp10_quantize_fp_32x32_facade,
|
|
vp10_highbd_quantize_fp_facade, vp10_highbd_quantize_fp_32x32_facade},
|
|
{vp10_quantize_b_facade, vp10_quantize_b_32x32_facade,
|
|
vp10_highbd_quantize_b_facade, vp10_highbd_quantize_b_32x32_facade},
|
|
{vp10_quantize_dc_facade, vp10_quantize_dc_32x32_facade,
|
|
vp10_highbd_quantize_dc_facade, vp10_highbd_quantize_dc_32x32_facade},
|
|
{NULL, NULL, NULL, NULL}};
|
|
|
|
#else
|
|
typedef enum QUANT_FUNC {
|
|
QUANT_FUNC_LOWBD = 0,
|
|
QUANT_FUNC_LOWBD_32 = 1,
|
|
QUANT_FUNC_LAST = 2
|
|
} QUANT_FUNC;
|
|
|
|
static VP10_QUANT_FACADE
|
|
quant_func_list[VP10_XFORM_QUANT_LAST][QUANT_FUNC_LAST] = {
|
|
{vp10_quantize_fp_facade, vp10_quantize_fp_32x32_facade},
|
|
{vp10_quantize_b_facade, vp10_quantize_b_32x32_facade},
|
|
{vp10_quantize_dc_facade, vp10_quantize_dc_32x32_facade},
|
|
{NULL, NULL}};
|
|
#endif
|
|
|
|
static FWD_TXFM_OPT fwd_txfm_opt_list[VP10_XFORM_QUANT_LAST] = {
|
|
FWD_TXFM_OPT_NORMAL, FWD_TXFM_OPT_NORMAL, FWD_TXFM_OPT_DC,
|
|
FWD_TXFM_OPT_NORMAL};
|
|
|
|
void vp10_xform_quant(MACROBLOCK *x, int plane, int block, int blk_row,
|
|
int blk_col, BLOCK_SIZE plane_bsize, TX_SIZE tx_size,
|
|
VP10_XFORM_QUANT xform_quant_idx) {
|
|
MACROBLOCKD *const xd = &x->e_mbd;
|
|
const struct macroblock_plane *const p = &x->plane[plane];
|
|
const struct macroblockd_plane *const pd = &xd->plane[plane];
|
|
PLANE_TYPE plane_type = (plane == 0) ? PLANE_TYPE_Y : PLANE_TYPE_UV;
|
|
TX_TYPE tx_type = get_tx_type(plane_type, xd, block, tx_size);
|
|
const scan_order *const scan_order =
|
|
get_scan(tx_size, tx_type, is_inter_block(&xd->mi[0]->mbmi));
|
|
tran_low_t *const coeff = BLOCK_OFFSET(p->coeff, block);
|
|
tran_low_t *const qcoeff = BLOCK_OFFSET(p->qcoeff, block);
|
|
tran_low_t *const dqcoeff = BLOCK_OFFSET(pd->dqcoeff, block);
|
|
uint16_t *const eob = &p->eobs[block];
|
|
const int diff_stride = 4 * num_4x4_blocks_wide_lookup[plane_bsize];
|
|
const int16_t *src_diff;
|
|
const int tx1d_size = get_tx1d_size(tx_size);
|
|
const int tx2d_size = tx1d_size * tx1d_size;
|
|
|
|
FWD_TXFM_PARAM fwd_txfm_param;
|
|
fwd_txfm_param.tx_type = get_tx_type(plane_type, xd, block, tx_size);
|
|
fwd_txfm_param.tx_size = tx_size;
|
|
fwd_txfm_param.fwd_txfm_opt = fwd_txfm_opt_list[xform_quant_idx];
|
|
fwd_txfm_param.rd_transform = x->use_lp32x32fdct;
|
|
fwd_txfm_param.lossless = xd->lossless[xd->mi[0]->mbmi.segment_id];
|
|
|
|
src_diff = &p->src_diff[4 * (blk_row * diff_stride + blk_col)];
|
|
|
|
#if CONFIG_VP9_HIGHBITDEPTH
|
|
fwd_txfm_param.bd = xd->bd;
|
|
if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) {
|
|
highbd_fwd_txfm(src_diff, coeff, diff_stride, &fwd_txfm_param);
|
|
if (xform_quant_idx != VP10_XFORM_QUANT_SKIP_QUANT) {
|
|
if (x->skip_block) {
|
|
vp10_quantize_skip(tx2d_size, qcoeff, dqcoeff, eob);
|
|
} else {
|
|
if (tx_size == TX_32X32 && xd->bd != 10)
|
|
quant_func_list[xform_quant_idx][QUANT_FUNC_HIGHBD_32](
|
|
coeff, tx2d_size, p, qcoeff, pd, dqcoeff, eob, scan_order);
|
|
else
|
|
quant_func_list[xform_quant_idx][QUANT_FUNC_HIGHBD](
|
|
coeff, tx2d_size, p, qcoeff, pd, dqcoeff, eob, scan_order);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
#endif // CONFIG_VP9_HIGHBITDEPTH
|
|
|
|
fwd_txfm(src_diff, coeff, diff_stride, &fwd_txfm_param);
|
|
if (xform_quant_idx != VP10_XFORM_QUANT_SKIP_QUANT) {
|
|
if (x->skip_block) {
|
|
vp10_quantize_skip(tx2d_size, qcoeff, dqcoeff, eob);
|
|
} else {
|
|
if (tx_size == TX_32X32)
|
|
quant_func_list[xform_quant_idx][QUANT_FUNC_LOWBD_32](
|
|
coeff, tx2d_size, p, qcoeff, pd, dqcoeff, eob, scan_order);
|
|
else
|
|
quant_func_list[xform_quant_idx][QUANT_FUNC_LOWBD](
|
|
coeff, tx2d_size, p, qcoeff, pd, dqcoeff, eob, scan_order);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void encode_block(int plane, int block, int blk_row, int blk_col,
|
|
BLOCK_SIZE plane_bsize,
|
|
TX_SIZE tx_size, void *arg) {
|
|
struct encode_b_args *const args = arg;
|
|
MACROBLOCK *const x = args->x;
|
|
MACROBLOCKD *const xd = &x->e_mbd;
|
|
struct optimize_ctx *const ctx = args->ctx;
|
|
struct macroblock_plane *const p = &x->plane[plane];
|
|
struct macroblockd_plane *const pd = &xd->plane[plane];
|
|
tran_low_t *const dqcoeff = BLOCK_OFFSET(pd->dqcoeff, block);
|
|
uint8_t *dst;
|
|
ENTROPY_CONTEXT *a, *l;
|
|
INV_TXFM_PARAM inv_txfm_param;
|
|
#if CONFIG_VAR_TX
|
|
int i;
|
|
const int bwl = b_width_log2_lookup[plane_bsize];
|
|
#endif
|
|
dst = &pd->dst.buf[4 * blk_row * pd->dst.stride + 4 * blk_col];
|
|
a = &ctx->ta[plane][blk_col];
|
|
l = &ctx->tl[plane][blk_row];
|
|
|
|
// TODO(jingning): per transformed block zero forcing only enabled for
|
|
// luma component. will integrate chroma components as well.
|
|
// Turn this back on when the rate-distortion loop is synchronized with
|
|
// the recursive transform block coding.
|
|
// if (x->zcoeff_blk[tx_size][block] && plane == 0) {
|
|
// p->eobs[block] = 0;
|
|
// *a = *l = 0;
|
|
// return;
|
|
// }
|
|
|
|
#if CONFIG_VAR_TX
|
|
if (!x->skip_recode &&
|
|
x->blk_skip[plane][(blk_row << bwl) + blk_col] == 0) {
|
|
#else
|
|
if (!x->skip_recode) {
|
|
#endif
|
|
if (x->quant_fp) {
|
|
// Encoding process for rtc mode
|
|
if (x->skip_txfm[0][0] == SKIP_TXFM_AC_DC && plane == 0) {
|
|
// skip forward transform
|
|
p->eobs[block] = 0;
|
|
*a = *l = 0;
|
|
return;
|
|
} else {
|
|
vp10_xform_quant(x, plane, block, blk_row, blk_col, plane_bsize,
|
|
tx_size, VP10_XFORM_QUANT_FP);
|
|
}
|
|
} else {
|
|
if (max_txsize_lookup[plane_bsize] == tx_size) {
|
|
int blk_index = (block >> (tx_size << 1));
|
|
if (x->skip_txfm[plane][blk_index] == SKIP_TXFM_NONE) {
|
|
// full forward transform and quantization
|
|
vp10_xform_quant(x, plane, block, blk_row, blk_col, plane_bsize,
|
|
tx_size, VP10_XFORM_QUANT_B);
|
|
} else if (x->skip_txfm[plane][blk_index] == SKIP_TXFM_AC_ONLY) {
|
|
// fast path forward transform and quantization
|
|
vp10_xform_quant(x, plane, block, blk_row, blk_col, plane_bsize,
|
|
tx_size, VP10_XFORM_QUANT_DC);
|
|
} else {
|
|
// skip forward transform
|
|
p->eobs[block] = 0;
|
|
*a = *l = 0;
|
|
#if !CONFIG_VAR_TX
|
|
return;
|
|
#endif
|
|
}
|
|
} else {
|
|
vp10_xform_quant(x, plane, block, blk_row, blk_col, plane_bsize,
|
|
tx_size, VP10_XFORM_QUANT_B);
|
|
}
|
|
}
|
|
}
|
|
#if CONFIG_VAR_TX
|
|
else {
|
|
if (!x->skip_recode)
|
|
p->eobs[block] = 0;
|
|
}
|
|
#endif
|
|
|
|
if (x->optimize && (!x->skip_recode || !x->skip_optimize)) {
|
|
int ctx;
|
|
#if CONFIG_VAR_TX
|
|
switch (tx_size) {
|
|
case TX_4X4:
|
|
break;
|
|
case TX_8X8:
|
|
a[0] = !!*(const uint16_t *)&a[0];
|
|
l[0] = !!*(const uint16_t *)&l[0];
|
|
break;
|
|
case TX_16X16:
|
|
a[0] = !!*(const uint32_t *)&a[0];
|
|
l[0] = !!*(const uint32_t *)&l[0];
|
|
break;
|
|
case TX_32X32:
|
|
a[0] = !!*(const uint64_t *)&a[0];
|
|
l[0] = !!*(const uint64_t *)&l[0];
|
|
break;
|
|
default:
|
|
assert(0 && "Invalid transform size.");
|
|
break;
|
|
}
|
|
#endif
|
|
ctx = combine_entropy_contexts(*a, *l);
|
|
*a = *l = optimize_b(x, plane, block, tx_size, ctx) > 0;
|
|
} else {
|
|
*a = *l = p->eobs[block] > 0;
|
|
}
|
|
|
|
#if CONFIG_VAR_TX
|
|
for (i = 0; i < (1 << tx_size); ++i) {
|
|
a[i] = a[0];
|
|
l[i] = l[0];
|
|
}
|
|
#endif
|
|
|
|
if (p->eobs[block])
|
|
*(args->skip) = 0;
|
|
|
|
if (p->eobs[block] == 0)
|
|
return;
|
|
|
|
// inverse transform parameters
|
|
inv_txfm_param.tx_type = get_tx_type(pd->plane_type, xd, block, tx_size);
|
|
inv_txfm_param.tx_size = tx_size;
|
|
inv_txfm_param.eob = p->eobs[block];
|
|
inv_txfm_param.lossless = xd->lossless[xd->mi[0]->mbmi.segment_id];
|
|
|
|
#if CONFIG_VP9_HIGHBITDEPTH
|
|
if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) {
|
|
inv_txfm_param.bd = xd->bd;
|
|
highbd_inv_txfm_add(dqcoeff, dst, pd->dst.stride, &inv_txfm_param);
|
|
return;
|
|
}
|
|
#endif // CONFIG_VP9_HIGHBITDEPTH
|
|
inv_txfm_add(dqcoeff, dst, pd->dst.stride, &inv_txfm_param);
|
|
}
|
|
|
|
#if CONFIG_VAR_TX
|
|
static void encode_block_inter(int plane, int block, int blk_row, int blk_col,
|
|
BLOCK_SIZE plane_bsize, TX_SIZE tx_size,
|
|
void *arg) {
|
|
struct encode_b_args *const args = arg;
|
|
MACROBLOCK *const x = args->x;
|
|
MACROBLOCKD *const xd = &x->e_mbd;
|
|
MB_MODE_INFO *const mbmi = &xd->mi[0]->mbmi;
|
|
const BLOCK_SIZE bsize = txsize_to_bsize[tx_size];
|
|
const struct macroblockd_plane *const pd = &xd->plane[plane];
|
|
const int tx_row = blk_row >> (1 - pd->subsampling_y);
|
|
const int tx_col = blk_col >> (1 - pd->subsampling_x);
|
|
const TX_SIZE plane_tx_size = plane ?
|
|
get_uv_tx_size_impl(mbmi->inter_tx_size[tx_row][tx_col], bsize, 0, 0) :
|
|
mbmi->inter_tx_size[tx_row][tx_col];
|
|
|
|
int max_blocks_high = num_4x4_blocks_high_lookup[plane_bsize];
|
|
int max_blocks_wide = num_4x4_blocks_wide_lookup[plane_bsize];
|
|
|
|
if (xd->mb_to_bottom_edge < 0)
|
|
max_blocks_high += xd->mb_to_bottom_edge >> (5 + pd->subsampling_y);
|
|
if (xd->mb_to_right_edge < 0)
|
|
max_blocks_wide += xd->mb_to_right_edge >> (5 + pd->subsampling_x);
|
|
|
|
if (blk_row >= max_blocks_high || blk_col >= max_blocks_wide)
|
|
return;
|
|
|
|
if (tx_size == plane_tx_size) {
|
|
encode_block(plane, block, blk_row, blk_col, plane_bsize,
|
|
tx_size, arg);
|
|
} else {
|
|
int bsl = b_width_log2_lookup[bsize];
|
|
int i;
|
|
|
|
assert(bsl > 0);
|
|
--bsl;
|
|
|
|
for (i = 0; i < 4; ++i) {
|
|
const int offsetr = blk_row + ((i >> 1) << bsl);
|
|
const int offsetc = blk_col + ((i & 0x01) << bsl);
|
|
int step = 1 << (2 * (tx_size - 1));
|
|
|
|
if (offsetr >= max_blocks_high || offsetc >= max_blocks_wide)
|
|
continue;
|
|
|
|
encode_block_inter(plane, block + i * step, offsetr, offsetc,
|
|
plane_bsize, tx_size - 1, arg);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static void encode_block_pass1(int plane, int block, int blk_row, int blk_col,
|
|
BLOCK_SIZE plane_bsize,
|
|
TX_SIZE tx_size, void *arg) {
|
|
MACROBLOCK *const x = (MACROBLOCK *)arg;
|
|
MACROBLOCKD *const xd = &x->e_mbd;
|
|
struct macroblock_plane *const p = &x->plane[plane];
|
|
struct macroblockd_plane *const pd = &xd->plane[plane];
|
|
tran_low_t *const dqcoeff = BLOCK_OFFSET(pd->dqcoeff, block);
|
|
uint8_t *dst;
|
|
dst = &pd->dst.buf[4 * blk_row * pd->dst.stride + 4 * blk_col];
|
|
|
|
vp10_xform_quant(x, plane, block, blk_row, blk_col, plane_bsize,
|
|
tx_size, VP10_XFORM_QUANT_B);
|
|
|
|
if (p->eobs[block] > 0) {
|
|
#if CONFIG_VP9_HIGHBITDEPTH
|
|
if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) {
|
|
if (xd->lossless[xd->mi[0]->mbmi.segment_id]) {
|
|
vp10_highbd_iwht4x4_add(dqcoeff, dst, pd->dst.stride,
|
|
p->eobs[block], xd->bd);
|
|
} else {
|
|
vp10_highbd_idct4x4_add(dqcoeff, dst, pd->dst.stride,
|
|
p->eobs[block], xd->bd);
|
|
}
|
|
return;
|
|
}
|
|
#endif // CONFIG_VP9_HIGHBITDEPTH
|
|
if (xd->lossless[xd->mi[0]->mbmi.segment_id]) {
|
|
vp10_iwht4x4_add(dqcoeff, dst, pd->dst.stride, p->eobs[block]);
|
|
} else {
|
|
vp10_idct4x4_add(dqcoeff, dst, pd->dst.stride, p->eobs[block]);
|
|
}
|
|
}
|
|
}
|
|
|
|
void vp10_encode_sby_pass1(MACROBLOCK *x, BLOCK_SIZE bsize) {
|
|
vp10_subtract_plane(x, bsize, 0);
|
|
vp10_foreach_transformed_block_in_plane(&x->e_mbd, bsize, 0,
|
|
encode_block_pass1, x);
|
|
}
|
|
|
|
void vp10_encode_sb(MACROBLOCK *x, BLOCK_SIZE bsize) {
|
|
MACROBLOCKD *const xd = &x->e_mbd;
|
|
struct optimize_ctx ctx;
|
|
MB_MODE_INFO *mbmi = &xd->mi[0]->mbmi;
|
|
struct encode_b_args arg = {x, &ctx, &mbmi->skip};
|
|
int plane;
|
|
|
|
mbmi->skip = 1;
|
|
|
|
if (x->skip)
|
|
return;
|
|
|
|
for (plane = 0; plane < MAX_MB_PLANE; ++plane) {
|
|
#if CONFIG_VAR_TX
|
|
// TODO(jingning): Clean this up.
|
|
const struct macroblockd_plane *const pd = &xd->plane[plane];
|
|
const BLOCK_SIZE plane_bsize = get_plane_block_size(bsize, pd);
|
|
const int mi_width = num_4x4_blocks_wide_lookup[plane_bsize];
|
|
const int mi_height = num_4x4_blocks_high_lookup[plane_bsize];
|
|
const TX_SIZE max_tx_size = max_txsize_lookup[plane_bsize];
|
|
const BLOCK_SIZE txb_size = txsize_to_bsize[max_tx_size];
|
|
const int bh = num_4x4_blocks_wide_lookup[txb_size];
|
|
int idx, idy;
|
|
int block = 0;
|
|
int step = 1 << (max_tx_size * 2);
|
|
#endif
|
|
if (!x->skip_recode)
|
|
vp10_subtract_plane(x, bsize, plane);
|
|
|
|
if (x->optimize && (!x->skip_recode || !x->skip_optimize)) {
|
|
#if CONFIG_VAR_TX
|
|
vp10_get_entropy_contexts(bsize, TX_4X4, pd,
|
|
ctx.ta[plane], ctx.tl[plane]);
|
|
#else
|
|
const struct macroblockd_plane* const pd = &xd->plane[plane];
|
|
const TX_SIZE tx_size = plane ? get_uv_tx_size(mbmi, pd) : mbmi->tx_size;
|
|
vp10_get_entropy_contexts(bsize, tx_size, pd,
|
|
ctx.ta[plane], ctx.tl[plane]);
|
|
#endif
|
|
}
|
|
|
|
#if CONFIG_VAR_TX
|
|
for (idy = 0; idy < mi_height; idy += bh) {
|
|
for (idx = 0; idx < mi_width; idx += bh) {
|
|
encode_block_inter(plane, block, idy, idx, plane_bsize,
|
|
max_tx_size, &arg);
|
|
block += step;
|
|
}
|
|
}
|
|
#else
|
|
vp10_foreach_transformed_block_in_plane(xd, bsize, plane, encode_block,
|
|
&arg);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
#if CONFIG_SUPERTX
|
|
void vp10_encode_sb_supertx(MACROBLOCK *x, BLOCK_SIZE bsize) {
|
|
MACROBLOCKD *const xd = &x->e_mbd;
|
|
struct optimize_ctx ctx;
|
|
MB_MODE_INFO *mbmi = &xd->mi[0]->mbmi;
|
|
struct encode_b_args arg = {x, &ctx, &mbmi->skip};
|
|
int plane;
|
|
|
|
mbmi->skip = 1;
|
|
if (x->skip)
|
|
return;
|
|
|
|
for (plane = 0; plane < MAX_MB_PLANE; ++plane) {
|
|
const struct macroblockd_plane* const pd = &xd->plane[plane];
|
|
const TX_SIZE tx_size = plane ? get_uv_tx_size(mbmi, pd) : mbmi->tx_size;
|
|
vp10_subtract_plane(x, bsize, plane);
|
|
vp10_get_entropy_contexts(bsize, tx_size, pd,
|
|
ctx.ta[plane], ctx.tl[plane]);
|
|
vp10_foreach_transformed_block_in_plane(xd, bsize, plane, encode_block,
|
|
&arg);
|
|
}
|
|
}
|
|
#endif // CONFIG_SUPERTX
|
|
|
|
void vp10_encode_block_intra(int plane, int block, int blk_row, int blk_col,
|
|
BLOCK_SIZE plane_bsize,
|
|
TX_SIZE tx_size, void *arg) {
|
|
struct encode_b_args* const args = arg;
|
|
MACROBLOCK *const x = args->x;
|
|
MACROBLOCKD *const xd = &x->e_mbd;
|
|
MB_MODE_INFO *mbmi = &xd->mi[0]->mbmi;
|
|
struct macroblock_plane *const p = &x->plane[plane];
|
|
struct macroblockd_plane *const pd = &xd->plane[plane];
|
|
tran_low_t *dqcoeff = BLOCK_OFFSET(pd->dqcoeff, block);
|
|
PLANE_TYPE plane_type = (plane == 0) ? PLANE_TYPE_Y : PLANE_TYPE_UV;
|
|
const TX_TYPE tx_type = get_tx_type(plane_type, xd, block, tx_size);
|
|
PREDICTION_MODE mode;
|
|
const int bwl = b_width_log2_lookup[plane_bsize];
|
|
const int bhl = b_height_log2_lookup[plane_bsize];
|
|
const int diff_stride = 4 * (1 << bwl);
|
|
uint8_t *src, *dst;
|
|
int16_t *src_diff;
|
|
uint16_t *eob = &p->eobs[block];
|
|
const int src_stride = p->src.stride;
|
|
const int dst_stride = pd->dst.stride;
|
|
|
|
const int tx1d_size = get_tx1d_size(tx_size);
|
|
|
|
INV_TXFM_PARAM inv_txfm_param;
|
|
|
|
dst = &pd->dst.buf[4 * (blk_row * dst_stride + blk_col)];
|
|
src = &p->src.buf[4 * (blk_row * src_stride + blk_col)];
|
|
src_diff = &p->src_diff[4 * (blk_row * diff_stride + blk_col)];
|
|
|
|
mode = plane == 0 ? get_y_mode(xd->mi[0], block) : mbmi->uv_mode;
|
|
vp10_predict_intra_block(xd, bwl, bhl, tx_size, mode, dst, dst_stride, dst,
|
|
dst_stride, blk_col, blk_row, plane);
|
|
#if CONFIG_VP9_HIGHBITDEPTH
|
|
if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) {
|
|
vpx_highbd_subtract_block(tx1d_size, tx1d_size, src_diff, diff_stride, src,
|
|
src_stride, dst, dst_stride, xd->bd);
|
|
} else {
|
|
vpx_subtract_block(tx1d_size, tx1d_size, src_diff, diff_stride, src,
|
|
src_stride, dst, dst_stride);
|
|
}
|
|
#else
|
|
vpx_subtract_block(tx1d_size, tx1d_size, src_diff, diff_stride, src,
|
|
src_stride, dst, dst_stride);
|
|
#endif // CONFIG_VP9_HIGHBITDEPTH
|
|
|
|
#if CONFIG_EXT_INTRA
|
|
vp10_xform_quant(x, plane, block, blk_row, blk_col, plane_bsize, tx_size,
|
|
VP10_XFORM_QUANT_B);
|
|
#else
|
|
if (!x->skip_recode)
|
|
vp10_xform_quant(x, plane, block, blk_row, blk_col, plane_bsize, tx_size,
|
|
VP10_XFORM_QUANT_B);
|
|
else
|
|
vp10_xform_quant(x, plane, block, blk_row, blk_col, plane_bsize, tx_size,
|
|
VP10_XFORM_QUANT_SKIP_QUANT);
|
|
#endif // CONFIG_EXT_INTRA
|
|
|
|
if (*eob) {
|
|
// inverse transform
|
|
inv_txfm_param.tx_type = tx_type;
|
|
inv_txfm_param.tx_size = tx_size;
|
|
inv_txfm_param.eob = *eob;
|
|
inv_txfm_param.lossless = xd->lossless[mbmi->segment_id];
|
|
#if CONFIG_VP9_HIGHBITDEPTH
|
|
inv_txfm_param.bd = xd->bd;
|
|
if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) {
|
|
highbd_inv_txfm_add(dqcoeff, dst, dst_stride, &inv_txfm_param);
|
|
} else {
|
|
inv_txfm_add(dqcoeff, dst, dst_stride, &inv_txfm_param);
|
|
}
|
|
#else
|
|
inv_txfm_add(dqcoeff, dst, dst_stride, &inv_txfm_param);
|
|
#endif // CONFIG_VP9_HIGHBITDEPTH
|
|
|
|
*(args->skip) = 0;
|
|
}
|
|
}
|
|
|
|
void vp10_encode_intra_block_plane(MACROBLOCK *x, BLOCK_SIZE bsize, int plane) {
|
|
const MACROBLOCKD *const xd = &x->e_mbd;
|
|
struct encode_b_args arg = {x, NULL, &xd->mi[0]->mbmi.skip};
|
|
|
|
vp10_foreach_transformed_block_in_plane(xd, bsize, plane,
|
|
vp10_encode_block_intra, &arg);
|
|
}
|