aom/vp8/encoder/encodemb.c

781 строка
19 KiB
C
Исходник Обычный вид История

2010-05-18 19:58:33 +04:00
/*
* Copyright (c) 2010 The VP8 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.
2010-05-18 19:58:33 +04:00
*/
#include "vpx_ports/config.h"
#include "encodemb.h"
#include "reconinter.h"
#include "quantize.h"
#include "invtrans.h"
#include "recon.h"
#include "reconintra.h"
#include "dct.h"
#include "vpx_mem/vpx_mem.h"
#if CONFIG_RUNTIME_CPU_DETECT
#define IF_RTCD(x) (x)
#else
#define IF_RTCD(x) NULL
#endif
void vp8_subtract_b_c(BLOCK *be, BLOCKD *bd, int pitch)
{
unsigned char *src_ptr = (*(be->base_src) + be->src);
short *diff_ptr = be->src_diff;
unsigned char *pred_ptr = bd->predictor;
int src_stride = be->src_stride;
int r, c;
for (r = 0; r < 4; r++)
{
for (c = 0; c < 4; c++)
{
diff_ptr[c] = src_ptr[c] - pred_ptr[c];
}
diff_ptr += pitch;
pred_ptr += pitch;
src_ptr += src_stride;
}
}
void vp8_subtract_mbuv_c(short *diff, unsigned char *usrc, unsigned char *vsrc, unsigned char *pred, int stride)
{
short *udiff = diff + 256;
short *vdiff = diff + 320;
unsigned char *upred = pred + 256;
unsigned char *vpred = pred + 320;
int r, c;
for (r = 0; r < 8; r++)
{
for (c = 0; c < 8; c++)
{
udiff[c] = usrc[c] - upred[c];
}
udiff += 8;
upred += 8;
usrc += stride;
}
for (r = 0; r < 8; r++)
{
for (c = 0; c < 8; c++)
{
vdiff[c] = vsrc[c] - vpred[c];
}
vdiff += 8;
vpred += 8;
vsrc += stride;
}
}
void vp8_subtract_mby_c(short *diff, unsigned char *src, unsigned char *pred, int stride)
{
int r, c;
for (r = 0; r < 16; r++)
{
for (c = 0; c < 16; c++)
{
diff[c] = src[c] - pred[c];
}
diff += 16;
pred += 16;
src += stride;
}
}
static void vp8_subtract_mb(const VP8_ENCODER_RTCD *rtcd, MACROBLOCK *x)
{
ENCODEMB_INVOKE(&rtcd->encodemb, submby)(x->src_diff, x->src.y_buffer, x->e_mbd.predictor, x->src.y_stride);
ENCODEMB_INVOKE(&rtcd->encodemb, submbuv)(x->src_diff, x->src.u_buffer, x->src.v_buffer, x->e_mbd.predictor, x->src.uv_stride);
}
void vp8_build_dcblock(MACROBLOCK *x)
{
short *src_diff_ptr = &x->src_diff[384];
int i;
for (i = 0; i < 16; i++)
{
src_diff_ptr[i] = x->coeff[i * 16];
}
}
void vp8_transform_mbuv(MACROBLOCK *x)
{
int i;
for (i = 16; i < 24; i += 2)
{
x->vp8_short_fdct8x4(&x->block[i].src_diff[0], &x->block[i].coeff[0], 16);
}
}
void vp8_transform_mbuvrd(MACROBLOCK *x)
{
int i;
for (i = 16; i < 24; i += 2)
{
x->short_fdct8x4rd(&x->block[i].src_diff[0], &x->block[i].coeff[0], 16);
}
}
void vp8_transform_intra_mby(MACROBLOCK *x)
{
int i;
for (i = 0; i < 16; i += 2)
{
x->vp8_short_fdct8x4(&x->block[i].src_diff[0], &x->block[i].coeff[0], 32);
}
// build dc block from 16 y dc values
vp8_build_dcblock(x);
// do 2nd order transform on the dc block
x->short_walsh4x4(&x->block[24].src_diff[0], &x->block[24].coeff[0], 8);
}
void vp8_transform_intra_mbyrd(MACROBLOCK *x)
{
int i;
for (i = 0; i < 16; i += 2)
{
x->short_fdct8x4rd(&x->block[i].src_diff[0], &x->block[i].coeff[0], 32);
}
// build dc block from 16 y dc values
vp8_build_dcblock(x);
// do 2nd order transform on the dc block
x->short_walsh4x4(&x->block[24].src_diff[0], &x->block[24].coeff[0], 8);
}
void vp8_transform_mb(MACROBLOCK *x)
{
int i;
for (i = 0; i < 16; i += 2)
{
x->vp8_short_fdct8x4(&x->block[i].src_diff[0], &x->block[i].coeff[0], 32);
}
// build dc block from 16 y dc values
if (x->e_mbd.mbmi.mode != SPLITMV)
vp8_build_dcblock(x);
for (i = 16; i < 24; i += 2)
{
x->vp8_short_fdct8x4(&x->block[i].src_diff[0], &x->block[i].coeff[0], 16);
}
// do 2nd order transform on the dc block
if (x->e_mbd.mbmi.mode != SPLITMV)
x->short_walsh4x4(&x->block[24].src_diff[0], &x->block[24].coeff[0], 8);
}
void vp8_transform_mby(MACROBLOCK *x)
{
int i;
for (i = 0; i < 16; i += 2)
{
x->vp8_short_fdct8x4(&x->block[i].src_diff[0], &x->block[i].coeff[0], 32);
}
// build dc block from 16 y dc values
if (x->e_mbd.mbmi.mode != SPLITMV)
{
vp8_build_dcblock(x);
x->short_walsh4x4(&x->block[24].src_diff[0], &x->block[24].coeff[0], 8);
}
}
void vp8_transform_mbrd(MACROBLOCK *x)
{
int i;
for (i = 0; i < 16; i += 2)
{
x->short_fdct8x4rd(&x->block[i].src_diff[0], &x->block[i].coeff[0], 32);
}
// build dc block from 16 y dc values
if (x->e_mbd.mbmi.mode != SPLITMV)
vp8_build_dcblock(x);
for (i = 16; i < 24; i += 2)
{
x->short_fdct8x4rd(&x->block[i].src_diff[0], &x->block[i].coeff[0], 16);
}
// do 2nd order transform on the dc block
if (x->e_mbd.mbmi.mode != SPLITMV)
x->short_walsh4x4(&x->block[24].src_diff[0], &x->block[24].coeff[0], 8);
}
void vp8_stuff_inter16x16(MACROBLOCK *x)
{
vp8_build_inter_predictors_mb_s(&x->e_mbd);
/*
// recon = copy from predictors to destination
{
BLOCKD *b = &x->e_mbd.block[0];
unsigned char *pred_ptr = b->predictor;
unsigned char *dst_ptr = *(b->base_dst) + b->dst;
int stride = b->dst_stride;
int i;
for(i=0;i<16;i++)
vpx_memcpy(dst_ptr+i*stride,pred_ptr+16*i,16);
b = &x->e_mbd.block[16];
pred_ptr = b->predictor;
dst_ptr = *(b->base_dst) + b->dst;
stride = b->dst_stride;
for(i=0;i<8;i++)
vpx_memcpy(dst_ptr+i*stride,pred_ptr+8*i,8);
b = &x->e_mbd.block[20];
pred_ptr = b->predictor;
dst_ptr = *(b->base_dst) + b->dst;
stride = b->dst_stride;
for(i=0;i<8;i++)
vpx_memcpy(dst_ptr+i*stride,pred_ptr+8*i,8);
}
*/
}
#if !(CONFIG_REALTIME_ONLY)
extern const TOKENEXTRA vp8_dct_value_tokens[DCT_MAX_VALUE*2];
extern const TOKENEXTRA *vp8_dct_value_tokens_ptr;
extern int vp8_dct_value_cost[DCT_MAX_VALUE*2];
extern int *vp8_dct_value_cost_ptr;
static int cost_coeffs(MACROBLOCK *mb, BLOCKD *b, int type, ENTROPY_CONTEXT *a, ENTROPY_CONTEXT *l)
{
int c = !type; /* start at coef 0, unless Y with Y2 */
int eob = b->eob;
int pt ; /* surrounding block/prev coef predictor */
int cost = 0;
short *qcoeff_ptr = b->qcoeff;
VP8_COMBINEENTROPYCONTEXTS(pt, *a, *l);
# define QC( I) ( qcoeff_ptr [vp8_default_zig_zag1d[I]] )
for (; c < eob; c++)
{
int v = QC(c);
int t = vp8_dct_value_tokens_ptr[v].Token;
cost += mb->token_costs [type] [vp8_coef_bands[c]] [pt] [t];
cost += vp8_dct_value_cost_ptr[v];
pt = vp8_prev_token_class[t];
}
# undef QC
if (c < 16)
cost += mb->token_costs [type] [vp8_coef_bands[c]] [pt] [DCT_EOB_TOKEN];
return cost;
}
static int mbycost_coeffs(MACROBLOCK *mb)
{
int cost = 0;
int b;
TEMP_CONTEXT t;
int type = 0;
MACROBLOCKD *x = &mb->e_mbd;
vp8_setup_temp_context(&t, x->above_context[Y1CONTEXT], x->left_context[Y1CONTEXT], 4);
if (x->mbmi.mode == SPLITMV)
type = 3;
for (b = 0; b < 16; b++)
cost += cost_coeffs(mb, x->block + b, type,
t.a + vp8_block2above[b], t.l + vp8_block2left[b]);
return cost;
}
#define RDFUNC(RM,DM,R,D,target_rd) ( ((128+(R)*(RM)) >> 8) + (DM)*(D) )
void vp8_optimize_b(MACROBLOCK *x, int i, int type, ENTROPY_CONTEXT *a, ENTROPY_CONTEXT *l, const VP8_ENCODER_RTCD *rtcd)
{
BLOCK *b = &x->block[i];
BLOCKD *bd = &x->e_mbd.block[i];
short *dequant_ptr = &bd->dequant[0][0];
int nzpos[16] = {0};
short saved_qcoefs[16];
short saved_dqcoefs[16];
int baserate, baseerror, baserd;
int rate, error, thisrd;
int k;
int nzcoefcount = 0;
int nc, bestnc = 0;
int besteob;
// count potential coefficient to be optimized
for (k = !type; k < 16; k++)
{
int qcoef = abs(bd->qcoeff[k]);
int coef = abs(b->coeff[k]);
int dq = dequant_ptr[k];
if (qcoef && (qcoef * dq > coef) && (qcoef * dq < coef + dq))
{
nzpos[nzcoefcount] = k;
nzcoefcount++;
}
}
// if nothing here, do nothing for this block.
if (!nzcoefcount)
{
*a = *l = (bd->eob != !type);
return;
}
// save a copy of quantized coefficients
vpx_memcpy(saved_qcoefs, bd->qcoeff, 32);
vpx_memcpy(saved_dqcoefs, bd->dqcoeff, 32);
besteob = bd->eob;
baserate = cost_coeffs(x, bd, type, a, l);
baseerror = ENCODEMB_INVOKE(&rtcd->encodemb, berr)(b->coeff, bd->dqcoeff) >> 2;
baserd = RDFUNC(x->rdmult, x->rddiv, baserate, baseerror, 100);
for (nc = 1; nc < (1 << nzcoefcount); nc++)
{
//reset coefficients
vpx_memcpy(bd->qcoeff, saved_qcoefs, 32);
vpx_memcpy(bd->dqcoeff, saved_dqcoefs, 32);
for (k = 0; k < nzcoefcount; k++)
{
int pos = nzpos[k];
if ((nc & (1 << k)))
{
int cur_qcoef = bd->qcoeff[pos];
if (cur_qcoef < 0)
{
bd->qcoeff[pos]++;
bd->dqcoeff[pos] = bd->qcoeff[pos] * dequant_ptr[pos];
}
else
{
bd->qcoeff[pos]--;
bd->dqcoeff[pos] = bd->qcoeff[pos] * dequant_ptr[pos];
}
}
}
{
int eob = -1;
int rc;
int m;
for (m = 0; m < 16; m++)
{
rc = vp8_default_zig_zag1d[m];
if (bd->qcoeff[rc])
eob = m;
}
bd->eob = eob + 1;
}
rate = cost_coeffs(x, bd, type, a, l);
error = ENCODEMB_INVOKE(&rtcd->encodemb, berr)(b->coeff, bd->dqcoeff) >> 2;
thisrd = RDFUNC(x->rdmult, x->rddiv, rate, error, 100);
if (thisrd < baserd)
{
baserd = thisrd;
bestnc = nc;
besteob = bd->eob;
}
}
//reset coefficients
vpx_memcpy(bd->qcoeff, saved_qcoefs, 32);
vpx_memcpy(bd->dqcoeff, saved_dqcoefs, 32);
if (bestnc)
{
for (k = 0; k < nzcoefcount; k++)
{
int pos = nzpos[k];
if (bestnc & (1 << k))
{
int cur_qcoef = bd->qcoeff[pos];
if (cur_qcoef < 0)
{
bd->qcoeff[pos]++;
bd->dqcoeff[pos] = bd->qcoeff[pos] * dequant_ptr[pos];
}
else
{
bd->qcoeff[pos]--;
bd->dqcoeff[pos] = bd->qcoeff[pos] * dequant_ptr[pos];
}
}
}
#if 0
{
int eob = -1;
int rc;
int m;
for (m = 0; m < 16; m++)
{
rc = vp8_default_zig_zag1d[m];
if (bd->qcoeff[rc])
eob = m;
}
bd->eob = eob + 1;
}
#endif
}
#if 1
bd->eob = besteob;
#endif
#if 0
{
int eob = -1;
int rc;
int m;
for (m = 0; m < 16; m++)
{
rc = vp8_default_zig_zag1d[m];
if (bd->qcoeff[rc])
eob = m;
}
bd->eob = eob + 1;
}
#endif
*a = *l = (bd->eob != !type);
return;
}
void vp8_optimize_y2b(MACROBLOCK *x, int i, int type, ENTROPY_CONTEXT *a, ENTROPY_CONTEXT *l, const VP8_ENCODER_RTCD *rtcd)
{
BLOCK *b = &x->block[i];
BLOCKD *bd = &x->e_mbd.block[i];
short *dequant_ptr = &bd->dequant[0][0];
int baserate, baseerror, baserd;
int rate, error, thisrd;
int k;
if (bd->eob == 0)
return;
baserate = cost_coeffs(x, bd, type, a, l);
baseerror = ENCODEMB_INVOKE(&rtcd->encodemb, berr)(b->coeff, bd->dqcoeff) >> 4;
baserd = RDFUNC(x->rdmult, x->rddiv, baserate, baseerror, 100);
for (k = 0; k < 16; k++)
{
int cur_qcoef = bd->qcoeff[k];
if (!cur_qcoef)
continue;
if (cur_qcoef < 0)
{
bd->qcoeff[k]++;
bd->dqcoeff[k] = bd->qcoeff[k] * dequant_ptr[k];
}
else
{
bd->qcoeff[k]--;
bd->dqcoeff[k] = bd->qcoeff[k] * dequant_ptr[k];
}
if (bd->qcoeff[k] == 0)
{
int eob = -1;
int rc;
int l;
for (l = 0; l < 16; l++)
{
rc = vp8_default_zig_zag1d[l];
if (bd->qcoeff[rc])
eob = l;
}
bd->eob = eob + 1;
}
rate = cost_coeffs(x, bd, type, a, l);
error = ENCODEMB_INVOKE(&rtcd->encodemb, berr)(b->coeff, bd->dqcoeff) >> 4;
thisrd = RDFUNC(x->rdmult, x->rddiv, rate, error, 100);
if (thisrd > baserd)
{
bd->qcoeff[k] = cur_qcoef;
bd->dqcoeff[k] = cur_qcoef * dequant_ptr[k];
}
else
{
baserd = thisrd;
}
}
{
int eob = -1;
int rc;
for (k = 0; k < 16; k++)
{
rc = vp8_default_zig_zag1d[k];
if (bd->qcoeff[rc])
eob = k;
}
bd->eob = eob + 1;
}
return;
}
void vp8_optimize_mb(MACROBLOCK *x, const VP8_ENCODER_RTCD *rtcd)
{
int b;
TEMP_CONTEXT t, t2;
int type = 0;
vp8_setup_temp_context(&t, x->e_mbd.above_context[Y1CONTEXT], x->e_mbd.left_context[Y1CONTEXT], 4);
if (x->e_mbd.mbmi.mode == SPLITMV || x->e_mbd.mbmi.mode == B_PRED)
type = 3;
for (b = 0; b < 16; b++)
{
//vp8_optimize_bplus(x, b, type, t.a + vp8_block2above[b], t.l + vp8_block2left[b]);
vp8_optimize_b(x, b, type, t.a + vp8_block2above[b], t.l + vp8_block2left[b], rtcd);
}
vp8_setup_temp_context(&t, x->e_mbd.above_context[UCONTEXT], x->e_mbd.left_context[UCONTEXT], 2);
vp8_setup_temp_context(&t2, x->e_mbd.above_context[VCONTEXT], x->e_mbd.left_context[VCONTEXT], 2);
for (b = 16; b < 20; b++)
{
//vp8_optimize_bplus(x, b, vp8_block2type[b], t.a + vp8_block2above[b], t.l + vp8_block2left[b]);
vp8_optimize_b(x, b, vp8_block2type[b], t.a + vp8_block2above[b], t.l + vp8_block2left[b], rtcd);
}
for (b = 20; b < 24; b++)
{
//vp8_optimize_bplus(x, b, vp8_block2type[b], t2.a + vp8_block2above[b], t2.l + vp8_block2left[b]);
vp8_optimize_b(x, b, vp8_block2type[b], t2.a + vp8_block2above[b], t2.l + vp8_block2left[b], rtcd);
}
}
static void vp8_find_mb_skip_coef(MACROBLOCK *x)
{
int i;
x->e_mbd.mbmi.mb_skip_coeff = 1;
if (x->e_mbd.mbmi.mode != B_PRED && x->e_mbd.mbmi.mode != SPLITMV)
{
for (i = 0; i < 16; i++)
{
x->e_mbd.mbmi.mb_skip_coeff &= (x->e_mbd.block[i].eob < 2);
}
for (i = 16; i < 25; i++)
{
x->e_mbd.mbmi.mb_skip_coeff &= (!x->e_mbd.block[i].eob);
}
}
else
{
for (i = 0; i < 24; i++)
{
x->e_mbd.mbmi.mb_skip_coeff &= (!x->e_mbd.block[i].eob);
}
}
}
void vp8_optimize_mby(MACROBLOCK *x, const VP8_ENCODER_RTCD *rtcd)
{
int b;
TEMP_CONTEXT t;
int type = 0;
if (!x->e_mbd.above_context[Y1CONTEXT])
return;
if (!x->e_mbd.left_context[Y1CONTEXT])
return;
vp8_setup_temp_context(&t, x->e_mbd.above_context[Y1CONTEXT], x->e_mbd.left_context[Y1CONTEXT], 4);
if (x->e_mbd.mbmi.mode == SPLITMV || x->e_mbd.mbmi.mode == B_PRED)
type = 3;
for (b = 0; b < 16; b++)
{
vp8_optimize_b(x, b, type, t.a + vp8_block2above[b], t.l + vp8_block2left[b], rtcd);
}
}
void vp8_optimize_mbuv(MACROBLOCK *x, const VP8_ENCODER_RTCD *rtcd)
{
int b;
TEMP_CONTEXT t, t2;
if (!x->e_mbd.above_context[UCONTEXT])
return;
if (!x->e_mbd.left_context[UCONTEXT])
return;
if (!x->e_mbd.above_context[VCONTEXT])
return;
if (!x->e_mbd.left_context[VCONTEXT])
return;
vp8_setup_temp_context(&t, x->e_mbd.above_context[UCONTEXT], x->e_mbd.left_context[UCONTEXT], 2);
vp8_setup_temp_context(&t2, x->e_mbd.above_context[VCONTEXT], x->e_mbd.left_context[VCONTEXT], 2);
for (b = 16; b < 20; b++)
{
vp8_optimize_b(x, b, vp8_block2type[b],
t.a + vp8_block2above[b], t.l + vp8_block2left[b], rtcd);
}
for (b = 20; b < 24; b++)
{
vp8_optimize_b(x, b, vp8_block2type[b],
t2.a + vp8_block2above[b], t2.l + vp8_block2left[b], rtcd);
}
}
#endif
void vp8_encode_inter16x16(const VP8_ENCODER_RTCD *rtcd, MACROBLOCK *x)
{
vp8_build_inter_predictors_mb(&x->e_mbd);
vp8_subtract_mb(rtcd, x);
vp8_transform_mb(x);
vp8_quantize_mb(x);
#if !(CONFIG_REALTIME_ONLY)
#if 1
if (x->optimize && x->rddiv > 1)
{
vp8_optimize_mb(x, rtcd);
vp8_find_mb_skip_coef(x);
}
#endif
#endif
vp8_inverse_transform_mb(IF_RTCD(&rtcd->common->idct), &x->e_mbd);
vp8_recon16x16mb(IF_RTCD(&rtcd->common->recon), &x->e_mbd);
}
/* this funciton is used by first pass only */
void vp8_encode_inter16x16y(const VP8_ENCODER_RTCD *rtcd, MACROBLOCK *x)
{
vp8_build_inter_predictors_mby(&x->e_mbd);
ENCODEMB_INVOKE(&rtcd->encodemb, submby)(x->src_diff, x->src.y_buffer, x->e_mbd.predictor, x->src.y_stride);
vp8_transform_mby(x);
vp8_quantize_mby(x);
vp8_inverse_transform_mby(IF_RTCD(&rtcd->common->idct), &x->e_mbd);
vp8_recon16x16mby(IF_RTCD(&rtcd->common->recon), &x->e_mbd);
}
void vp8_encode_inter16x16uv(const VP8_ENCODER_RTCD *rtcd, MACROBLOCK *x)
{
vp8_build_inter_predictors_mbuv(&x->e_mbd);
ENCODEMB_INVOKE(&rtcd->encodemb, submbuv)(x->src_diff, x->src.u_buffer, x->src.v_buffer, x->e_mbd.predictor, x->src.uv_stride);
vp8_transform_mbuv(x);
vp8_quantize_mb(x);
2010-05-18 19:58:33 +04:00
vp8_inverse_transform_mbuv(IF_RTCD(&rtcd->common->idct), &x->e_mbd);
vp8_recon_intra_mbuv(IF_RTCD(&rtcd->common->recon), &x->e_mbd);
}
void vp8_encode_inter16x16uvrd(const VP8_ENCODER_RTCD *rtcd, MACROBLOCK *x)
{
vp8_build_inter_predictors_mbuv(&x->e_mbd);
ENCODEMB_INVOKE(&rtcd->encodemb, submbuv)(x->src_diff, x->src.u_buffer, x->src.v_buffer, x->e_mbd.predictor, x->src.uv_stride);
vp8_transform_mbuvrd(x);
vp8_quantize_mbuv(x);
2010-05-18 19:58:33 +04:00
}