import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo

This commit is contained in:
Roy Tam 2018-01-19 03:59:58 +08:00
commit dcd9973243
150858 changed files with 23884658 additions and 0 deletions

View file

@ -0,0 +1,241 @@
/*
* Copyright (c) 2014 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 <arm_neon.h>
#include "./vp9_rtcd.h"
#include "./vpx_config.h"
#include "vp9/common/vp9_blockd.h"
#include "vp9/common/vp9_idct.h"
void vp9_fdct8x8_1_neon(const int16_t *input, int16_t *output, int stride) {
int r;
int16x8_t sum = vld1q_s16(&input[0]);
for (r = 1; r < 8; ++r) {
const int16x8_t input_00 = vld1q_s16(&input[r * stride]);
sum = vaddq_s16(sum, input_00);
}
{
const int32x4_t a = vpaddlq_s16(sum);
const int64x2_t b = vpaddlq_s32(a);
const int32x2_t c = vadd_s32(vreinterpret_s32_s64(vget_low_s64(b)),
vreinterpret_s32_s64(vget_high_s64(b)));
output[0] = vget_lane_s16(vreinterpret_s16_s32(c), 0);
output[1] = 0;
}
}
void vp9_fdct8x8_quant_neon(const int16_t *input, int stride,
int16_t* coeff_ptr, intptr_t n_coeffs,
int skip_block, const int16_t* zbin_ptr,
const int16_t* round_ptr, const int16_t* quant_ptr,
const int16_t* quant_shift_ptr,
int16_t* qcoeff_ptr, int16_t* dqcoeff_ptr,
const int16_t* dequant_ptr, uint16_t* eob_ptr,
const int16_t* scan_ptr,
const int16_t* iscan_ptr) {
int16_t temp_buffer[64];
(void)coeff_ptr;
vp9_fdct8x8_neon(input, temp_buffer, stride);
vp9_quantize_fp_neon(temp_buffer, n_coeffs, skip_block, zbin_ptr, round_ptr,
quant_ptr, quant_shift_ptr, qcoeff_ptr, dqcoeff_ptr,
dequant_ptr, eob_ptr, scan_ptr, iscan_ptr);
}
void vp9_fdct8x8_neon(const int16_t *input, int16_t *final_output, int stride) {
int i;
// stage 1
int16x8_t input_0 = vshlq_n_s16(vld1q_s16(&input[0 * stride]), 2);
int16x8_t input_1 = vshlq_n_s16(vld1q_s16(&input[1 * stride]), 2);
int16x8_t input_2 = vshlq_n_s16(vld1q_s16(&input[2 * stride]), 2);
int16x8_t input_3 = vshlq_n_s16(vld1q_s16(&input[3 * stride]), 2);
int16x8_t input_4 = vshlq_n_s16(vld1q_s16(&input[4 * stride]), 2);
int16x8_t input_5 = vshlq_n_s16(vld1q_s16(&input[5 * stride]), 2);
int16x8_t input_6 = vshlq_n_s16(vld1q_s16(&input[6 * stride]), 2);
int16x8_t input_7 = vshlq_n_s16(vld1q_s16(&input[7 * stride]), 2);
for (i = 0; i < 2; ++i) {
int16x8_t out_0, out_1, out_2, out_3, out_4, out_5, out_6, out_7;
const int16x8_t v_s0 = vaddq_s16(input_0, input_7);
const int16x8_t v_s1 = vaddq_s16(input_1, input_6);
const int16x8_t v_s2 = vaddq_s16(input_2, input_5);
const int16x8_t v_s3 = vaddq_s16(input_3, input_4);
const int16x8_t v_s4 = vsubq_s16(input_3, input_4);
const int16x8_t v_s5 = vsubq_s16(input_2, input_5);
const int16x8_t v_s6 = vsubq_s16(input_1, input_6);
const int16x8_t v_s7 = vsubq_s16(input_0, input_7);
// fdct4(step, step);
int16x8_t v_x0 = vaddq_s16(v_s0, v_s3);
int16x8_t v_x1 = vaddq_s16(v_s1, v_s2);
int16x8_t v_x2 = vsubq_s16(v_s1, v_s2);
int16x8_t v_x3 = vsubq_s16(v_s0, v_s3);
// fdct4(step, step);
int32x4_t v_t0_lo = vaddl_s16(vget_low_s16(v_x0), vget_low_s16(v_x1));
int32x4_t v_t0_hi = vaddl_s16(vget_high_s16(v_x0), vget_high_s16(v_x1));
int32x4_t v_t1_lo = vsubl_s16(vget_low_s16(v_x0), vget_low_s16(v_x1));
int32x4_t v_t1_hi = vsubl_s16(vget_high_s16(v_x0), vget_high_s16(v_x1));
int32x4_t v_t2_lo = vmull_n_s16(vget_low_s16(v_x2), (int16_t)cospi_24_64);
int32x4_t v_t2_hi = vmull_n_s16(vget_high_s16(v_x2), (int16_t)cospi_24_64);
int32x4_t v_t3_lo = vmull_n_s16(vget_low_s16(v_x3), (int16_t)cospi_24_64);
int32x4_t v_t3_hi = vmull_n_s16(vget_high_s16(v_x3), (int16_t)cospi_24_64);
v_t2_lo = vmlal_n_s16(v_t2_lo, vget_low_s16(v_x3), (int16_t)cospi_8_64);
v_t2_hi = vmlal_n_s16(v_t2_hi, vget_high_s16(v_x3), (int16_t)cospi_8_64);
v_t3_lo = vmlsl_n_s16(v_t3_lo, vget_low_s16(v_x2), (int16_t)cospi_8_64);
v_t3_hi = vmlsl_n_s16(v_t3_hi, vget_high_s16(v_x2), (int16_t)cospi_8_64);
v_t0_lo = vmulq_n_s32(v_t0_lo, cospi_16_64);
v_t0_hi = vmulq_n_s32(v_t0_hi, cospi_16_64);
v_t1_lo = vmulq_n_s32(v_t1_lo, cospi_16_64);
v_t1_hi = vmulq_n_s32(v_t1_hi, cospi_16_64);
{
const int16x4_t a = vrshrn_n_s32(v_t0_lo, DCT_CONST_BITS);
const int16x4_t b = vrshrn_n_s32(v_t0_hi, DCT_CONST_BITS);
const int16x4_t c = vrshrn_n_s32(v_t1_lo, DCT_CONST_BITS);
const int16x4_t d = vrshrn_n_s32(v_t1_hi, DCT_CONST_BITS);
const int16x4_t e = vrshrn_n_s32(v_t2_lo, DCT_CONST_BITS);
const int16x4_t f = vrshrn_n_s32(v_t2_hi, DCT_CONST_BITS);
const int16x4_t g = vrshrn_n_s32(v_t3_lo, DCT_CONST_BITS);
const int16x4_t h = vrshrn_n_s32(v_t3_hi, DCT_CONST_BITS);
out_0 = vcombine_s16(a, c); // 00 01 02 03 40 41 42 43
out_2 = vcombine_s16(e, g); // 20 21 22 23 60 61 62 63
out_4 = vcombine_s16(b, d); // 04 05 06 07 44 45 46 47
out_6 = vcombine_s16(f, h); // 24 25 26 27 64 65 66 67
}
// Stage 2
v_x0 = vsubq_s16(v_s6, v_s5);
v_x1 = vaddq_s16(v_s6, v_s5);
v_t0_lo = vmull_n_s16(vget_low_s16(v_x0), (int16_t)cospi_16_64);
v_t0_hi = vmull_n_s16(vget_high_s16(v_x0), (int16_t)cospi_16_64);
v_t1_lo = vmull_n_s16(vget_low_s16(v_x1), (int16_t)cospi_16_64);
v_t1_hi = vmull_n_s16(vget_high_s16(v_x1), (int16_t)cospi_16_64);
{
const int16x4_t a = vrshrn_n_s32(v_t0_lo, DCT_CONST_BITS);
const int16x4_t b = vrshrn_n_s32(v_t0_hi, DCT_CONST_BITS);
const int16x4_t c = vrshrn_n_s32(v_t1_lo, DCT_CONST_BITS);
const int16x4_t d = vrshrn_n_s32(v_t1_hi, DCT_CONST_BITS);
const int16x8_t ab = vcombine_s16(a, b);
const int16x8_t cd = vcombine_s16(c, d);
// Stage 3
v_x0 = vaddq_s16(v_s4, ab);
v_x1 = vsubq_s16(v_s4, ab);
v_x2 = vsubq_s16(v_s7, cd);
v_x3 = vaddq_s16(v_s7, cd);
}
// Stage 4
v_t0_lo = vmull_n_s16(vget_low_s16(v_x3), (int16_t)cospi_4_64);
v_t0_hi = vmull_n_s16(vget_high_s16(v_x3), (int16_t)cospi_4_64);
v_t0_lo = vmlal_n_s16(v_t0_lo, vget_low_s16(v_x0), (int16_t)cospi_28_64);
v_t0_hi = vmlal_n_s16(v_t0_hi, vget_high_s16(v_x0), (int16_t)cospi_28_64);
v_t1_lo = vmull_n_s16(vget_low_s16(v_x1), (int16_t)cospi_12_64);
v_t1_hi = vmull_n_s16(vget_high_s16(v_x1), (int16_t)cospi_12_64);
v_t1_lo = vmlal_n_s16(v_t1_lo, vget_low_s16(v_x2), (int16_t)cospi_20_64);
v_t1_hi = vmlal_n_s16(v_t1_hi, vget_high_s16(v_x2), (int16_t)cospi_20_64);
v_t2_lo = vmull_n_s16(vget_low_s16(v_x2), (int16_t)cospi_12_64);
v_t2_hi = vmull_n_s16(vget_high_s16(v_x2), (int16_t)cospi_12_64);
v_t2_lo = vmlsl_n_s16(v_t2_lo, vget_low_s16(v_x1), (int16_t)cospi_20_64);
v_t2_hi = vmlsl_n_s16(v_t2_hi, vget_high_s16(v_x1), (int16_t)cospi_20_64);
v_t3_lo = vmull_n_s16(vget_low_s16(v_x3), (int16_t)cospi_28_64);
v_t3_hi = vmull_n_s16(vget_high_s16(v_x3), (int16_t)cospi_28_64);
v_t3_lo = vmlsl_n_s16(v_t3_lo, vget_low_s16(v_x0), (int16_t)cospi_4_64);
v_t3_hi = vmlsl_n_s16(v_t3_hi, vget_high_s16(v_x0), (int16_t)cospi_4_64);
{
const int16x4_t a = vrshrn_n_s32(v_t0_lo, DCT_CONST_BITS);
const int16x4_t b = vrshrn_n_s32(v_t0_hi, DCT_CONST_BITS);
const int16x4_t c = vrshrn_n_s32(v_t1_lo, DCT_CONST_BITS);
const int16x4_t d = vrshrn_n_s32(v_t1_hi, DCT_CONST_BITS);
const int16x4_t e = vrshrn_n_s32(v_t2_lo, DCT_CONST_BITS);
const int16x4_t f = vrshrn_n_s32(v_t2_hi, DCT_CONST_BITS);
const int16x4_t g = vrshrn_n_s32(v_t3_lo, DCT_CONST_BITS);
const int16x4_t h = vrshrn_n_s32(v_t3_hi, DCT_CONST_BITS);
out_1 = vcombine_s16(a, c); // 10 11 12 13 50 51 52 53
out_3 = vcombine_s16(e, g); // 30 31 32 33 70 71 72 73
out_5 = vcombine_s16(b, d); // 14 15 16 17 54 55 56 57
out_7 = vcombine_s16(f, h); // 34 35 36 37 74 75 76 77
}
// transpose 8x8
{
// 00 01 02 03 40 41 42 43
// 10 11 12 13 50 51 52 53
// 20 21 22 23 60 61 62 63
// 30 31 32 33 70 71 72 73
// 04 05 06 07 44 45 46 47
// 14 15 16 17 54 55 56 57
// 24 25 26 27 64 65 66 67
// 34 35 36 37 74 75 76 77
const int32x4x2_t r02_s32 = vtrnq_s32(vreinterpretq_s32_s16(out_0),
vreinterpretq_s32_s16(out_2));
const int32x4x2_t r13_s32 = vtrnq_s32(vreinterpretq_s32_s16(out_1),
vreinterpretq_s32_s16(out_3));
const int32x4x2_t r46_s32 = vtrnq_s32(vreinterpretq_s32_s16(out_4),
vreinterpretq_s32_s16(out_6));
const int32x4x2_t r57_s32 = vtrnq_s32(vreinterpretq_s32_s16(out_5),
vreinterpretq_s32_s16(out_7));
const int16x8x2_t r01_s16 =
vtrnq_s16(vreinterpretq_s16_s32(r02_s32.val[0]),
vreinterpretq_s16_s32(r13_s32.val[0]));
const int16x8x2_t r23_s16 =
vtrnq_s16(vreinterpretq_s16_s32(r02_s32.val[1]),
vreinterpretq_s16_s32(r13_s32.val[1]));
const int16x8x2_t r45_s16 =
vtrnq_s16(vreinterpretq_s16_s32(r46_s32.val[0]),
vreinterpretq_s16_s32(r57_s32.val[0]));
const int16x8x2_t r67_s16 =
vtrnq_s16(vreinterpretq_s16_s32(r46_s32.val[1]),
vreinterpretq_s16_s32(r57_s32.val[1]));
input_0 = r01_s16.val[0];
input_1 = r01_s16.val[1];
input_2 = r23_s16.val[0];
input_3 = r23_s16.val[1];
input_4 = r45_s16.val[0];
input_5 = r45_s16.val[1];
input_6 = r67_s16.val[0];
input_7 = r67_s16.val[1];
// 00 10 20 30 40 50 60 70
// 01 11 21 31 41 51 61 71
// 02 12 22 32 42 52 62 72
// 03 13 23 33 43 53 63 73
// 04 14 24 34 44 54 64 74
// 05 15 25 35 45 55 65 75
// 06 16 26 36 46 56 66 76
// 07 17 27 37 47 57 67 77
}
} // for
{
// from vp9_dct_sse2.c
// Post-condition (division by two)
// division of two 16 bits signed numbers using shifts
// n / 2 = (n - (n >> 15)) >> 1
const int16x8_t sign_in0 = vshrq_n_s16(input_0, 15);
const int16x8_t sign_in1 = vshrq_n_s16(input_1, 15);
const int16x8_t sign_in2 = vshrq_n_s16(input_2, 15);
const int16x8_t sign_in3 = vshrq_n_s16(input_3, 15);
const int16x8_t sign_in4 = vshrq_n_s16(input_4, 15);
const int16x8_t sign_in5 = vshrq_n_s16(input_5, 15);
const int16x8_t sign_in6 = vshrq_n_s16(input_6, 15);
const int16x8_t sign_in7 = vshrq_n_s16(input_7, 15);
input_0 = vhsubq_s16(input_0, sign_in0);
input_1 = vhsubq_s16(input_1, sign_in1);
input_2 = vhsubq_s16(input_2, sign_in2);
input_3 = vhsubq_s16(input_3, sign_in3);
input_4 = vhsubq_s16(input_4, sign_in4);
input_5 = vhsubq_s16(input_5, sign_in5);
input_6 = vhsubq_s16(input_6, sign_in6);
input_7 = vhsubq_s16(input_7, sign_in7);
// store results
vst1q_s16(&final_output[0 * 8], input_0);
vst1q_s16(&final_output[1 * 8], input_1);
vst1q_s16(&final_output[2 * 8], input_2);
vst1q_s16(&final_output[3 * 8], input_3);
vst1q_s16(&final_output[4 * 8], input_4);
vst1q_s16(&final_output[5 * 8], input_5);
vst1q_s16(&final_output[6 * 8], input_6);
vst1q_s16(&final_output[7 * 8], input_7);
}
}

View file

@ -0,0 +1,118 @@
/*
* Copyright (c) 2014 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 <arm_neon.h>
#include <math.h>
#include "vpx_mem/vpx_mem.h"
#include "vp9/common/vp9_quant_common.h"
#include "vp9/common/vp9_seg_common.h"
#include "vp9/encoder/vp9_encoder.h"
#include "vp9/encoder/vp9_quantize.h"
#include "vp9/encoder/vp9_rd.h"
void vp9_quantize_fp_neon(const int16_t *coeff_ptr, intptr_t count,
int skip_block, const int16_t *zbin_ptr,
const int16_t *round_ptr, const int16_t *quant_ptr,
const int16_t *quant_shift_ptr, int16_t *qcoeff_ptr,
int16_t *dqcoeff_ptr, const int16_t *dequant_ptr,
uint16_t *eob_ptr,
const int16_t *scan, const int16_t *iscan) {
// TODO(jingning) Decide the need of these arguments after the
// quantization process is completed.
(void)zbin_ptr;
(void)quant_shift_ptr;
(void)scan;
if (!skip_block) {
// Quantization pass: All coefficients with index >= zero_flag are
// skippable. Note: zero_flag can be zero.
int i;
const int16x8_t v_zero = vdupq_n_s16(0);
const int16x8_t v_one = vdupq_n_s16(1);
int16x8_t v_eobmax_76543210 = vdupq_n_s16(-1);
int16x8_t v_round = vmovq_n_s16(round_ptr[1]);
int16x8_t v_quant = vmovq_n_s16(quant_ptr[1]);
int16x8_t v_dequant = vmovq_n_s16(dequant_ptr[1]);
// adjust for dc
v_round = vsetq_lane_s16(round_ptr[0], v_round, 0);
v_quant = vsetq_lane_s16(quant_ptr[0], v_quant, 0);
v_dequant = vsetq_lane_s16(dequant_ptr[0], v_dequant, 0);
// process dc and the first seven ac coeffs
{
const int16x8_t v_iscan = vld1q_s16(&iscan[0]);
const int16x8_t v_coeff = vld1q_s16(&coeff_ptr[0]);
const int16x8_t v_coeff_sign = vshrq_n_s16(v_coeff, 15);
const int16x8_t v_tmp = vabaq_s16(v_round, v_coeff, v_zero);
const int32x4_t v_tmp_lo = vmull_s16(vget_low_s16(v_tmp),
vget_low_s16(v_quant));
const int32x4_t v_tmp_hi = vmull_s16(vget_high_s16(v_tmp),
vget_high_s16(v_quant));
const int16x8_t v_tmp2 = vcombine_s16(vshrn_n_s32(v_tmp_lo, 16),
vshrn_n_s32(v_tmp_hi, 16));
const uint16x8_t v_nz_mask = vceqq_s16(v_tmp2, v_zero);
const int16x8_t v_iscan_plus1 = vaddq_s16(v_iscan, v_one);
const int16x8_t v_nz_iscan = vbslq_s16(v_nz_mask, v_zero, v_iscan_plus1);
const int16x8_t v_qcoeff_a = veorq_s16(v_tmp2, v_coeff_sign);
const int16x8_t v_qcoeff = vsubq_s16(v_qcoeff_a, v_coeff_sign);
const int16x8_t v_dqcoeff = vmulq_s16(v_qcoeff, v_dequant);
v_eobmax_76543210 = vmaxq_s16(v_eobmax_76543210, v_nz_iscan);
vst1q_s16(&qcoeff_ptr[0], v_qcoeff);
vst1q_s16(&dqcoeff_ptr[0], v_dqcoeff);
v_round = vmovq_n_s16(round_ptr[1]);
v_quant = vmovq_n_s16(quant_ptr[1]);
v_dequant = vmovq_n_s16(dequant_ptr[1]);
}
// now process the rest of the ac coeffs
for (i = 8; i < count; i += 8) {
const int16x8_t v_iscan = vld1q_s16(&iscan[i]);
const int16x8_t v_coeff = vld1q_s16(&coeff_ptr[i]);
const int16x8_t v_coeff_sign = vshrq_n_s16(v_coeff, 15);
const int16x8_t v_tmp = vabaq_s16(v_round, v_coeff, v_zero);
const int32x4_t v_tmp_lo = vmull_s16(vget_low_s16(v_tmp),
vget_low_s16(v_quant));
const int32x4_t v_tmp_hi = vmull_s16(vget_high_s16(v_tmp),
vget_high_s16(v_quant));
const int16x8_t v_tmp2 = vcombine_s16(vshrn_n_s32(v_tmp_lo, 16),
vshrn_n_s32(v_tmp_hi, 16));
const uint16x8_t v_nz_mask = vceqq_s16(v_tmp2, v_zero);
const int16x8_t v_iscan_plus1 = vaddq_s16(v_iscan, v_one);
const int16x8_t v_nz_iscan = vbslq_s16(v_nz_mask, v_zero, v_iscan_plus1);
const int16x8_t v_qcoeff_a = veorq_s16(v_tmp2, v_coeff_sign);
const int16x8_t v_qcoeff = vsubq_s16(v_qcoeff_a, v_coeff_sign);
const int16x8_t v_dqcoeff = vmulq_s16(v_qcoeff, v_dequant);
v_eobmax_76543210 = vmaxq_s16(v_eobmax_76543210, v_nz_iscan);
vst1q_s16(&qcoeff_ptr[i], v_qcoeff);
vst1q_s16(&dqcoeff_ptr[i], v_dqcoeff);
}
{
const int16x4_t v_eobmax_3210 =
vmax_s16(vget_low_s16(v_eobmax_76543210),
vget_high_s16(v_eobmax_76543210));
const int64x1_t v_eobmax_xx32 =
vshr_n_s64(vreinterpret_s64_s16(v_eobmax_3210), 32);
const int16x4_t v_eobmax_tmp =
vmax_s16(v_eobmax_3210, vreinterpret_s16_s64(v_eobmax_xx32));
const int64x1_t v_eobmax_xxx3 =
vshr_n_s64(vreinterpret_s64_s16(v_eobmax_tmp), 16);
const int16x4_t v_eobmax_final =
vmax_s16(v_eobmax_tmp, vreinterpret_s16_s64(v_eobmax_xxx3));
*eob_ptr = (uint16_t)vget_lane_s16(v_eobmax_final, 0);
}
} else {
memset(qcoeff_ptr, 0, count * sizeof(int16_t));
memset(dqcoeff_ptr, 0, count * sizeof(int16_t));
*eob_ptr = 0;
}
}

View file

@ -0,0 +1,81 @@
/*
* Copyright (c) 2014 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 <arm_neon.h>
#include "./vp9_rtcd.h"
#include "./vpx_config.h"
#include "vpx/vpx_integer.h"
void vp9_subtract_block_neon(int rows, int cols,
int16_t *diff, ptrdiff_t diff_stride,
const uint8_t *src, ptrdiff_t src_stride,
const uint8_t *pred, ptrdiff_t pred_stride) {
int r, c;
if (cols > 16) {
for (r = 0; r < rows; ++r) {
for (c = 0; c < cols; c += 32) {
const uint8x16_t v_src_00 = vld1q_u8(&src[c + 0]);
const uint8x16_t v_src_16 = vld1q_u8(&src[c + 16]);
const uint8x16_t v_pred_00 = vld1q_u8(&pred[c + 0]);
const uint8x16_t v_pred_16 = vld1q_u8(&pred[c + 16]);
const uint16x8_t v_diff_lo_00 = vsubl_u8(vget_low_u8(v_src_00),
vget_low_u8(v_pred_00));
const uint16x8_t v_diff_hi_00 = vsubl_u8(vget_high_u8(v_src_00),
vget_high_u8(v_pred_00));
const uint16x8_t v_diff_lo_16 = vsubl_u8(vget_low_u8(v_src_16),
vget_low_u8(v_pred_16));
const uint16x8_t v_diff_hi_16 = vsubl_u8(vget_high_u8(v_src_16),
vget_high_u8(v_pred_16));
vst1q_s16(&diff[c + 0], vreinterpretq_s16_u16(v_diff_lo_00));
vst1q_s16(&diff[c + 8], vreinterpretq_s16_u16(v_diff_hi_00));
vst1q_s16(&diff[c + 16], vreinterpretq_s16_u16(v_diff_lo_16));
vst1q_s16(&diff[c + 24], vreinterpretq_s16_u16(v_diff_hi_16));
}
diff += diff_stride;
pred += pred_stride;
src += src_stride;
}
} else if (cols > 8) {
for (r = 0; r < rows; ++r) {
const uint8x16_t v_src = vld1q_u8(&src[0]);
const uint8x16_t v_pred = vld1q_u8(&pred[0]);
const uint16x8_t v_diff_lo = vsubl_u8(vget_low_u8(v_src),
vget_low_u8(v_pred));
const uint16x8_t v_diff_hi = vsubl_u8(vget_high_u8(v_src),
vget_high_u8(v_pred));
vst1q_s16(&diff[0], vreinterpretq_s16_u16(v_diff_lo));
vst1q_s16(&diff[8], vreinterpretq_s16_u16(v_diff_hi));
diff += diff_stride;
pred += pred_stride;
src += src_stride;
}
} else if (cols > 4) {
for (r = 0; r < rows; ++r) {
const uint8x8_t v_src = vld1_u8(&src[0]);
const uint8x8_t v_pred = vld1_u8(&pred[0]);
const uint16x8_t v_diff = vsubl_u8(v_src, v_pred);
vst1q_s16(&diff[0], vreinterpretq_s16_u16(v_diff));
diff += diff_stride;
pred += pred_stride;
src += src_stride;
}
} else {
for (r = 0; r < rows; ++r) {
for (c = 0; c < cols; ++c)
diff[c] = src[c] - pred[c];
diff += diff_stride;
pred += pred_stride;
src += src_stride;
}
}
}

View file

@ -0,0 +1,153 @@
/*
* Copyright (c) 2014 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 <arm_neon.h>
#include "./vp9_rtcd.h"
#include "./vpx_dsp_rtcd.h"
#include "./vpx_config.h"
#include "vpx_ports/mem.h"
#include "vpx/vpx_integer.h"
#include "vp9/common/vp9_filter.h"
static uint8_t bilinear_filters[8][2] = {
{ 128, 0, },
{ 112, 16, },
{ 96, 32, },
{ 80, 48, },
{ 64, 64, },
{ 48, 80, },
{ 32, 96, },
{ 16, 112, },
};
static void var_filter_block2d_bil_w8(const uint8_t *src_ptr,
uint8_t *output_ptr,
unsigned int src_pixels_per_line,
int pixel_step,
unsigned int output_height,
unsigned int output_width,
const uint8_t *vp9_filter) {
const uint8x8_t f0 = vmov_n_u8(vp9_filter[0]);
const uint8x8_t f1 = vmov_n_u8(vp9_filter[1]);
unsigned int i;
for (i = 0; i < output_height; ++i) {
const uint8x8_t src_0 = vld1_u8(&src_ptr[0]);
const uint8x8_t src_1 = vld1_u8(&src_ptr[pixel_step]);
const uint16x8_t a = vmull_u8(src_0, f0);
const uint16x8_t b = vmlal_u8(a, src_1, f1);
const uint8x8_t out = vrshrn_n_u16(b, FILTER_BITS);
vst1_u8(&output_ptr[0], out);
// Next row...
src_ptr += src_pixels_per_line;
output_ptr += output_width;
}
}
static void var_filter_block2d_bil_w16(const uint8_t *src_ptr,
uint8_t *output_ptr,
unsigned int src_pixels_per_line,
int pixel_step,
unsigned int output_height,
unsigned int output_width,
const uint8_t *vp9_filter) {
const uint8x8_t f0 = vmov_n_u8(vp9_filter[0]);
const uint8x8_t f1 = vmov_n_u8(vp9_filter[1]);
unsigned int i, j;
for (i = 0; i < output_height; ++i) {
for (j = 0; j < output_width; j += 16) {
const uint8x16_t src_0 = vld1q_u8(&src_ptr[j]);
const uint8x16_t src_1 = vld1q_u8(&src_ptr[j + pixel_step]);
const uint16x8_t a = vmull_u8(vget_low_u8(src_0), f0);
const uint16x8_t b = vmlal_u8(a, vget_low_u8(src_1), f1);
const uint8x8_t out_lo = vrshrn_n_u16(b, FILTER_BITS);
const uint16x8_t c = vmull_u8(vget_high_u8(src_0), f0);
const uint16x8_t d = vmlal_u8(c, vget_high_u8(src_1), f1);
const uint8x8_t out_hi = vrshrn_n_u16(d, FILTER_BITS);
vst1q_u8(&output_ptr[j], vcombine_u8(out_lo, out_hi));
}
// Next row...
src_ptr += src_pixels_per_line;
output_ptr += output_width;
}
}
unsigned int vp9_sub_pixel_variance8x8_neon(const uint8_t *src,
int src_stride,
int xoffset,
int yoffset,
const uint8_t *dst,
int dst_stride,
unsigned int *sse) {
DECLARE_ALIGNED(16, uint8_t, temp2[8 * 8]);
DECLARE_ALIGNED(16, uint8_t, fdata3[9 * 8]);
var_filter_block2d_bil_w8(src, fdata3, src_stride, 1,
9, 8,
bilinear_filters[xoffset]);
var_filter_block2d_bil_w8(fdata3, temp2, 8, 8, 8,
8, bilinear_filters[yoffset]);
return vpx_variance8x8_neon(temp2, 8, dst, dst_stride, sse);
}
unsigned int vp9_sub_pixel_variance16x16_neon(const uint8_t *src,
int src_stride,
int xoffset,
int yoffset,
const uint8_t *dst,
int dst_stride,
unsigned int *sse) {
DECLARE_ALIGNED(16, uint8_t, temp2[16 * 16]);
DECLARE_ALIGNED(16, uint8_t, fdata3[17 * 16]);
var_filter_block2d_bil_w16(src, fdata3, src_stride, 1,
17, 16,
bilinear_filters[xoffset]);
var_filter_block2d_bil_w16(fdata3, temp2, 16, 16, 16,
16, bilinear_filters[yoffset]);
return vpx_variance16x16_neon(temp2, 16, dst, dst_stride, sse);
}
unsigned int vp9_sub_pixel_variance32x32_neon(const uint8_t *src,
int src_stride,
int xoffset,
int yoffset,
const uint8_t *dst,
int dst_stride,
unsigned int *sse) {
DECLARE_ALIGNED(16, uint8_t, temp2[32 * 32]);
DECLARE_ALIGNED(16, uint8_t, fdata3[33 * 32]);
var_filter_block2d_bil_w16(src, fdata3, src_stride, 1,
33, 32,
bilinear_filters[xoffset]);
var_filter_block2d_bil_w16(fdata3, temp2, 32, 32, 32,
32, bilinear_filters[yoffset]);
return vpx_variance32x32_neon(temp2, 32, dst, dst_stride, sse);
}
unsigned int vp9_sub_pixel_variance64x64_neon(const uint8_t *src,
int src_stride,
int xoffset,
int yoffset,
const uint8_t *dst,
int dst_stride,
unsigned int *sse) {
DECLARE_ALIGNED(16, uint8_t, temp2[64 * 64]);
DECLARE_ALIGNED(16, uint8_t, fdata3[65 * 64]);
var_filter_block2d_bil_w16(src, fdata3, src_stride, 1,
65, 64,
bilinear_filters[xoffset]);
var_filter_block2d_bil_w16(fdata3, temp2, 64, 64, 64,
64, bilinear_filters[yoffset]);
return vpx_variance64x64_neon(temp2, 64, dst, dst_stride, sse);
}

View file

@ -0,0 +1,49 @@
/*
* Copyright (c) 2015 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 <arm_neon.h>
#include "./vp9_rtcd.h"
#include "./vpx_config.h"
#include "vpx/vpx_integer.h"
static INLINE unsigned int horizontal_add_u16x8(const uint16x8_t v_16x8) {
const uint32x4_t a = vpaddlq_u16(v_16x8);
const uint64x2_t b = vpaddlq_u32(a);
const uint32x2_t c = vadd_u32(vreinterpret_u32_u64(vget_low_u64(b)),
vreinterpret_u32_u64(vget_high_u64(b)));
return vget_lane_u32(c, 0);
}
unsigned int vp9_avg_8x8_neon(const uint8_t *s, int p) {
uint8x8_t v_s0 = vld1_u8(s);
const uint8x8_t v_s1 = vld1_u8(s + p);
uint16x8_t v_sum = vaddl_u8(v_s0, v_s1);
v_s0 = vld1_u8(s + 2 * p);
v_sum = vaddw_u8(v_sum, v_s0);
v_s0 = vld1_u8(s + 3 * p);
v_sum = vaddw_u8(v_sum, v_s0);
v_s0 = vld1_u8(s + 4 * p);
v_sum = vaddw_u8(v_sum, v_s0);
v_s0 = vld1_u8(s + 5 * p);
v_sum = vaddw_u8(v_sum, v_s0);
v_s0 = vld1_u8(s + 6 * p);
v_sum = vaddw_u8(v_sum, v_s0);
v_s0 = vld1_u8(s + 7 * p);
v_sum = vaddw_u8(v_sum, v_s0);
return (horizontal_add_u16x8(v_sum) + 32) >> 6;
}

View file

@ -0,0 +1,163 @@
/*
* Copyright (c) 2014 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <limits.h>
#include <math.h>
#include "vp9/encoder/vp9_aq_complexity.h"
#include "vp9/encoder/vp9_aq_variance.h"
#include "vp9/encoder/vp9_encodeframe.h"
#include "vp9/common/vp9_seg_common.h"
#include "vp9/encoder/vp9_segmentation.h"
#define AQ_C_SEGMENTS 5
#define DEFAULT_AQ2_SEG 3 // Neutral Q segment
#define AQ_C_STRENGTHS 3
static const double aq_c_q_adj_factor[AQ_C_STRENGTHS][AQ_C_SEGMENTS] =
{ {1.75, 1.25, 1.05, 1.00, 0.90},
{2.00, 1.50, 1.15, 1.00, 0.85},
{2.50, 1.75, 1.25, 1.00, 0.80} };
static const double aq_c_transitions[AQ_C_STRENGTHS][AQ_C_SEGMENTS] =
{ {0.15, 0.30, 0.55, 2.00, 100.0},
{0.20, 0.40, 0.65, 2.00, 100.0},
{0.25, 0.50, 0.75, 2.00, 100.0} };
static const double aq_c_var_thresholds[AQ_C_STRENGTHS][AQ_C_SEGMENTS] =
{ {-4.0, -3.0, -2.0, 100.00, 100.0},
{-3.5, -2.5, -1.5, 100.00, 100.0},
{-3.0, -2.0, -1.0, 100.00, 100.0} };
#define DEFAULT_COMPLEXITY 64
static int get_aq_c_strength(int q_index, vpx_bit_depth_t bit_depth) {
// Approximate base quatizer (truncated to int)
const int base_quant = vp9_ac_quant(q_index, 0, bit_depth) / 4;
return (base_quant > 10) + (base_quant > 25);
}
void vp9_setup_in_frame_q_adj(VP9_COMP *cpi) {
VP9_COMMON *const cm = &cpi->common;
struct segmentation *const seg = &cm->seg;
// Make SURE use of floating point in this function is safe.
vp9_clear_system_state();
if (cm->frame_type == KEY_FRAME ||
cpi->refresh_alt_ref_frame ||
(cpi->refresh_golden_frame && !cpi->rc.is_src_frame_alt_ref)) {
int segment;
const int aq_strength = get_aq_c_strength(cm->base_qindex, cm->bit_depth);
// Clear down the segment map.
memset(cpi->segmentation_map, DEFAULT_AQ2_SEG, cm->mi_rows * cm->mi_cols);
vp9_clearall_segfeatures(seg);
// Segmentation only makes sense if the target bits per SB is above a
// threshold. Below this the overheads will usually outweigh any benefit.
if (cpi->rc.sb64_target_rate < 256) {
vp9_disable_segmentation(seg);
return;
}
vp9_enable_segmentation(seg);
// Select delta coding method.
seg->abs_delta = SEGMENT_DELTADATA;
// Default segment "Q" feature is disabled so it defaults to the baseline Q.
vp9_disable_segfeature(seg, DEFAULT_AQ2_SEG, SEG_LVL_ALT_Q);
// Use some of the segments for in frame Q adjustment.
for (segment = 0; segment < AQ_C_SEGMENTS; ++segment) {
int qindex_delta;
if (segment == DEFAULT_AQ2_SEG)
continue;
qindex_delta =
vp9_compute_qdelta_by_rate(&cpi->rc, cm->frame_type, cm->base_qindex,
aq_c_q_adj_factor[aq_strength][segment],
cm->bit_depth);
// For AQ complexity mode, we dont allow Q0 in a segment if the base
// Q is not 0. Q0 (lossless) implies 4x4 only and in AQ mode 2 a segment
// Q delta is sometimes applied without going back around the rd loop.
// This could lead to an illegal combination of partition size and q.
if ((cm->base_qindex != 0) && ((cm->base_qindex + qindex_delta) == 0)) {
qindex_delta = -cm->base_qindex + 1;
}
if ((cm->base_qindex + qindex_delta) > 0) {
vp9_enable_segfeature(seg, segment, SEG_LVL_ALT_Q);
vp9_set_segdata(seg, segment, SEG_LVL_ALT_Q, qindex_delta);
}
}
}
}
#define DEFAULT_LV_THRESH 10.0
#define MIN_DEFAULT_LV_THRESH 8.0
#define VAR_STRENGTH_STEP 0.25
// Select a segment for the current block.
// The choice of segment for a block depends on the ratio of the projected
// bits for the block vs a target average and its spatial complexity.
void vp9_caq_select_segment(VP9_COMP *cpi, MACROBLOCK *mb, BLOCK_SIZE bs,
int mi_row, int mi_col, int projected_rate) {
VP9_COMMON *const cm = &cpi->common;
const int mi_offset = mi_row * cm->mi_cols + mi_col;
const int bw = num_8x8_blocks_wide_lookup[BLOCK_64X64];
const int bh = num_8x8_blocks_high_lookup[BLOCK_64X64];
const int xmis = MIN(cm->mi_cols - mi_col, num_8x8_blocks_wide_lookup[bs]);
const int ymis = MIN(cm->mi_rows - mi_row, num_8x8_blocks_high_lookup[bs]);
int x, y;
int i;
unsigned char segment;
if (0) {
segment = DEFAULT_AQ2_SEG;
} else {
// Rate depends on fraction of a SB64 in frame (xmis * ymis / bw * bh).
// It is converted to bits * 256 units.
const int target_rate = (cpi->rc.sb64_target_rate * xmis * ymis * 256) /
(bw * bh);
double logvar;
double low_var_thresh;
const int aq_strength = get_aq_c_strength(cm->base_qindex, cm->bit_depth);
vp9_clear_system_state();
low_var_thresh = (cpi->oxcf.pass == 2)
? MAX(cpi->twopass.mb_av_energy, MIN_DEFAULT_LV_THRESH)
: DEFAULT_LV_THRESH;
vp9_setup_src_planes(mb, cpi->Source, mi_row, mi_col);
logvar = vp9_log_block_var(cpi, mb, bs);
segment = AQ_C_SEGMENTS - 1; // Just in case no break out below.
for (i = 0; i < AQ_C_SEGMENTS; ++i) {
// Test rate against a threshold value and variance against a threshold.
// Increasing segment number (higher variance and complexity) = higher Q.
if ((projected_rate <
target_rate * aq_c_transitions[aq_strength][i]) &&
(logvar < (low_var_thresh + aq_c_var_thresholds[aq_strength][i]))) {
segment = i;
break;
}
}
}
// Fill in the entires in the segment map corresponding to this SB64.
for (y = 0; y < ymis; y++) {
for (x = 0; x < xmis; x++) {
cpi->segmentation_map[mi_offset + y * cm->mi_cols + x] = segment;
}
}
}

View file

@ -0,0 +1,37 @@
/*
* Copyright (c) 2014 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.
*/
#ifndef VP9_ENCODER_VP9_AQ_COMPLEXITY_H_
#define VP9_ENCODER_VP9_AQ_COMPLEXITY_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "vp9/common/vp9_enums.h"
struct VP9_COMP;
struct macroblock;
// Select a segment for the current Block.
void vp9_caq_select_segment(struct VP9_COMP *cpi, struct macroblock *,
BLOCK_SIZE bs,
int mi_row, int mi_col, int projected_rate);
// This function sets up a set of segments with delta Q values around
// the baseline frame quantizer.
void vp9_setup_in_frame_q_adj(struct VP9_COMP *cpi);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // VP9_ENCODER_VP9_AQ_COMPLEXITY_H_

View file

@ -0,0 +1,519 @@
/*
* Copyright (c) 2014 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <limits.h>
#include <math.h>
#include "vp9/encoder/vp9_aq_cyclicrefresh.h"
#include "vp9/common/vp9_seg_common.h"
#include "vp9/encoder/vp9_ratectrl.h"
#include "vp9/encoder/vp9_segmentation.h"
struct CYCLIC_REFRESH {
// Percentage of blocks per frame that are targeted as candidates
// for cyclic refresh.
int percent_refresh;
// Maximum q-delta as percentage of base q.
int max_qdelta_perc;
// Superblock starting index for cycling through the frame.
int sb_index;
// Controls how long block will need to wait to be refreshed again, in
// excess of the cycle time, i.e., in the case of all zero motion, block
// will be refreshed every (100/percent_refresh + time_for_refresh) frames.
int time_for_refresh;
// Target number of (8x8) blocks that are set for delta-q.
int target_num_seg_blocks;
// Actual number of (8x8) blocks that were applied delta-q.
int actual_num_seg1_blocks;
int actual_num_seg2_blocks;
// RD mult. parameters for segment 1.
int rdmult;
// Cyclic refresh map.
signed char *map;
// Thresholds applied to the projected rate/distortion of the coding block,
// when deciding whether block should be refreshed.
int64_t thresh_rate_sb;
int64_t thresh_dist_sb;
// Threshold applied to the motion vector (in units of 1/8 pel) of the
// coding block, when deciding whether block should be refreshed.
int16_t motion_thresh;
// Rate target ratio to set q delta.
double rate_ratio_qdelta;
double low_content_avg;
int qindex_delta_seg1;
int qindex_delta_seg2;
};
CYCLIC_REFRESH *vp9_cyclic_refresh_alloc(int mi_rows, int mi_cols) {
CYCLIC_REFRESH *const cr = vpx_calloc(1, sizeof(*cr));
if (cr == NULL)
return NULL;
cr->map = vpx_calloc(mi_rows * mi_cols, sizeof(*cr->map));
if (cr->map == NULL) {
vpx_free(cr);
return NULL;
}
return cr;
}
void vp9_cyclic_refresh_free(CYCLIC_REFRESH *cr) {
vpx_free(cr->map);
vpx_free(cr);
}
// Check if we should turn off cyclic refresh based on bitrate condition.
static int apply_cyclic_refresh_bitrate(const VP9_COMMON *cm,
const RATE_CONTROL *rc) {
// Turn off cyclic refresh if bits available per frame is not sufficiently
// larger than bit cost of segmentation. Segment map bit cost should scale
// with number of seg blocks, so compare available bits to number of blocks.
// Average bits available per frame = avg_frame_bandwidth
// Number of (8x8) blocks in frame = mi_rows * mi_cols;
const float factor = 0.25;
const int number_blocks = cm->mi_rows * cm->mi_cols;
// The condition below corresponds to turning off at target bitrates:
// (at 30fps), ~12kbps for CIF, 36kbps for VGA, 100kps for HD/720p.
// Also turn off at very small frame sizes, to avoid too large fraction of
// superblocks to be refreshed per frame. Threshold below is less than QCIF.
if (rc->avg_frame_bandwidth < factor * number_blocks ||
number_blocks / 64 < 5)
return 0;
else
return 1;
}
// Check if this coding block, of size bsize, should be considered for refresh
// (lower-qp coding). Decision can be based on various factors, such as
// size of the coding block (i.e., below min_block size rejected), coding
// mode, and rate/distortion.
static int candidate_refresh_aq(const CYCLIC_REFRESH *cr,
const MB_MODE_INFO *mbmi,
int64_t rate,
int64_t dist,
int bsize) {
MV mv = mbmi->mv[0].as_mv;
// Reject the block for lower-qp coding if projected distortion
// is above the threshold, and any of the following is true:
// 1) mode uses large mv
// 2) mode is an intra-mode
// Otherwise accept for refresh.
if (dist > cr->thresh_dist_sb &&
(mv.row > cr->motion_thresh || mv.row < -cr->motion_thresh ||
mv.col > cr->motion_thresh || mv.col < -cr->motion_thresh ||
!is_inter_block(mbmi)))
return CR_SEGMENT_ID_BASE;
else if (bsize >= BLOCK_16X16 &&
rate < cr->thresh_rate_sb &&
is_inter_block(mbmi) &&
mbmi->mv[0].as_int == 0)
// More aggressive delta-q for bigger blocks with zero motion.
return CR_SEGMENT_ID_BOOST2;
else
return CR_SEGMENT_ID_BOOST1;
}
// Compute delta-q for the segment.
static int compute_deltaq(const VP9_COMP *cpi, int q, double rate_factor) {
const CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
const RATE_CONTROL *const rc = &cpi->rc;
int deltaq = vp9_compute_qdelta_by_rate(rc, cpi->common.frame_type,
q, rate_factor,
cpi->common.bit_depth);
if ((-deltaq) > cr->max_qdelta_perc * q / 100) {
deltaq = -cr->max_qdelta_perc * q / 100;
}
return deltaq;
}
// For the just encoded frame, estimate the bits, incorporating the delta-q
// from non-base segment. For now ignore effect of multiple segments
// (with different delta-q). Note this function is called in the postencode
// (called from rc_update_rate_correction_factors()).
int vp9_cyclic_refresh_estimate_bits_at_q(const VP9_COMP *cpi,
double correction_factor) {
const VP9_COMMON *const cm = &cpi->common;
const CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
int estimated_bits;
int mbs = cm->MBs;
int num8x8bl = mbs << 2;
// Weight for non-base segments: use actual number of blocks refreshed in
// previous/just encoded frame. Note number of blocks here is in 8x8 units.
double weight_segment1 = (double)cr->actual_num_seg1_blocks / num8x8bl;
double weight_segment2 = (double)cr->actual_num_seg2_blocks / num8x8bl;
// Take segment weighted average for estimated bits.
estimated_bits = (int)((1.0 - weight_segment1 - weight_segment2) *
vp9_estimate_bits_at_q(cm->frame_type, cm->base_qindex, mbs,
correction_factor, cm->bit_depth) +
weight_segment1 *
vp9_estimate_bits_at_q(cm->frame_type,
cm->base_qindex + cr->qindex_delta_seg1, mbs,
correction_factor, cm->bit_depth) +
weight_segment2 *
vp9_estimate_bits_at_q(cm->frame_type,
cm->base_qindex + cr->qindex_delta_seg2, mbs,
correction_factor, cm->bit_depth));
return estimated_bits;
}
// Prior to encoding the frame, estimate the bits per mb, for a given q = i and
// a corresponding delta-q (for segment 1). This function is called in the
// rc_regulate_q() to set the base qp index.
// Note: the segment map is set to either 0/CR_SEGMENT_ID_BASE (no refresh) or
// to 1/CR_SEGMENT_ID_BOOST1 (refresh) for each superblock, prior to encoding.
int vp9_cyclic_refresh_rc_bits_per_mb(const VP9_COMP *cpi, int i,
double correction_factor) {
const VP9_COMMON *const cm = &cpi->common;
CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
int bits_per_mb;
int num8x8bl = cm->MBs << 2;
// Weight for segment prior to encoding: take the average of the target
// number for the frame to be encoded and the actual from the previous frame.
double weight_segment = (double)((cr->target_num_seg_blocks +
cr->actual_num_seg1_blocks + cr->actual_num_seg2_blocks) >> 1) /
num8x8bl;
// Compute delta-q corresponding to qindex i.
int deltaq = compute_deltaq(cpi, i, cr->rate_ratio_qdelta);
// Take segment weighted average for bits per mb.
bits_per_mb = (int)((1.0 - weight_segment) *
vp9_rc_bits_per_mb(cm->frame_type, i, correction_factor, cm->bit_depth) +
weight_segment *
vp9_rc_bits_per_mb(cm->frame_type, i + deltaq, correction_factor,
cm->bit_depth));
return bits_per_mb;
}
// Prior to coding a given prediction block, of size bsize at (mi_row, mi_col),
// check if we should reset the segment_id, and update the cyclic_refresh map
// and segmentation map.
void vp9_cyclic_refresh_update_segment(VP9_COMP *const cpi,
MB_MODE_INFO *const mbmi,
int mi_row, int mi_col,
BLOCK_SIZE bsize,
int64_t rate,
int64_t dist,
int skip) {
const VP9_COMMON *const cm = &cpi->common;
CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
const int bw = num_8x8_blocks_wide_lookup[bsize];
const int bh = num_8x8_blocks_high_lookup[bsize];
const int xmis = MIN(cm->mi_cols - mi_col, bw);
const int ymis = MIN(cm->mi_rows - mi_row, bh);
const int block_index = mi_row * cm->mi_cols + mi_col;
const int refresh_this_block = candidate_refresh_aq(cr, mbmi, rate, dist,
bsize);
// Default is to not update the refresh map.
int new_map_value = cr->map[block_index];
int x = 0; int y = 0;
// If this block is labeled for refresh, check if we should reset the
// segment_id.
if (cyclic_refresh_segment_id_boosted(mbmi->segment_id)) {
mbmi->segment_id = refresh_this_block;
// Reset segment_id if will be skipped.
if (skip)
mbmi->segment_id = CR_SEGMENT_ID_BASE;
}
// Update the cyclic refresh map, to be used for setting segmentation map
// for the next frame. If the block will be refreshed this frame, mark it
// as clean. The magnitude of the -ve influences how long before we consider
// it for refresh again.
if (cyclic_refresh_segment_id_boosted(mbmi->segment_id)) {
new_map_value = -cr->time_for_refresh;
} else if (refresh_this_block) {
// Else if it is accepted as candidate for refresh, and has not already
// been refreshed (marked as 1) then mark it as a candidate for cleanup
// for future time (marked as 0), otherwise don't update it.
if (cr->map[block_index] == 1)
new_map_value = 0;
} else {
// Leave it marked as block that is not candidate for refresh.
new_map_value = 1;
}
// Update entries in the cyclic refresh map with new_map_value, and
// copy mbmi->segment_id into global segmentation map.
for (y = 0; y < ymis; y++)
for (x = 0; x < xmis; x++) {
cr->map[block_index + y * cm->mi_cols + x] = new_map_value;
cpi->segmentation_map[block_index + y * cm->mi_cols + x] =
mbmi->segment_id;
}
}
// Update the actual number of blocks that were applied the segment delta q.
void vp9_cyclic_refresh_postencode(VP9_COMP *const cpi) {
VP9_COMMON *const cm = &cpi->common;
CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
unsigned char *const seg_map = cpi->segmentation_map;
int mi_row, mi_col;
cr->actual_num_seg1_blocks = 0;
cr->actual_num_seg2_blocks = 0;
for (mi_row = 0; mi_row < cm->mi_rows; mi_row++)
for (mi_col = 0; mi_col < cm->mi_cols; mi_col++) {
if (cyclic_refresh_segment_id(
seg_map[mi_row * cm->mi_cols + mi_col]) == CR_SEGMENT_ID_BOOST1)
cr->actual_num_seg1_blocks++;
else if (cyclic_refresh_segment_id(
seg_map[mi_row * cm->mi_cols + mi_col]) == CR_SEGMENT_ID_BOOST2)
cr->actual_num_seg2_blocks++;
}
}
// Set golden frame update interval, for non-svc 1 pass CBR mode.
void vp9_cyclic_refresh_set_golden_update(VP9_COMP *const cpi) {
RATE_CONTROL *const rc = &cpi->rc;
CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
// Set minimum gf_interval for GF update to a multiple (== 2) of refresh
// period. Depending on past encoding stats, GF flag may be reset and update
// may not occur until next baseline_gf_interval.
if (cr->percent_refresh > 0)
rc->baseline_gf_interval = 4 * (100 / cr->percent_refresh);
else
rc->baseline_gf_interval = 40;
}
// Update some encoding stats (from the just encoded frame). If this frame's
// background has high motion, refresh the golden frame. Otherwise, if the
// golden reference is to be updated check if we should NOT update the golden
// ref.
void vp9_cyclic_refresh_check_golden_update(VP9_COMP *const cpi) {
VP9_COMMON *const cm = &cpi->common;
CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
int mi_row, mi_col;
double fraction_low = 0.0;
int low_content_frame = 0;
MODE_INFO **mi = cm->mi_grid_visible;
RATE_CONTROL *const rc = &cpi->rc;
const int rows = cm->mi_rows, cols = cm->mi_cols;
int cnt1 = 0, cnt2 = 0;
int force_gf_refresh = 0;
for (mi_row = 0; mi_row < rows; mi_row++) {
for (mi_col = 0; mi_col < cols; mi_col++) {
int16_t abs_mvr = mi[0]->mbmi.mv[0].as_mv.row >= 0 ?
mi[0]->mbmi.mv[0].as_mv.row : -1 * mi[0]->mbmi.mv[0].as_mv.row;
int16_t abs_mvc = mi[0]->mbmi.mv[0].as_mv.col >= 0 ?
mi[0]->mbmi.mv[0].as_mv.col : -1 * mi[0]->mbmi.mv[0].as_mv.col;
// Calculate the motion of the background.
if (abs_mvr <= 16 && abs_mvc <= 16) {
cnt1++;
if (abs_mvr == 0 && abs_mvc == 0)
cnt2++;
}
mi++;
// Accumulate low_content_frame.
if (cr->map[mi_row * cols + mi_col] < 1)
low_content_frame++;
}
mi += 8;
}
// For video conference clips, if the background has high motion in current
// frame because of the camera movement, set this frame as the golden frame.
// Use 70% and 5% as the thresholds for golden frame refreshing.
if (cnt1 * 10 > (70 * rows * cols) && cnt2 * 20 < cnt1) {
vp9_cyclic_refresh_set_golden_update(cpi);
rc->frames_till_gf_update_due = rc->baseline_gf_interval;
if (rc->frames_till_gf_update_due > rc->frames_to_key)
rc->frames_till_gf_update_due = rc->frames_to_key;
cpi->refresh_golden_frame = 1;
force_gf_refresh = 1;
}
fraction_low =
(double)low_content_frame / (rows * cols);
// Update average.
cr->low_content_avg = (fraction_low + 3 * cr->low_content_avg) / 4;
if (!force_gf_refresh && cpi->refresh_golden_frame == 1) {
// Don't update golden reference if the amount of low_content for the
// current encoded frame is small, or if the recursive average of the
// low_content over the update interval window falls below threshold.
if (fraction_low < 0.8 || cr->low_content_avg < 0.7)
cpi->refresh_golden_frame = 0;
// Reset for next internal.
cr->low_content_avg = fraction_low;
}
}
// Update the segmentation map, and related quantities: cyclic refresh map,
// refresh sb_index, and target number of blocks to be refreshed.
// The map is set to either 0/CR_SEGMENT_ID_BASE (no refresh) or to
// 1/CR_SEGMENT_ID_BOOST1 (refresh) for each superblock.
// Blocks labeled as BOOST1 may later get set to BOOST2 (during the
// encoding of the superblock).
static void cyclic_refresh_update_map(VP9_COMP *const cpi) {
VP9_COMMON *const cm = &cpi->common;
CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
unsigned char *const seg_map = cpi->segmentation_map;
int i, block_count, bl_index, sb_rows, sb_cols, sbs_in_frame;
int xmis, ymis, x, y;
memset(seg_map, CR_SEGMENT_ID_BASE, cm->mi_rows * cm->mi_cols);
sb_cols = (cm->mi_cols + MI_BLOCK_SIZE - 1) / MI_BLOCK_SIZE;
sb_rows = (cm->mi_rows + MI_BLOCK_SIZE - 1) / MI_BLOCK_SIZE;
sbs_in_frame = sb_cols * sb_rows;
// Number of target blocks to get the q delta (segment 1).
block_count = cr->percent_refresh * cm->mi_rows * cm->mi_cols / 100;
// Set the segmentation map: cycle through the superblocks, starting at
// cr->mb_index, and stopping when either block_count blocks have been found
// to be refreshed, or we have passed through whole frame.
assert(cr->sb_index < sbs_in_frame);
i = cr->sb_index;
cr->target_num_seg_blocks = 0;
do {
int sum_map = 0;
// Get the mi_row/mi_col corresponding to superblock index i.
int sb_row_index = (i / sb_cols);
int sb_col_index = i - sb_row_index * sb_cols;
int mi_row = sb_row_index * MI_BLOCK_SIZE;
int mi_col = sb_col_index * MI_BLOCK_SIZE;
assert(mi_row >= 0 && mi_row < cm->mi_rows);
assert(mi_col >= 0 && mi_col < cm->mi_cols);
bl_index = mi_row * cm->mi_cols + mi_col;
// Loop through all 8x8 blocks in superblock and update map.
xmis = MIN(cm->mi_cols - mi_col,
num_8x8_blocks_wide_lookup[BLOCK_64X64]);
ymis = MIN(cm->mi_rows - mi_row,
num_8x8_blocks_high_lookup[BLOCK_64X64]);
for (y = 0; y < ymis; y++) {
for (x = 0; x < xmis; x++) {
const int bl_index2 = bl_index + y * cm->mi_cols + x;
// If the block is as a candidate for clean up then mark it
// for possible boost/refresh (segment 1). The segment id may get
// reset to 0 later if block gets coded anything other than ZEROMV.
if (cr->map[bl_index2] == 0) {
sum_map++;
} else if (cr->map[bl_index2] < 0) {
cr->map[bl_index2]++;
}
}
}
// Enforce constant segment over superblock.
// If segment is at least half of superblock, set to 1.
if (sum_map >= xmis * ymis / 2) {
for (y = 0; y < ymis; y++)
for (x = 0; x < xmis; x++) {
seg_map[bl_index + y * cm->mi_cols + x] = CR_SEGMENT_ID_BOOST1;
}
cr->target_num_seg_blocks += xmis * ymis;
}
i++;
if (i == sbs_in_frame) {
i = 0;
}
} while (cr->target_num_seg_blocks < block_count && i != cr->sb_index);
cr->sb_index = i;
}
// Set/update global/frame level cyclic refresh parameters.
void vp9_cyclic_refresh_update_parameters(VP9_COMP *const cpi) {
const RATE_CONTROL *const rc = &cpi->rc;
CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
cr->percent_refresh = 10;
// Use larger delta-qp (increase rate_ratio_qdelta) for first few (~4)
// periods of the refresh cycle, after a key frame. This corresponds to ~40
// frames with cr->percent_refresh = 10.
if (rc->frames_since_key < 40)
cr->rate_ratio_qdelta = 3.0;
else
cr->rate_ratio_qdelta = 2.0;
}
// Setup cyclic background refresh: set delta q and segmentation map.
void vp9_cyclic_refresh_setup(VP9_COMP *const cpi) {
VP9_COMMON *const cm = &cpi->common;
const RATE_CONTROL *const rc = &cpi->rc;
CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
struct segmentation *const seg = &cm->seg;
const int apply_cyclic_refresh = apply_cyclic_refresh_bitrate(cm, rc);
if (cm->current_video_frame == 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) ||
(cpi->svc.temporal_layer_id > 0) ||
(cpi->svc.spatial_layer_id > 0)) {
// 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);
vp9_disable_segmentation(&cm->seg);
if (cm->frame_type == KEY_FRAME)
cr->sb_index = 0;
return;
} else {
int qindex_delta = 0;
int qindex2;
const double q = vp9_convert_qindex_to_q(cm->base_qindex, cm->bit_depth);
vp9_clear_system_state();
cr->max_qdelta_perc = 50;
cr->time_for_refresh = 0;
// Set rate threshold to some multiple (set to 2 for now) of the target
// rate (target is given by sb64_target_rate and scaled by 256).
cr->thresh_rate_sb = ((int64_t)(rc->sb64_target_rate) << 8) << 2;
// Distortion threshold, quadratic in Q, scale factor to be adjusted.
// q will not exceed 457, so (q * q) is within 32bit; see:
// vp9_convert_qindex_to_q(), vp9_ac_quant(), ac_qlookup*[].
cr->thresh_dist_sb = ((int64_t)(q * q)) << 2;
cr->motion_thresh = 32;
// Set up segmentation.
// Clear down the segment map.
vp9_enable_segmentation(&cm->seg);
vp9_clearall_segfeatures(seg);
// Select delta coding method.
seg->abs_delta = SEGMENT_DELTADATA;
// Note: setting temporal_update has no effect, as the seg-map coding method
// (temporal or spatial) is determined in vp9_choose_segmap_coding_method(),
// based on the coding cost of each method. For error_resilient mode on the
// last_frame_seg_map is set to 0, so if temporal coding is used, it is
// relative to 0 previous map.
// seg->temporal_update = 0;
// Segment BASE "Q" feature is disabled so it defaults to the baseline Q.
vp9_disable_segfeature(seg, CR_SEGMENT_ID_BASE, SEG_LVL_ALT_Q);
// Use segment BOOST1 for in-frame Q adjustment.
vp9_enable_segfeature(seg, CR_SEGMENT_ID_BOOST1, SEG_LVL_ALT_Q);
// Use segment BOOST2 for more aggressive in-frame Q adjustment.
vp9_enable_segfeature(seg, CR_SEGMENT_ID_BOOST2, SEG_LVL_ALT_Q);
// Set the q delta for segment BOOST1.
qindex_delta = compute_deltaq(cpi, cm->base_qindex, cr->rate_ratio_qdelta);
cr->qindex_delta_seg1 = qindex_delta;
// Compute rd-mult for segment BOOST1.
qindex2 = clamp(cm->base_qindex + cm->y_dc_delta_q + qindex_delta, 0, MAXQ);
cr->rdmult = vp9_compute_rd_mult(cpi, qindex2);
vp9_set_segdata(seg, CR_SEGMENT_ID_BOOST1, SEG_LVL_ALT_Q, qindex_delta);
// Set a more aggressive (higher) q delta for segment BOOST2.
qindex_delta = compute_deltaq(cpi, cm->base_qindex,
MIN(CR_MAX_RATE_TARGET_RATIO,
CR_BOOST2_FAC * cr->rate_ratio_qdelta));
cr->qindex_delta_seg2 = qindex_delta;
vp9_set_segdata(seg, CR_SEGMENT_ID_BOOST2, SEG_LVL_ALT_Q, qindex_delta);
// Update the segmentation and refresh map.
cyclic_refresh_update_map(cpi);
}
}
int vp9_cyclic_refresh_get_rdmult(const CYCLIC_REFRESH *cr) {
return cr->rdmult;
}

View file

@ -0,0 +1,99 @@
/*
* Copyright (c) 2014 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.
*/
#ifndef VP9_ENCODER_VP9_AQ_CYCLICREFRESH_H_
#define VP9_ENCODER_VP9_AQ_CYCLICREFRESH_H_
#include "vp9/common/vp9_blockd.h"
#ifdef __cplusplus
extern "C" {
#endif
// The segment ids used in cyclic refresh: from base (no boost) to increasing
// boost (higher delta-qp).
#define CR_SEGMENT_ID_BASE 0
#define CR_SEGMENT_ID_BOOST1 1
#define CR_SEGMENT_ID_BOOST2 2
// Maximum rate target ratio for setting segment delta-qp.
#define CR_MAX_RATE_TARGET_RATIO 4.0
// Boost factor for rate target ratio, for segment CR_SEGMENT_ID_BOOST2.
#define CR_BOOST2_FAC 1.7
struct VP9_COMP;
struct CYCLIC_REFRESH;
typedef struct CYCLIC_REFRESH CYCLIC_REFRESH;
CYCLIC_REFRESH *vp9_cyclic_refresh_alloc(int mi_rows, int mi_cols);
void vp9_cyclic_refresh_free(CYCLIC_REFRESH *cr);
// Estimate the bits, incorporating the delta-q from segment 1, after encoding
// the frame.
int vp9_cyclic_refresh_estimate_bits_at_q(const struct VP9_COMP *cpi,
double correction_factor);
// Estimate the bits per mb, for a given q = i and a corresponding delta-q
// (for segment 1), prior to encoding the frame.
int vp9_cyclic_refresh_rc_bits_per_mb(const struct VP9_COMP *cpi, int i,
double correction_factor);
// Prior to coding a given prediction block, of size bsize at (mi_row, mi_col),
// check if we should reset the segment_id, and update the cyclic_refresh map
// and segmentation map.
void vp9_cyclic_refresh_update_segment(struct VP9_COMP *const cpi,
MB_MODE_INFO *const mbmi,
int mi_row, int mi_col, BLOCK_SIZE bsize,
int64_t rate, int64_t dist, int skip);
// Update the segmentation map, and related quantities: cyclic refresh map,
// refresh sb_index, and target number of blocks to be refreshed.
void vp9_cyclic_refresh_update__map(struct VP9_COMP *const cpi);
// Update the actual number of blocks that were applied the segment delta q.
void vp9_cyclic_refresh_postencode(struct VP9_COMP *const cpi);
// Set golden frame update interval, for non-svc 1 pass CBR mode.
void vp9_cyclic_refresh_set_golden_update(struct VP9_COMP *const cpi);
// Check if we should not update golden reference, based on past refresh stats.
void vp9_cyclic_refresh_check_golden_update(struct VP9_COMP *const cpi);
// Set/update global/frame level refresh parameters.
void vp9_cyclic_refresh_update_parameters(struct VP9_COMP *const cpi);
// Setup cyclic background refresh: set delta q and segmentation map.
void vp9_cyclic_refresh_setup(struct VP9_COMP *const cpi);
int vp9_cyclic_refresh_get_rdmult(const CYCLIC_REFRESH *cr);
static INLINE int cyclic_refresh_segment_id_boosted(int segment_id) {
return segment_id == CR_SEGMENT_ID_BOOST1 ||
segment_id == CR_SEGMENT_ID_BOOST2;
}
static INLINE int cyclic_refresh_segment_id(int segment_id) {
if (segment_id == CR_SEGMENT_ID_BOOST1)
return CR_SEGMENT_ID_BOOST1;
else if (segment_id == CR_SEGMENT_ID_BOOST2)
return CR_SEGMENT_ID_BOOST2;
else
return CR_SEGMENT_ID_BASE;
}
#ifdef __cplusplus
} // extern "C"
#endif
#endif // VP9_ENCODER_VP9_AQ_CYCLICREFRESH_H_

View file

@ -0,0 +1,207 @@
/*
* Copyright (c) 2013 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 <math.h>
#include "vpx_ports/mem.h"
#include "vp9/encoder/vp9_aq_variance.h"
#include "vp9/common/vp9_seg_common.h"
#include "vp9/encoder/vp9_ratectrl.h"
#include "vp9/encoder/vp9_rd.h"
#include "vp9/encoder/vp9_segmentation.h"
#include "vp9/common/vp9_systemdependent.h"
#define ENERGY_MIN (-4)
#define ENERGY_MAX (1)
#define ENERGY_SPAN (ENERGY_MAX - ENERGY_MIN + 1)
#define ENERGY_IN_BOUNDS(energy)\
assert((energy) >= ENERGY_MIN && (energy) <= ENERGY_MAX)
static const double rate_ratio[MAX_SEGMENTS] =
{2.5, 2.0, 1.5, 1.0, 0.75, 1.0, 1.0, 1.0};
static const int segment_id[ENERGY_SPAN] = {0, 1, 1, 2, 3, 4};
#define SEGMENT_ID(i) segment_id[(i) - ENERGY_MIN]
DECLARE_ALIGNED(16, static const uint8_t, vp9_64_zeros[64]) = {0};
#if CONFIG_VP9_HIGHBITDEPTH
DECLARE_ALIGNED(16, static const uint16_t, vp9_highbd_64_zeros[64]) = {0};
#endif
unsigned int vp9_vaq_segment_id(int energy) {
ENERGY_IN_BOUNDS(energy);
return SEGMENT_ID(energy);
}
void vp9_vaq_frame_setup(VP9_COMP *cpi) {
VP9_COMMON *cm = &cpi->common;
struct segmentation *seg = &cm->seg;
int i;
if (cm->frame_type == KEY_FRAME ||
cpi->refresh_alt_ref_frame ||
(cpi->refresh_golden_frame && !cpi->rc.is_src_frame_alt_ref)) {
vp9_enable_segmentation(seg);
vp9_clearall_segfeatures(seg);
seg->abs_delta = SEGMENT_DELTADATA;
vp9_clear_system_state();
for (i = 0; i < MAX_SEGMENTS; ++i) {
int qindex_delta =
vp9_compute_qdelta_by_rate(&cpi->rc, cm->frame_type, cm->base_qindex,
rate_ratio[i], cm->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
// Q delta is sometimes applied without going back around the rd loop.
// This could lead to an illegal combination of partition size and q.
if ((cm->base_qindex != 0) && ((cm->base_qindex + qindex_delta) == 0)) {
qindex_delta = -cm->base_qindex + 1;
}
// No need to enable SEG_LVL_ALT_Q for this segment.
if (rate_ratio[i] == 1.0) {
continue;
}
vp9_set_segdata(seg, i, SEG_LVL_ALT_Q, qindex_delta);
vp9_enable_segfeature(seg, i, SEG_LVL_ALT_Q);
}
}
}
/* TODO(agrange, paulwilkins): The block_variance calls the unoptimized versions
* of variance() and highbd_8_variance(). It should not.
*/
static void aq_variance(const uint8_t *a, int a_stride,
const uint8_t *b, int b_stride,
int w, int h, unsigned int *sse, int *sum) {
int i, j;
*sum = 0;
*sse = 0;
for (i = 0; i < h; i++) {
for (j = 0; j < w; j++) {
const int diff = a[j] - b[j];
*sum += diff;
*sse += diff * diff;
}
a += a_stride;
b += b_stride;
}
}
#if CONFIG_VP9_HIGHBITDEPTH
static void aq_highbd_variance64(const uint8_t *a8, int a_stride,
const uint8_t *b8, int b_stride,
int w, int h, uint64_t *sse, uint64_t *sum) {
int i, j;
uint16_t *a = CONVERT_TO_SHORTPTR(a8);
uint16_t *b = CONVERT_TO_SHORTPTR(b8);
*sum = 0;
*sse = 0;
for (i = 0; i < h; i++) {
for (j = 0; j < w; j++) {
const int diff = a[j] - b[j];
*sum += diff;
*sse += diff * diff;
}
a += a_stride;
b += b_stride;
}
}
static void aq_highbd_8_variance(const uint8_t *a8, int a_stride,
const uint8_t *b8, int b_stride,
int w, int h, unsigned int *sse, int *sum) {
uint64_t sse_long = 0;
uint64_t sum_long = 0;
aq_highbd_variance64(a8, a_stride, b8, b_stride, w, h, &sse_long, &sum_long);
*sse = (unsigned int)sse_long;
*sum = (int)sum_long;
}
#endif // CONFIG_VP9_HIGHBITDEPTH
static unsigned int block_variance(VP9_COMP *cpi, MACROBLOCK *x,
BLOCK_SIZE bs) {
MACROBLOCKD *xd = &x->e_mbd;
unsigned int var, sse;
int right_overflow = (xd->mb_to_right_edge < 0) ?
((-xd->mb_to_right_edge) >> 3) : 0;
int bottom_overflow = (xd->mb_to_bottom_edge < 0) ?
((-xd->mb_to_bottom_edge) >> 3) : 0;
if (right_overflow || bottom_overflow) {
const int bw = 8 * num_8x8_blocks_wide_lookup[bs] - right_overflow;
const int bh = 8 * num_8x8_blocks_high_lookup[bs] - bottom_overflow;
int avg;
#if CONFIG_VP9_HIGHBITDEPTH
if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) {
aq_highbd_8_variance(x->plane[0].src.buf, x->plane[0].src.stride,
CONVERT_TO_BYTEPTR(vp9_highbd_64_zeros), 0, bw, bh,
&sse, &avg);
sse >>= 2 * (xd->bd - 8);
avg >>= (xd->bd - 8);
} else {
aq_variance(x->plane[0].src.buf, x->plane[0].src.stride,
vp9_64_zeros, 0, bw, bh, &sse, &avg);
}
#else
aq_variance(x->plane[0].src.buf, x->plane[0].src.stride,
vp9_64_zeros, 0, bw, bh, &sse, &avg);
#endif // CONFIG_VP9_HIGHBITDEPTH
var = sse - (((int64_t)avg * avg) / (bw * bh));
return (256 * var) / (bw * bh);
} else {
#if CONFIG_VP9_HIGHBITDEPTH
if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) {
var = cpi->fn_ptr[bs].vf(x->plane[0].src.buf,
x->plane[0].src.stride,
CONVERT_TO_BYTEPTR(vp9_highbd_64_zeros),
0, &sse);
} else {
var = cpi->fn_ptr[bs].vf(x->plane[0].src.buf,
x->plane[0].src.stride,
vp9_64_zeros, 0, &sse);
}
#else
var = cpi->fn_ptr[bs].vf(x->plane[0].src.buf,
x->plane[0].src.stride,
vp9_64_zeros, 0, &sse);
#endif // CONFIG_VP9_HIGHBITDEPTH
return (256 * var) >> num_pels_log2_lookup[bs];
}
}
double vp9_log_block_var(VP9_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bs) {
unsigned int var = block_variance(cpi, x, bs);
vp9_clear_system_state();
return log(var + 1.0);
}
#define DEFAULT_E_MIDPOINT 10.0
int vp9_block_energy(VP9_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bs) {
double energy;
double energy_midpoint;
vp9_clear_system_state();
energy_midpoint =
(cpi->oxcf.pass == 2) ? cpi->twopass.mb_av_energy : DEFAULT_E_MIDPOINT;
energy = vp9_log_block_var(cpi, x, bs) - energy_midpoint;
return clamp((int)round(energy), ENERGY_MIN, ENERGY_MAX);
}

View file

@ -0,0 +1,31 @@
/*
* Copyright (c) 2013 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.
*/
#ifndef VP9_ENCODER_VP9_AQ_VARIANCE_H_
#define VP9_ENCODER_VP9_AQ_VARIANCE_H_
#include "vp9/encoder/vp9_encoder.h"
#ifdef __cplusplus
extern "C" {
#endif
unsigned int vp9_vaq_segment_id(int energy);
void vp9_vaq_frame_setup(VP9_COMP *cpi);
int vp9_block_energy(VP9_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bs);
double vp9_log_block_var(VP9_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bs);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // VP9_ENCODER_VP9_AQ_VARIANCE_H_

View file

@ -0,0 +1,211 @@
/*
* Copyright (c) 2014 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 "./vp9_rtcd.h"
#include "vp9/common/vp9_common.h"
#include "vpx_ports/mem.h"
unsigned int vp9_avg_8x8_c(const uint8_t *s, int p) {
int i, j;
int sum = 0;
for (i = 0; i < 8; ++i, s+=p)
for (j = 0; j < 8; sum += s[j], ++j) {}
return (sum + 32) >> 6;
}
unsigned int vp9_avg_4x4_c(const uint8_t *s, int p) {
int i, j;
int sum = 0;
for (i = 0; i < 4; ++i, s+=p)
for (j = 0; j < 4; sum += s[j], ++j) {}
return (sum + 8) >> 4;
}
static void hadamard_col8(const int16_t *src_diff, int src_stride,
int16_t *coeff) {
int16_t b0 = src_diff[0 * src_stride] + src_diff[1 * src_stride];
int16_t b1 = src_diff[0 * src_stride] - src_diff[1 * src_stride];
int16_t b2 = src_diff[2 * src_stride] + src_diff[3 * src_stride];
int16_t b3 = src_diff[2 * src_stride] - src_diff[3 * src_stride];
int16_t b4 = src_diff[4 * src_stride] + src_diff[5 * src_stride];
int16_t b5 = src_diff[4 * src_stride] - src_diff[5 * src_stride];
int16_t b6 = src_diff[6 * src_stride] + src_diff[7 * src_stride];
int16_t b7 = src_diff[6 * src_stride] - src_diff[7 * src_stride];
int16_t c0 = b0 + b2;
int16_t c1 = b1 + b3;
int16_t c2 = b0 - b2;
int16_t c3 = b1 - b3;
int16_t c4 = b4 + b6;
int16_t c5 = b5 + b7;
int16_t c6 = b4 - b6;
int16_t c7 = b5 - b7;
coeff[0] = c0 + c4;
coeff[7] = c1 + c5;
coeff[3] = c2 + c6;
coeff[4] = c3 + c7;
coeff[2] = c0 - c4;
coeff[6] = c1 - c5;
coeff[1] = c2 - c6;
coeff[5] = c3 - c7;
}
void vp9_hadamard_8x8_c(int16_t const *src_diff, int src_stride,
int16_t *coeff) {
int idx;
int16_t buffer[64];
int16_t *tmp_buf = &buffer[0];
for (idx = 0; idx < 8; ++idx) {
hadamard_col8(src_diff, src_stride, tmp_buf);
tmp_buf += 8;
++src_diff;
}
tmp_buf = &buffer[0];
for (idx = 0; idx < 8; ++idx) {
hadamard_col8(tmp_buf, 8, coeff);
coeff += 8;
++tmp_buf;
}
}
// In place 16x16 2D Hadamard transform
void vp9_hadamard_16x16_c(int16_t const *src_diff, int src_stride,
int16_t *coeff) {
int idx;
for (idx = 0; idx < 4; ++idx) {
int16_t const *src_ptr = src_diff + (idx >> 1) * 8 * src_stride
+ (idx & 0x01) * 8;
vp9_hadamard_8x8_c(src_ptr, src_stride, coeff + idx * 64);
}
for (idx = 0; idx < 64; ++idx) {
int16_t a0 = coeff[0];
int16_t a1 = coeff[64];
int16_t a2 = coeff[128];
int16_t a3 = coeff[192];
int16_t b0 = a0 + a1;
int16_t b1 = a0 - a1;
int16_t b2 = a2 + a3;
int16_t b3 = a2 - a3;
coeff[0] = (b0 + b2) >> 1;
coeff[64] = (b1 + b3) >> 1;
coeff[128] = (b0 - b2) >> 1;
coeff[192] = (b1 - b3) >> 1;
++coeff;
}
}
int16_t vp9_satd_c(const int16_t *coeff, int length) {
int i;
int satd = 0;
for (i = 0; i < length; ++i)
satd += abs(coeff[i]);
return (int16_t)satd;
}
// Integer projection onto row vectors.
void vp9_int_pro_row_c(int16_t *hbuf, uint8_t const *ref,
const int ref_stride, const int height) {
int idx;
const int norm_factor = MAX(8, height >> 1);
for (idx = 0; idx < 16; ++idx) {
int i;
hbuf[idx] = 0;
for (i = 0; i < height; ++i)
hbuf[idx] += ref[i * ref_stride];
hbuf[idx] /= norm_factor;
++ref;
}
}
int16_t vp9_int_pro_col_c(uint8_t const *ref, const int width) {
int idx;
int16_t sum = 0;
for (idx = 0; idx < width; ++idx)
sum += ref[idx];
return sum;
}
int vp9_vector_var_c(int16_t const *ref, int16_t const *src,
const int bwl) {
int i;
int width = 4 << bwl;
int sse = 0, mean = 0, var;
for (i = 0; i < width; ++i) {
int diff = ref[i] - src[i];
mean += diff;
sse += diff * diff;
}
var = sse - ((mean * mean) >> (bwl + 2));
return var;
}
void vp9_minmax_8x8_c(const uint8_t *s, int p, const uint8_t *d, int dp,
int *min, int *max) {
int i, j;
*min = 255;
*max = 0;
for (i = 0; i < 8; ++i, s += p, d += dp) {
for (j = 0; j < 8; ++j) {
int diff = abs(s[j]-d[j]);
*min = diff < *min ? diff : *min;
*max = diff > *max ? diff : *max;
}
}
}
#if CONFIG_VP9_HIGHBITDEPTH
unsigned int vp9_highbd_avg_8x8_c(const uint8_t *s8, int p) {
int i, j;
int sum = 0;
const uint16_t* s = CONVERT_TO_SHORTPTR(s8);
for (i = 0; i < 8; ++i, s+=p)
for (j = 0; j < 8; sum += s[j], ++j) {}
return (sum + 32) >> 6;
}
unsigned int vp9_highbd_avg_4x4_c(const uint8_t *s8, int p) {
int i, j;
int sum = 0;
const uint16_t* s = CONVERT_TO_SHORTPTR(s8);
for (i = 0; i < 4; ++i, s+=p)
for (j = 0; j < 4; sum += s[j], ++j) {}
return (sum + 8) >> 4;
}
void vp9_highbd_minmax_8x8_c(const uint8_t *s8, int p, const uint8_t *d8,
int dp, int *min, int *max) {
int i, j;
const uint16_t* s = CONVERT_TO_SHORTPTR(s8);
const uint16_t* d = CONVERT_TO_SHORTPTR(d8);
*min = 255;
*max = 0;
for (i = 0; i < 8; ++i, s += p, d += dp) {
for (j = 0; j < 8; ++j) {
int diff = abs(s[j]-d[j]);
*min = diff < *min ? diff : *min;
*max = diff > *max ? diff : *max;
}
}
}
#endif // CONFIG_VP9_HIGHBITDEPTH

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,37 @@
/*
* 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.
*/
#ifndef VP9_ENCODER_VP9_BITSTREAM_H_
#define VP9_ENCODER_VP9_BITSTREAM_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "vp9/encoder/vp9_encoder.h"
void vp9_pack_bitstream(VP9_COMP *cpi, uint8_t *dest, size_t *size);
static INLINE int vp9_preserve_existing_gf(VP9_COMP *cpi) {
return !cpi->multi_arf_allowed && cpi->refresh_golden_frame &&
cpi->rc.is_src_frame_alt_ref &&
(!cpi->use_svc || // Add spatial svc base layer case here
(is_two_pass_svc(cpi) &&
cpi->svc.spatial_layer_id == 0 &&
cpi->svc.layer_context[0].gold_ref_idx >=0 &&
cpi->oxcf.ss_enable_auto_arf[0]));
}
#ifdef __cplusplus
} // extern "C"
#endif
#endif // VP9_ENCODER_VP9_BITSTREAM_H_

View file

@ -0,0 +1,137 @@
/*
* 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.
*/
#ifndef VP9_ENCODER_VP9_BLOCK_H_
#define VP9_ENCODER_VP9_BLOCK_H_
#include "vp9/common/vp9_entropymv.h"
#include "vp9/common/vp9_entropy.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
unsigned int sse;
int sum;
unsigned int var;
} diff;
struct macroblock_plane {
DECLARE_ALIGNED(16, int16_t, src_diff[64 * 64]);
tran_low_t *qcoeff;
tran_low_t *coeff;
uint16_t *eobs;
struct buf_2d src;
// Quantizer setings
int16_t *quant_fp;
int16_t *round_fp;
int16_t *quant;
int16_t *quant_shift;
int16_t *zbin;
int16_t *round;
int64_t quant_thred[2];
};
/* The [2] dimension is for whether we skip the EOB node (i.e. if previous
* coefficient in this block was zero) or not. */
typedef unsigned int vp9_coeff_cost[PLANE_TYPES][REF_TYPES][COEF_BANDS][2]
[COEFF_CONTEXTS][ENTROPY_TOKENS];
typedef struct macroblock MACROBLOCK;
struct macroblock {
struct macroblock_plane plane[MAX_MB_PLANE];
MACROBLOCKD e_mbd;
int skip_block;
int select_tx_size;
int skip_recode;
int skip_optimize;
int q_index;
int errorperbit;
int sadperbit16;
int sadperbit4;
int rddiv;
int rdmult;
int mb_energy;
// These are set to their default values at the beginning, and then adjusted
// further in the encoding process.
BLOCK_SIZE min_partition_size;
BLOCK_SIZE max_partition_size;
int mv_best_ref_index[MAX_REF_FRAMES];
unsigned int max_mv_context[MAX_REF_FRAMES];
unsigned int source_variance;
unsigned int pred_sse[MAX_REF_FRAMES];
int pred_mv_sad[MAX_REF_FRAMES];
int nmvjointcost[MV_JOINTS];
int *nmvcost[2];
int *nmvcost_hp[2];
int **mvcost;
int nmvjointsadcost[MV_JOINTS];
int *nmvsadcost[2];
int *nmvsadcost_hp[2];
int **mvsadcost;
// These define limits to motion vector components to prevent them
// from extending outside the UMV borders
int mv_col_min;
int mv_col_max;
int mv_row_min;
int mv_row_max;
uint8_t zcoeff_blk[TX_SIZES][256];
int skip;
int encode_breakout;
// note that token_costs is the cost when eob node is skipped
vp9_coeff_cost token_costs[TX_SIZES];
int optimize;
// indicate if it is in the rd search loop or encoding process
int use_lp32x32fdct;
int skip_encode;
// use fast quantization process
int quant_fp;
// skip forward transform and quantization
uint8_t skip_txfm[MAX_MB_PLANE << 2];
int64_t bsse[MAX_MB_PLANE << 2];
// Used to store sub partition's choices.
MV pred_mv[MAX_REF_FRAMES];
// Strong color activity detection. Used in RTC coding mode to enhance
// the visual quality at the boundary of moving color objects.
uint8_t color_sensitivity[2];
void (*fwd_txm4x4)(const int16_t *input, tran_low_t *output, int stride);
void (*itxm_add)(const tran_low_t *input, uint8_t *dest, int stride, int eob);
#if CONFIG_VP9_HIGHBITDEPTH
void (*highbd_itxm_add)(const tran_low_t *input, uint8_t *dest, int stride,
int eob, int bd);
#endif
};
#ifdef __cplusplus
} // extern "C"
#endif
#endif // VP9_ENCODER_VP9_BLOCK_H_

View file

@ -0,0 +1,138 @@
/*
* Copyright (c) 2014 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 "./vpx_config.h"
#include "./vp9_rtcd.h"
#include "vp9/common/vp9_common.h"
#include "vp9/common/vp9_convolve.h"
#include "vp9/common/vp9_filter.h"
#include "vpx/vpx_integer.h"
#include "vpx_ports/mem.h"
static int horizontal_filter(const uint8_t *s) {
return (s[1] - s[-2]) * 2 + (s[-1] - s[0]) * 6;
}
static int vertical_filter(const uint8_t *s, int p) {
return (s[p] - s[-2 * p]) * 2 + (s[-p] - s[0]) * 6;
}
static int variance(int sum, int sum_squared, int size) {
return sum_squared / size - (sum / size) * (sum / size);
}
// Calculate a blockiness level for a vertical block edge.
// This function returns a new blockiness metric that's defined as
// p0 p1 p2 p3
// q0 q1 q2 q3
// block edge ->
// r0 r1 r2 r3
// s0 s1 s2 s3
// blockiness = p0*-2+q0*6+r0*-6+s0*2 +
// p1*-2+q1*6+r1*-6+s1*2 +
// p2*-2+q2*6+r2*-6+s2*2 +
// p3*-2+q3*6+r3*-6+s3*2 ;
// reconstructed_blockiness = abs(blockiness from reconstructed buffer -
// blockiness from source buffer,0)
//
// I make the assumption that flat blocks are much more visible than high
// contrast blocks. As such, I scale the result of the blockiness calc
// by dividing the blockiness by the variance of the pixels on either side
// of the edge as follows:
// var_0 = (q0^2+q1^2+q2^2+q3^2) - ((q0 + q1 + q2 + q3) / 4 )^2
// var_1 = (r0^2+r1^2+r2^2+r3^2) - ((r0 + r1 + r2 + r3) / 4 )^2
// The returned blockiness is the scaled value
// Reconstructed blockiness / ( 1 + var_0 + var_1 ) ;
int blockiness_vertical(const uint8_t *s, int sp, const uint8_t *r, int rp,
int size) {
int s_blockiness = 0;
int r_blockiness = 0;
int sum_0 = 0;
int sum_sq_0 = 0;
int sum_1 = 0;
int sum_sq_1 = 0;
int i;
int var_0;
int var_1;
for (i = 0; i < size; ++i, s += sp, r += rp) {
s_blockiness += horizontal_filter(s);
r_blockiness += horizontal_filter(r);
sum_0 += s[0];
sum_sq_0 += s[0]*s[0];
sum_1 += s[-1];
sum_sq_1 += s[-1]*s[-1];
}
var_0 = variance(sum_0, sum_sq_0, size);
var_1 = variance(sum_1, sum_sq_1, size);
r_blockiness = abs(r_blockiness);
s_blockiness = abs(s_blockiness);
if (r_blockiness > s_blockiness)
return (r_blockiness - s_blockiness) / (1 + var_0 + var_1);
else
return 0;
}
// Calculate a blockiness level for a horizontal block edge
// same as above.
int blockiness_horizontal(const uint8_t *s, int sp, const uint8_t *r, int rp,
int size) {
int s_blockiness = 0;
int r_blockiness = 0;
int sum_0 = 0;
int sum_sq_0 = 0;
int sum_1 = 0;
int sum_sq_1 = 0;
int i;
int var_0;
int var_1;
for (i = 0; i < size; ++i, ++s, ++r) {
s_blockiness += vertical_filter(s, sp);
r_blockiness += vertical_filter(r, rp);
sum_0 += s[0];
sum_sq_0 += s[0] * s[0];
sum_1 += s[-sp];
sum_sq_1 += s[-sp] * s[-sp];
}
var_0 = variance(sum_0, sum_sq_0, size);
var_1 = variance(sum_1, sum_sq_1, size);
r_blockiness = abs(r_blockiness);
s_blockiness = abs(s_blockiness);
if (r_blockiness > s_blockiness)
return (r_blockiness - s_blockiness) / (1 + var_0 + var_1);
else
return 0;
}
// This function returns the blockiness for the entire frame currently by
// looking at all borders in steps of 4.
double vp9_get_blockiness(const unsigned char *img1, int img1_pitch,
const unsigned char *img2, int img2_pitch,
int width, int height ) {
double blockiness = 0;
int i, j;
vp9_clear_system_state();
for (i = 0; i < height; i += 4, img1 += img1_pitch * 4,
img2 += img2_pitch * 4) {
for (j = 0; j < width; j += 4) {
if (i > 0 && i < height && j > 0 && j < width) {
blockiness += blockiness_vertical(img1 + j, img1_pitch,
img2 + j, img2_pitch, 4);
blockiness += blockiness_horizontal(img1 + j, img1_pitch,
img2 + j, img2_pitch, 4);
}
}
}
blockiness /= width * height / 16;
return blockiness;
}

View file

@ -0,0 +1,158 @@
/*
* Copyright (c) 2014 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 "vp9/encoder/vp9_context_tree.h"
#include "vp9/encoder/vp9_encoder.h"
static const BLOCK_SIZE square[] = {
BLOCK_8X8,
BLOCK_16X16,
BLOCK_32X32,
BLOCK_64X64,
};
static void alloc_mode_context(VP9_COMMON *cm, int num_4x4_blk,
PICK_MODE_CONTEXT *ctx) {
const int num_blk = (num_4x4_blk < 4 ? 4 : num_4x4_blk);
const int num_pix = num_blk << 4;
int i, k;
ctx->num_4x4_blk = num_blk;
CHECK_MEM_ERROR(cm, ctx->zcoeff_blk,
vpx_calloc(num_4x4_blk, sizeof(uint8_t)));
for (i = 0; i < MAX_MB_PLANE; ++i) {
for (k = 0; k < 3; ++k) {
CHECK_MEM_ERROR(cm, ctx->coeff[i][k],
vpx_memalign(16, num_pix * sizeof(*ctx->coeff[i][k])));
CHECK_MEM_ERROR(cm, ctx->qcoeff[i][k],
vpx_memalign(16, num_pix * sizeof(*ctx->qcoeff[i][k])));
CHECK_MEM_ERROR(cm, ctx->dqcoeff[i][k],
vpx_memalign(16, num_pix * sizeof(*ctx->dqcoeff[i][k])));
CHECK_MEM_ERROR(cm, ctx->eobs[i][k],
vpx_memalign(16, num_pix * sizeof(*ctx->eobs[i][k])));
ctx->coeff_pbuf[i][k] = ctx->coeff[i][k];
ctx->qcoeff_pbuf[i][k] = ctx->qcoeff[i][k];
ctx->dqcoeff_pbuf[i][k] = ctx->dqcoeff[i][k];
ctx->eobs_pbuf[i][k] = ctx->eobs[i][k];
}
}
}
static void free_mode_context(PICK_MODE_CONTEXT *ctx) {
int i, k;
vpx_free(ctx->zcoeff_blk);
ctx->zcoeff_blk = 0;
for (i = 0; i < MAX_MB_PLANE; ++i) {
for (k = 0; k < 3; ++k) {
vpx_free(ctx->coeff[i][k]);
ctx->coeff[i][k] = 0;
vpx_free(ctx->qcoeff[i][k]);
ctx->qcoeff[i][k] = 0;
vpx_free(ctx->dqcoeff[i][k]);
ctx->dqcoeff[i][k] = 0;
vpx_free(ctx->eobs[i][k]);
ctx->eobs[i][k] = 0;
}
}
}
static void alloc_tree_contexts(VP9_COMMON *cm, PC_TREE *tree,
int num_4x4_blk) {
alloc_mode_context(cm, num_4x4_blk, &tree->none);
alloc_mode_context(cm, num_4x4_blk/2, &tree->horizontal[0]);
alloc_mode_context(cm, num_4x4_blk/2, &tree->vertical[0]);
/* TODO(Jbb): for 4x8 and 8x4 these allocated values are not used.
* Figure out a better way to do this. */
alloc_mode_context(cm, num_4x4_blk/2, &tree->horizontal[1]);
alloc_mode_context(cm, num_4x4_blk/2, &tree->vertical[1]);
}
static void free_tree_contexts(PC_TREE *tree) {
free_mode_context(&tree->none);
free_mode_context(&tree->horizontal[0]);
free_mode_context(&tree->horizontal[1]);
free_mode_context(&tree->vertical[0]);
free_mode_context(&tree->vertical[1]);
}
// This function sets up a tree of contexts such that at each square
// partition level. There are contexts for none, horizontal, vertical, and
// split. Along with a block_size value and a selected block_size which
// represents the state of our search.
void vp9_setup_pc_tree(VP9_COMMON *cm, ThreadData *td) {
int i, j;
const int leaf_nodes = 64;
const int tree_nodes = 64 + 16 + 4 + 1;
int pc_tree_index = 0;
PC_TREE *this_pc;
PICK_MODE_CONTEXT *this_leaf;
int square_index = 1;
int nodes;
vpx_free(td->leaf_tree);
CHECK_MEM_ERROR(cm, td->leaf_tree, vpx_calloc(leaf_nodes,
sizeof(*td->leaf_tree)));
vpx_free(td->pc_tree);
CHECK_MEM_ERROR(cm, td->pc_tree, vpx_calloc(tree_nodes,
sizeof(*td->pc_tree)));
this_pc = &td->pc_tree[0];
this_leaf = &td->leaf_tree[0];
// 4x4 blocks smaller than 8x8 but in the same 8x8 block share the same
// context so we only need to allocate 1 for each 8x8 block.
for (i = 0; i < leaf_nodes; ++i)
alloc_mode_context(cm, 1, &td->leaf_tree[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, 4);
tree->leaf_split[0] = this_leaf++;
for (j = 1; j < 4; j++)
tree->leaf_split[j] = tree->leaf_split[0];
}
// Each node has 4 leaf nodes, fill each block_size level of the tree
// from leafs to the root.
for (nodes = 16; 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, 4 << (2 * square_index));
tree->block_size = square[square_index];
for (j = 0; j < 4; j++)
tree->split[j] = this_pc++;
++pc_tree_index;
}
++square_index;
}
td->pc_root = &td->pc_tree[tree_nodes - 1];
td->pc_root[0].none.best_mode_index = 2;
}
void vp9_free_pc_tree(ThreadData *td) {
const int tree_nodes = 64 + 16 + 4 + 1;
int i;
// Set up all 4x4 mode contexts
for (i = 0; i < 64; ++i)
free_mode_context(&td->leaf_tree[i]);
// Sets up all the leaf nodes in the tree.
for (i = 0; i < tree_nodes; ++i)
free_tree_contexts(&td->pc_tree[i]);
vpx_free(td->pc_tree);
td->pc_tree = NULL;
vpx_free(td->leaf_tree);
td->leaf_tree = NULL;
}

View file

@ -0,0 +1,86 @@
/*
* Copyright (c) 2014 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.
*/
#ifndef VP9_ENCODER_VP9_CONTEXT_TREE_H_
#define VP9_ENCODER_VP9_CONTEXT_TREE_H_
#include "vp9/common/vp9_blockd.h"
struct VP9_COMP;
struct VP9Common;
struct ThreadData;
// Structure to hold snapshot of coding context during the mode picking process
typedef struct {
MODE_INFO mic;
uint8_t *zcoeff_blk;
tran_low_t *coeff[MAX_MB_PLANE][3];
tran_low_t *qcoeff[MAX_MB_PLANE][3];
tran_low_t *dqcoeff[MAX_MB_PLANE][3];
uint16_t *eobs[MAX_MB_PLANE][3];
// dual buffer pointers, 0: in use, 1: best in store
tran_low_t *coeff_pbuf[MAX_MB_PLANE][3];
tran_low_t *qcoeff_pbuf[MAX_MB_PLANE][3];
tran_low_t *dqcoeff_pbuf[MAX_MB_PLANE][3];
uint16_t *eobs_pbuf[MAX_MB_PLANE][3];
int is_coded;
int num_4x4_blk;
int skip;
int pred_pixel_ready;
// For current partition, only if all Y, U, and V transform blocks'
// coefficients are quantized to 0, skippable is set to 0.
int skippable;
uint8_t skip_txfm[MAX_MB_PLANE << 2];
int best_mode_index;
int hybrid_pred_diff;
int comp_pred_diff;
int single_pred_diff;
int64_t tx_rd_diff[TX_MODES];
int64_t best_filter_diff[SWITCHABLE_FILTER_CONTEXTS];
// TODO(jingning) Use RD_COST struct here instead. This involves a boarder
// scope of refactoring.
int rate;
int64_t dist;
#if CONFIG_VP9_TEMPORAL_DENOISING
unsigned int newmv_sse;
unsigned int zeromv_sse;
PREDICTION_MODE best_sse_inter_mode;
int_mv best_sse_mv;
MV_REFERENCE_FRAME best_reference_frame;
MV_REFERENCE_FRAME best_zeromv_reference_frame;
#endif
// motion vector cache for adaptive motion search control in partition
// search loop
MV pred_mv[MAX_REF_FRAMES];
INTERP_FILTER pred_interp_filter;
} PICK_MODE_CONTEXT;
typedef struct PC_TREE {
int index;
PARTITION_TYPE partitioning;
BLOCK_SIZE block_size;
PICK_MODE_CONTEXT none;
PICK_MODE_CONTEXT horizontal[2];
PICK_MODE_CONTEXT vertical[2];
union {
struct PC_TREE *split[4];
PICK_MODE_CONTEXT *leaf_split[4];
};
} PC_TREE;
void vp9_setup_pc_tree(struct VP9Common *cm, struct ThreadData *td);
void vp9_free_pc_tree(struct ThreadData *td);
#endif /* VP9_ENCODER_VP9_CONTEXT_TREE_H_ */

View file

@ -0,0 +1,62 @@
/*
* Copyright (c) 2014 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 "vp9/encoder/vp9_cost.h"
const unsigned int vp9_prob_cost[256] = {
2047, 2047, 1791, 1641, 1535, 1452, 1385, 1328, 1279, 1235, 1196, 1161,
1129, 1099, 1072, 1046, 1023, 1000, 979, 959, 940, 922, 905, 889,
873, 858, 843, 829, 816, 803, 790, 778, 767, 755, 744, 733,
723, 713, 703, 693, 684, 675, 666, 657, 649, 641, 633, 625,
617, 609, 602, 594, 587, 580, 573, 567, 560, 553, 547, 541,
534, 528, 522, 516, 511, 505, 499, 494, 488, 483, 477, 472,
467, 462, 457, 452, 447, 442, 437, 433, 428, 424, 419, 415,
410, 406, 401, 397, 393, 389, 385, 381, 377, 373, 369, 365,
361, 357, 353, 349, 346, 342, 338, 335, 331, 328, 324, 321,
317, 314, 311, 307, 304, 301, 297, 294, 291, 288, 285, 281,
278, 275, 272, 269, 266, 263, 260, 257, 255, 252, 249, 246,
243, 240, 238, 235, 232, 229, 227, 224, 221, 219, 216, 214,
211, 208, 206, 203, 201, 198, 196, 194, 191, 189, 186, 184,
181, 179, 177, 174, 172, 170, 168, 165, 163, 161, 159, 156,
154, 152, 150, 148, 145, 143, 141, 139, 137, 135, 133, 131,
129, 127, 125, 123, 121, 119, 117, 115, 113, 111, 109, 107,
105, 103, 101, 99, 97, 95, 93, 92, 90, 88, 86, 84,
82, 81, 79, 77, 75, 73, 72, 70, 68, 66, 65, 63,
61, 60, 58, 56, 55, 53, 51, 50, 48, 46, 45, 43,
41, 40, 38, 37, 35, 33, 32, 30, 29, 27, 25, 24,
22, 21, 19, 18, 16, 15, 13, 12, 10, 9, 7, 6,
4, 3, 1, 1};
static void cost(int *costs, vp9_tree tree, const vp9_prob *probs,
int i, int c) {
const vp9_prob prob = probs[i / 2];
int b;
for (b = 0; b <= 1; ++b) {
const int cc = c + vp9_cost_bit(prob, b);
const vp9_tree_index ii = tree[i + b];
if (ii <= 0)
costs[-ii] = cc;
else
cost(costs, tree, probs, ii, cc);
}
}
void vp9_cost_tokens(int *costs, const vp9_prob *probs, vp9_tree tree) {
cost(costs, tree, probs, 0, 0);
}
void vp9_cost_tokens_skip(int *costs, const vp9_prob *probs, vp9_tree tree) {
assert(tree[0] <= 0 && tree[1] > 0);
costs[-tree[0]] = vp9_cost_bit(probs[0], 0);
cost(costs, tree, probs, 2, 0);
}

View file

@ -0,0 +1,55 @@
/*
* Copyright (c) 2014 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.
*/
#ifndef VP9_ENCODER_VP9_COST_H_
#define VP9_ENCODER_VP9_COST_H_
#include "vp9/common/vp9_prob.h"
#ifdef __cplusplus
extern "C" {
#endif
extern const unsigned int vp9_prob_cost[256];
#define vp9_cost_zero(prob) (vp9_prob_cost[prob])
#define vp9_cost_one(prob) vp9_cost_zero(vp9_complement(prob))
#define vp9_cost_bit(prob, bit) vp9_cost_zero((bit) ? vp9_complement(prob) \
: (prob))
static INLINE unsigned int cost_branch256(const unsigned int ct[2],
vp9_prob p) {
return ct[0] * vp9_cost_zero(p) + ct[1] * vp9_cost_one(p);
}
static INLINE int treed_cost(vp9_tree tree, const vp9_prob *probs,
int bits, int len) {
int cost = 0;
vp9_tree_index i = 0;
do {
const int bit = (bits >> --len) & 1;
cost += vp9_cost_bit(probs[i >> 1], bit);
i = tree[i + bit];
} while (len);
return cost;
}
void vp9_cost_tokens(int *costs, const vp9_prob *probs, vp9_tree tree);
void vp9_cost_tokens_skip(int *costs, const vp9_prob *probs, vp9_tree tree);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // VP9_ENCODER_VP9_COST_H_

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,61 @@
/*
* Copyright (c) 2014 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.
*/
#ifndef VP9_ENCODER_VP9_DCT_H_
#define VP9_ENCODER_VP9_DCT_H_
#include "vp9/common/vp9_idct.h"
#ifdef __cplusplus
extern "C" {
#endif
void vp9_highbd_fdct4x4_c(const int16_t *input, tran_low_t *output, int stride);
void vp9_highbd_fdct8x8_c(const int16_t *input, tran_low_t *output, int stride);
void vp9_highbd_fdct16x16_c(const int16_t *input, tran_low_t *output,
int stride);
void vp9_highbd_fdct32x32_c(const int16_t *input, tran_low_t *out, int stride);
void vp9_highbd_fdct32x32_rd_c(const int16_t *input, tran_low_t *out,
int stride);
void vp9_fdct4(const tran_low_t *input, tran_low_t *output);
void vp9_fadst4(const tran_low_t *input, tran_low_t *output);
void vp9_fdct8(const tran_low_t *input, tran_low_t *output);
void vp9_fadst8(const tran_low_t *input, tran_low_t *output);
void vp9_fdct16(const tran_low_t in[16], tran_low_t out[16]);
void vp9_fadst16(const tran_low_t *input, tran_low_t *output);
void vp9_fdct32(const tran_high_t *input, tran_high_t *output, int round);
static const transform_2d FHT_4[] = {
{ vp9_fdct4, vp9_fdct4 }, // DCT_DCT = 0
{ vp9_fadst4, vp9_fdct4 }, // ADST_DCT = 1
{ vp9_fdct4, vp9_fadst4 }, // DCT_ADST = 2
{ vp9_fadst4, vp9_fadst4 } // ADST_ADST = 3
};
static const transform_2d FHT_8[] = {
{ vp9_fdct8, vp9_fdct8 }, // DCT_DCT = 0
{ vp9_fadst8, vp9_fdct8 }, // ADST_DCT = 1
{ vp9_fdct8, vp9_fadst8 }, // DCT_ADST = 2
{ vp9_fadst8, vp9_fadst8 } // ADST_ADST = 3
};
static const transform_2d FHT_16[] = {
{ vp9_fdct16, vp9_fdct16 }, // DCT_DCT = 0
{ vp9_fadst16, vp9_fdct16 }, // ADST_DCT = 1
{ vp9_fdct16, vp9_fadst16 }, // DCT_ADST = 2
{ vp9_fadst16, vp9_fadst16 } // ADST_ADST = 3
};
#ifdef __cplusplus
} // extern "C"
#endif
#endif // VP9_ENCODER_VP9_DCT_H_

View file

@ -0,0 +1,498 @@
/*
* Copyright (c) 2012 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 <assert.h>
#include <limits.h>
#include "vpx_scale/yv12config.h"
#include "vpx/vpx_integer.h"
#include "vp9/common/vp9_reconinter.h"
#include "vp9/encoder/vp9_context_tree.h"
#include "vp9/encoder/vp9_denoiser.h"
/* The VP9 denoiser is a work-in-progress. It currently is only designed to work
* with speed 6, though it (inexplicably) seems to also work with speed 5 (one
* would need to modify the source code in vp9_pickmode.c and vp9_encoder.c to
* make the calls to the vp9_denoiser_* functions when in speed 5).
*
* The implementation is very similar to that of the VP8 denoiser. While
* choosing the motion vectors / reference frames, the denoiser is run, and if
* it did not modify the signal to much, the denoised block is copied to the
* signal.
*/
#ifdef OUTPUT_YUV_DENOISED
static void make_grayscale(YV12_BUFFER_CONFIG *yuv);
#endif
static int absdiff_thresh(BLOCK_SIZE bs, int increase_denoising) {
(void)bs;
return 3 + (increase_denoising ? 1 : 0);
}
static int delta_thresh(BLOCK_SIZE bs, int increase_denoising) {
(void)bs;
(void)increase_denoising;
return 4;
}
static int noise_motion_thresh(BLOCK_SIZE bs, int increase_denoising) {
(void)bs;
(void)increase_denoising;
return 625;
}
static unsigned int sse_thresh(BLOCK_SIZE bs, int increase_denoising) {
return (1 << num_pels_log2_lookup[bs]) * (increase_denoising ? 60 : 40);
}
static int sse_diff_thresh(BLOCK_SIZE bs, int increase_denoising,
int motion_magnitude) {
if (motion_magnitude >
noise_motion_thresh(bs, increase_denoising)) {
return 0;
} else {
return (1 << num_pels_log2_lookup[bs]) * 20;
}
}
int total_adj_strong_thresh(BLOCK_SIZE bs, int increase_denoising) {
return (1 << num_pels_log2_lookup[bs]) * (increase_denoising ? 3 : 2);
}
static int total_adj_weak_thresh(BLOCK_SIZE bs, int increase_denoising) {
return (1 << num_pels_log2_lookup[bs]) * (increase_denoising ? 3 : 2);
}
// TODO(jackychen): If increase_denoising is enabled in the future,
// we might need to update the code for calculating 'total_adj' in
// case the C code is not bit-exact with corresponding sse2 code.
int vp9_denoiser_filter_c(const uint8_t *sig, int sig_stride,
const uint8_t *mc_avg,
int mc_avg_stride,
uint8_t *avg, int avg_stride,
int increase_denoising,
BLOCK_SIZE bs,
int motion_magnitude) {
int r, c;
const uint8_t *sig_start = sig;
const uint8_t *mc_avg_start = mc_avg;
uint8_t *avg_start = avg;
int diff, adj, absdiff, delta;
int adj_val[] = {3, 4, 6};
int total_adj = 0;
int shift_inc = 1;
// If motion_magnitude is small, making the denoiser more aggressive by
// increasing the adjustment for each level. Add another increment for
// blocks that are labeled for increase denoising.
if (motion_magnitude <= MOTION_MAGNITUDE_THRESHOLD) {
if (increase_denoising) {
shift_inc = 2;
}
adj_val[0] += shift_inc;
adj_val[1] += shift_inc;
adj_val[2] += shift_inc;
}
// First attempt to apply a strong temporal denoising filter.
for (r = 0; r < (4 << b_height_log2_lookup[bs]); ++r) {
for (c = 0; c < (4 << b_width_log2_lookup[bs]); ++c) {
diff = mc_avg[c] - sig[c];
absdiff = abs(diff);
if (absdiff <= absdiff_thresh(bs, increase_denoising)) {
avg[c] = mc_avg[c];
total_adj += diff;
} else {
switch (absdiff) {
case 4: case 5: case 6: case 7:
adj = adj_val[0];
break;
case 8: case 9: case 10: case 11:
case 12: case 13: case 14: case 15:
adj = adj_val[1];
break;
default:
adj = adj_val[2];
}
if (diff > 0) {
avg[c] = MIN(UINT8_MAX, sig[c] + adj);
total_adj += adj;
} else {
avg[c] = MAX(0, sig[c] - adj);
total_adj -= adj;
}
}
}
sig += sig_stride;
avg += avg_stride;
mc_avg += mc_avg_stride;
}
// If the strong filter did not modify the signal too much, we're all set.
if (abs(total_adj) <= total_adj_strong_thresh(bs, increase_denoising)) {
return FILTER_BLOCK;
}
// Otherwise, we try to dampen the filter if the delta is not too high.
delta = ((abs(total_adj) - total_adj_strong_thresh(bs, increase_denoising))
>> num_pels_log2_lookup[bs]) + 1;
if (delta >= delta_thresh(bs, increase_denoising)) {
return COPY_BLOCK;
}
mc_avg = mc_avg_start;
avg = avg_start;
sig = sig_start;
for (r = 0; r < (4 << b_height_log2_lookup[bs]); ++r) {
for (c = 0; c < (4 << b_width_log2_lookup[bs]); ++c) {
diff = mc_avg[c] - sig[c];
adj = abs(diff);
if (adj > delta) {
adj = delta;
}
if (diff > 0) {
// Diff positive means we made positive adjustment above
// (in first try/attempt), so now make negative adjustment to bring
// denoised signal down.
avg[c] = MAX(0, avg[c] - adj);
total_adj -= adj;
} else {
// Diff negative means we made negative adjustment above
// (in first try/attempt), so now make positive adjustment to bring
// denoised signal up.
avg[c] = MIN(UINT8_MAX, avg[c] + adj);
total_adj += adj;
}
}
sig += sig_stride;
avg += avg_stride;
mc_avg += mc_avg_stride;
}
// We can use the filter if it has been sufficiently dampened
if (abs(total_adj) <= total_adj_weak_thresh(bs, increase_denoising)) {
return FILTER_BLOCK;
}
return COPY_BLOCK;
}
static uint8_t *block_start(uint8_t *framebuf, int stride,
int mi_row, int mi_col) {
return framebuf + (stride * mi_row * 8) + (mi_col * 8);
}
static VP9_DENOISER_DECISION perform_motion_compensation(VP9_DENOISER *denoiser,
MACROBLOCK *mb,
BLOCK_SIZE bs,
int increase_denoising,
int mi_row,
int mi_col,
PICK_MODE_CONTEXT *ctx,
int *motion_magnitude
) {
int mv_col, mv_row;
int sse_diff = ctx->zeromv_sse - ctx->newmv_sse;
MV_REFERENCE_FRAME frame;
MACROBLOCKD *filter_mbd = &mb->e_mbd;
MB_MODE_INFO *mbmi = &filter_mbd->mi[0]->mbmi;
MB_MODE_INFO saved_mbmi;
int i, j;
struct buf_2d saved_dst[MAX_MB_PLANE];
struct buf_2d saved_pre[MAX_MB_PLANE][2]; // 2 pre buffers
mv_col = ctx->best_sse_mv.as_mv.col;
mv_row = ctx->best_sse_mv.as_mv.row;
*motion_magnitude = mv_row * mv_row + mv_col * mv_col;
frame = ctx->best_reference_frame;
saved_mbmi = *mbmi;
// If the best reference frame uses inter-prediction and there is enough of a
// difference in sum-squared-error, use it.
if (frame != INTRA_FRAME &&
sse_diff > sse_diff_thresh(bs, increase_denoising, *motion_magnitude)) {
mbmi->ref_frame[0] = ctx->best_reference_frame;
mbmi->mode = ctx->best_sse_inter_mode;
mbmi->mv[0] = ctx->best_sse_mv;
} else {
// Otherwise, use the zero reference frame.
frame = ctx->best_zeromv_reference_frame;
mbmi->ref_frame[0] = ctx->best_zeromv_reference_frame;
mbmi->mode = ZEROMV;
mbmi->mv[0].as_int = 0;
ctx->best_sse_inter_mode = ZEROMV;
ctx->best_sse_mv.as_int = 0;
ctx->newmv_sse = ctx->zeromv_sse;
}
if (ctx->newmv_sse > sse_thresh(bs, increase_denoising)) {
// Restore everything to its original state
*mbmi = saved_mbmi;
return COPY_BLOCK;
}
if (*motion_magnitude >
(noise_motion_thresh(bs, increase_denoising) << 3)) {
// Restore everything to its original state
*mbmi = saved_mbmi;
return COPY_BLOCK;
}
// We will restore these after motion compensation.
for (i = 0; i < MAX_MB_PLANE; ++i) {
for (j = 0; j < 2; ++j) {
saved_pre[i][j] = filter_mbd->plane[i].pre[j];
}
saved_dst[i] = filter_mbd->plane[i].dst;
}
// Set the pointers in the MACROBLOCKD to point to the buffers in the denoiser
// struct.
for (j = 0; j < 2; ++j) {
filter_mbd->plane[0].pre[j].buf =
block_start(denoiser->running_avg_y[frame].y_buffer,
denoiser->running_avg_y[frame].y_stride,
mi_row, mi_col);
filter_mbd->plane[0].pre[j].stride =
denoiser->running_avg_y[frame].y_stride;
filter_mbd->plane[1].pre[j].buf =
block_start(denoiser->running_avg_y[frame].u_buffer,
denoiser->running_avg_y[frame].uv_stride,
mi_row, mi_col);
filter_mbd->plane[1].pre[j].stride =
denoiser->running_avg_y[frame].uv_stride;
filter_mbd->plane[2].pre[j].buf =
block_start(denoiser->running_avg_y[frame].v_buffer,
denoiser->running_avg_y[frame].uv_stride,
mi_row, mi_col);
filter_mbd->plane[2].pre[j].stride =
denoiser->running_avg_y[frame].uv_stride;
}
filter_mbd->plane[0].dst.buf =
block_start(denoiser->mc_running_avg_y.y_buffer,
denoiser->mc_running_avg_y.y_stride,
mi_row, mi_col);
filter_mbd->plane[0].dst.stride = denoiser->mc_running_avg_y.y_stride;
filter_mbd->plane[1].dst.buf =
block_start(denoiser->mc_running_avg_y.u_buffer,
denoiser->mc_running_avg_y.uv_stride,
mi_row, mi_col);
filter_mbd->plane[1].dst.stride = denoiser->mc_running_avg_y.uv_stride;
filter_mbd->plane[2].dst.buf =
block_start(denoiser->mc_running_avg_y.v_buffer,
denoiser->mc_running_avg_y.uv_stride,
mi_row, mi_col);
filter_mbd->plane[2].dst.stride = denoiser->mc_running_avg_y.uv_stride;
vp9_build_inter_predictors_sby(filter_mbd, mv_row, mv_col, bs);
// Restore everything to its original state
*mbmi = saved_mbmi;
for (i = 0; i < MAX_MB_PLANE; ++i) {
for (j = 0; j < 2; ++j) {
filter_mbd->plane[i].pre[j] = saved_pre[i][j];
}
filter_mbd->plane[i].dst = saved_dst[i];
}
mv_row = ctx->best_sse_mv.as_mv.row;
mv_col = ctx->best_sse_mv.as_mv.col;
return FILTER_BLOCK;
}
void vp9_denoiser_denoise(VP9_DENOISER *denoiser, MACROBLOCK *mb,
int mi_row, int mi_col, BLOCK_SIZE bs,
PICK_MODE_CONTEXT *ctx) {
int motion_magnitude = 0;
VP9_DENOISER_DECISION decision = FILTER_BLOCK;
YV12_BUFFER_CONFIG avg = denoiser->running_avg_y[INTRA_FRAME];
YV12_BUFFER_CONFIG mc_avg = denoiser->mc_running_avg_y;
uint8_t *avg_start = block_start(avg.y_buffer, avg.y_stride, mi_row, mi_col);
uint8_t *mc_avg_start = block_start(mc_avg.y_buffer, mc_avg.y_stride,
mi_row, mi_col);
struct buf_2d src = mb->plane[0].src;
decision = perform_motion_compensation(denoiser, mb, bs,
denoiser->increase_denoising,
mi_row, mi_col, ctx,
&motion_magnitude);
if (decision == FILTER_BLOCK) {
decision = vp9_denoiser_filter(src.buf, src.stride,
mc_avg_start, mc_avg.y_stride,
avg_start, avg.y_stride,
0, bs, motion_magnitude);
}
if (decision == FILTER_BLOCK) {
vp9_convolve_copy(avg_start, avg.y_stride, src.buf, src.stride,
NULL, 0, NULL, 0,
num_4x4_blocks_wide_lookup[bs] << 2,
num_4x4_blocks_high_lookup[bs] << 2);
} else { // COPY_BLOCK
vp9_convolve_copy(src.buf, src.stride, avg_start, avg.y_stride,
NULL, 0, NULL, 0,
num_4x4_blocks_wide_lookup[bs] << 2,
num_4x4_blocks_high_lookup[bs] << 2);
}
}
static void copy_frame(YV12_BUFFER_CONFIG dest, const YV12_BUFFER_CONFIG src) {
int r;
const uint8_t *srcbuf = src.y_buffer;
uint8_t *destbuf = dest.y_buffer;
assert(dest.y_width == src.y_width);
assert(dest.y_height == src.y_height);
for (r = 0; r < dest.y_height; ++r) {
memcpy(destbuf, srcbuf, dest.y_width);
destbuf += dest.y_stride;
srcbuf += src.y_stride;
}
}
static void swap_frame_buffer(YV12_BUFFER_CONFIG *dest,
YV12_BUFFER_CONFIG *src) {
uint8_t *tmp_buf = dest->y_buffer;
assert(dest->y_width == src->y_width);
assert(dest->y_height == src->y_height);
dest->y_buffer = src->y_buffer;
src->y_buffer = tmp_buf;
}
void vp9_denoiser_update_frame_info(VP9_DENOISER *denoiser,
YV12_BUFFER_CONFIG src,
FRAME_TYPE frame_type,
int refresh_alt_ref_frame,
int refresh_golden_frame,
int refresh_last_frame) {
if (frame_type == KEY_FRAME) {
int i;
// Start at 1 so as not to overwrite the INTRA_FRAME
for (i = 1; i < MAX_REF_FRAMES; ++i)
copy_frame(denoiser->running_avg_y[i], src);
return;
}
/* For non key frames */
if (refresh_alt_ref_frame) {
swap_frame_buffer(&denoiser->running_avg_y[ALTREF_FRAME],
&denoiser->running_avg_y[INTRA_FRAME]);
}
if (refresh_golden_frame) {
swap_frame_buffer(&denoiser->running_avg_y[GOLDEN_FRAME],
&denoiser->running_avg_y[INTRA_FRAME]);
}
if (refresh_last_frame) {
swap_frame_buffer(&denoiser->running_avg_y[LAST_FRAME],
&denoiser->running_avg_y[INTRA_FRAME]);
}
}
void vp9_denoiser_reset_frame_stats(PICK_MODE_CONTEXT *ctx) {
ctx->zeromv_sse = UINT_MAX;
ctx->newmv_sse = UINT_MAX;
}
void vp9_denoiser_update_frame_stats(MB_MODE_INFO *mbmi, unsigned int sse,
PREDICTION_MODE mode,
PICK_MODE_CONTEXT *ctx) {
// TODO(tkopp): Use both MVs if possible
if (mbmi->mv[0].as_int == 0 && sse < ctx->zeromv_sse) {
ctx->zeromv_sse = sse;
ctx->best_zeromv_reference_frame = mbmi->ref_frame[0];
}
if (mbmi->mv[0].as_int != 0 && sse < ctx->newmv_sse) {
ctx->newmv_sse = sse;
ctx->best_sse_inter_mode = mode;
ctx->best_sse_mv = mbmi->mv[0];
ctx->best_reference_frame = mbmi->ref_frame[0];
}
}
int vp9_denoiser_alloc(VP9_DENOISER *denoiser, int width, int height,
int ssx, int ssy,
#if CONFIG_VP9_HIGHBITDEPTH
int use_highbitdepth,
#endif
int border) {
int i, fail;
const int legacy_byte_alignment = 0;
assert(denoiser != NULL);
for (i = 0; i < MAX_REF_FRAMES; ++i) {
fail = vp9_alloc_frame_buffer(&denoiser->running_avg_y[i], width, height,
ssx, ssy,
#if CONFIG_VP9_HIGHBITDEPTH
use_highbitdepth,
#endif
border, legacy_byte_alignment);
if (fail) {
vp9_denoiser_free(denoiser);
return 1;
}
#ifdef OUTPUT_YUV_DENOISED
make_grayscale(&denoiser->running_avg_y[i]);
#endif
}
fail = vp9_alloc_frame_buffer(&denoiser->mc_running_avg_y, width, height,
ssx, ssy,
#if CONFIG_VP9_HIGHBITDEPTH
use_highbitdepth,
#endif
border, legacy_byte_alignment);
if (fail) {
vp9_denoiser_free(denoiser);
return 1;
}
#ifdef OUTPUT_YUV_DENOISED
make_grayscale(&denoiser->running_avg_y[i]);
#endif
denoiser->increase_denoising = 0;
denoiser->frame_buffer_initialized = 1;
return 0;
}
void vp9_denoiser_free(VP9_DENOISER *denoiser) {
int i;
denoiser->frame_buffer_initialized = 0;
if (denoiser == NULL) {
return;
}
for (i = 0; i < MAX_REF_FRAMES; ++i) {
vp9_free_frame_buffer(&denoiser->running_avg_y[i]);
}
vp9_free_frame_buffer(&denoiser->mc_running_avg_y);
}
#ifdef OUTPUT_YUV_DENOISED
static void make_grayscale(YV12_BUFFER_CONFIG *yuv) {
int r, c;
uint8_t *u = yuv->u_buffer;
uint8_t *v = yuv->v_buffer;
for (r = 0; r < yuv->uv_height; ++r) {
for (c = 0; c < yuv->uv_width; ++c) {
u[c] = UINT8_MAX / 2;
v[c] = UINT8_MAX / 2;
}
u += yuv->uv_stride;
v += yuv->uv_stride;
}
}
#endif

View file

@ -0,0 +1,69 @@
/*
* Copyright (c) 2012 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.
*/
#ifndef VP9_ENCODER_DENOISER_H_
#define VP9_ENCODER_DENOISER_H_
#include "vp9/encoder/vp9_block.h"
#include "vpx_scale/yv12config.h"
#ifdef __cplusplus
extern "C" {
#endif
#define MOTION_MAGNITUDE_THRESHOLD (8 * 3)
typedef enum vp9_denoiser_decision {
COPY_BLOCK,
FILTER_BLOCK
} VP9_DENOISER_DECISION;
typedef struct vp9_denoiser {
YV12_BUFFER_CONFIG running_avg_y[MAX_REF_FRAMES];
YV12_BUFFER_CONFIG mc_running_avg_y;
int increase_denoising;
int frame_buffer_initialized;
} VP9_DENOISER;
void vp9_denoiser_update_frame_info(VP9_DENOISER *denoiser,
YV12_BUFFER_CONFIG src,
FRAME_TYPE frame_type,
int refresh_alt_ref_frame,
int refresh_golden_frame,
int refresh_last_frame);
void vp9_denoiser_denoise(VP9_DENOISER *denoiser, MACROBLOCK *mb,
int mi_row, int mi_col, BLOCK_SIZE bs,
PICK_MODE_CONTEXT *ctx);
void vp9_denoiser_reset_frame_stats(PICK_MODE_CONTEXT *ctx);
void vp9_denoiser_update_frame_stats(MB_MODE_INFO *mbmi,
unsigned int sse, PREDICTION_MODE mode,
PICK_MODE_CONTEXT *ctx);
int vp9_denoiser_alloc(VP9_DENOISER *denoiser, int width, int height,
int ssx, int ssy,
#if CONFIG_VP9_HIGHBITDEPTH
int use_highbitdepth,
#endif
int border);
#if CONFIG_VP9_TEMPORAL_DENOISING
int total_adj_strong_thresh(BLOCK_SIZE bs, int increase_denoising);
#endif
void vp9_denoiser_free(VP9_DENOISER *denoiser);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // VP9_ENCODER_DENOISER_H_

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,49 @@
/*
* 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.
*/
#ifndef VP9_ENCODER_VP9_ENCODEFRAME_H_
#define VP9_ENCODER_VP9_ENCODEFRAME_H_
#include "vpx/vpx_integer.h"
#ifdef __cplusplus
extern "C" {
#endif
struct macroblock;
struct yv12_buffer_config;
struct VP9_COMP;
struct ThreadData;
// Constants used in SOURCE_VAR_BASED_PARTITION
#define VAR_HIST_MAX_BG_VAR 1000
#define VAR_HIST_FACTOR 10
#define VAR_HIST_BINS (VAR_HIST_MAX_BG_VAR / VAR_HIST_FACTOR + 1)
#define VAR_HIST_LARGE_CUT_OFF 75
#define VAR_HIST_SMALL_CUT_OFF 45
void vp9_setup_src_planes(struct macroblock *x,
const struct yv12_buffer_config *src,
int mi_row, int mi_col);
void vp9_encode_frame(struct VP9_COMP *cpi);
void vp9_init_tile_data(struct VP9_COMP *cpi);
void vp9_encode_tile(struct VP9_COMP *cpi, struct ThreadData *td,
int tile_row, int tile_col);
void vp9_set_variance_partition_thresholds(struct VP9_COMP *cpi, int q);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // VP9_ENCODER_VP9_ENCODEFRAME_H_

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,46 @@
/*
* 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.
*/
#ifndef VP9_ENCODER_VP9_ENCODEMB_H_
#define VP9_ENCODER_VP9_ENCODEMB_H_
#include "./vpx_config.h"
#include "vp9/encoder/vp9_block.h"
#ifdef __cplusplus
extern "C" {
#endif
struct encode_b_args {
MACROBLOCK *x;
struct optimize_ctx *ctx;
int8_t *skip;
};
void vp9_encode_sb(MACROBLOCK *x, BLOCK_SIZE bsize);
void vp9_encode_sby_pass1(MACROBLOCK *x, BLOCK_SIZE bsize);
void vp9_xform_quant_fp(MACROBLOCK *x, int plane, int block,
BLOCK_SIZE plane_bsize, TX_SIZE tx_size);
void vp9_xform_quant_dc(MACROBLOCK *x, int plane, int block,
BLOCK_SIZE plane_bsize, TX_SIZE tx_size);
void vp9_xform_quant(MACROBLOCK *x, int plane, int block,
BLOCK_SIZE plane_bsize, TX_SIZE tx_size);
void vp9_subtract_plane(MACROBLOCK *x, BLOCK_SIZE bsize, int plane);
void vp9_encode_block_intra(int plane, int block, BLOCK_SIZE plane_bsize,
TX_SIZE tx_size, void *arg);
void vp9_encode_intra_block_plane(MACROBLOCK *x, BLOCK_SIZE bsize, int plane);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // VP9_ENCODER_VP9_ENCODEMB_H_

View file

@ -0,0 +1,266 @@
/*
* 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 <math.h>
#include "vp9/common/vp9_common.h"
#include "vp9/common/vp9_entropymode.h"
#include "vp9/common/vp9_systemdependent.h"
#include "vp9/encoder/vp9_cost.h"
#include "vp9/encoder/vp9_encodemv.h"
static struct vp9_token mv_joint_encodings[MV_JOINTS];
static struct vp9_token mv_class_encodings[MV_CLASSES];
static struct vp9_token mv_fp_encodings[MV_FP_SIZE];
static struct vp9_token mv_class0_encodings[CLASS0_SIZE];
void vp9_entropy_mv_init(void) {
vp9_tokens_from_tree(mv_joint_encodings, vp9_mv_joint_tree);
vp9_tokens_from_tree(mv_class_encodings, vp9_mv_class_tree);
vp9_tokens_from_tree(mv_class0_encodings, vp9_mv_class0_tree);
vp9_tokens_from_tree(mv_fp_encodings, vp9_mv_fp_tree);
}
static void encode_mv_component(vp9_writer* w, int comp,
const nmv_component* mvcomp, int usehp) {
int offset;
const int sign = comp < 0;
const int mag = sign ? -comp : comp;
const int mv_class = vp9_get_mv_class(mag - 1, &offset);
const int d = offset >> 3; // int mv data
const int fr = (offset >> 1) & 3; // fractional mv data
const int hp = offset & 1; // high precision mv data
assert(comp != 0);
// Sign
vp9_write(w, sign, mvcomp->sign);
// Class
vp9_write_token(w, vp9_mv_class_tree, mvcomp->classes,
&mv_class_encodings[mv_class]);
// Integer bits
if (mv_class == MV_CLASS_0) {
vp9_write_token(w, vp9_mv_class0_tree, mvcomp->class0,
&mv_class0_encodings[d]);
} else {
int i;
const int n = mv_class + CLASS0_BITS - 1; // number of bits
for (i = 0; i < n; ++i)
vp9_write(w, (d >> i) & 1, mvcomp->bits[i]);
}
// Fractional bits
vp9_write_token(w, vp9_mv_fp_tree,
mv_class == MV_CLASS_0 ? mvcomp->class0_fp[d] : mvcomp->fp,
&mv_fp_encodings[fr]);
// High precision bit
if (usehp)
vp9_write(w, hp,
mv_class == MV_CLASS_0 ? mvcomp->class0_hp : mvcomp->hp);
}
static void build_nmv_component_cost_table(int *mvcost,
const nmv_component* const mvcomp,
int usehp) {
int i, v;
int sign_cost[2], class_cost[MV_CLASSES], class0_cost[CLASS0_SIZE];
int bits_cost[MV_OFFSET_BITS][2];
int class0_fp_cost[CLASS0_SIZE][MV_FP_SIZE], fp_cost[MV_FP_SIZE];
int class0_hp_cost[2], hp_cost[2];
sign_cost[0] = vp9_cost_zero(mvcomp->sign);
sign_cost[1] = vp9_cost_one(mvcomp->sign);
vp9_cost_tokens(class_cost, mvcomp->classes, vp9_mv_class_tree);
vp9_cost_tokens(class0_cost, mvcomp->class0, vp9_mv_class0_tree);
for (i = 0; i < MV_OFFSET_BITS; ++i) {
bits_cost[i][0] = vp9_cost_zero(mvcomp->bits[i]);
bits_cost[i][1] = vp9_cost_one(mvcomp->bits[i]);
}
for (i = 0; i < CLASS0_SIZE; ++i)
vp9_cost_tokens(class0_fp_cost[i], mvcomp->class0_fp[i], vp9_mv_fp_tree);
vp9_cost_tokens(fp_cost, mvcomp->fp, vp9_mv_fp_tree);
if (usehp) {
class0_hp_cost[0] = vp9_cost_zero(mvcomp->class0_hp);
class0_hp_cost[1] = vp9_cost_one(mvcomp->class0_hp);
hp_cost[0] = vp9_cost_zero(mvcomp->hp);
hp_cost[1] = vp9_cost_one(mvcomp->hp);
}
mvcost[0] = 0;
for (v = 1; v <= MV_MAX; ++v) {
int z, c, o, d, e, f, cost = 0;
z = v - 1;
c = vp9_get_mv_class(z, &o);
cost += class_cost[c];
d = (o >> 3); /* int mv data */
f = (o >> 1) & 3; /* fractional pel mv data */
e = (o & 1); /* high precision mv data */
if (c == MV_CLASS_0) {
cost += class0_cost[d];
} else {
int i, b;
b = c + CLASS0_BITS - 1; /* number of bits */
for (i = 0; i < b; ++i)
cost += bits_cost[i][((d >> i) & 1)];
}
if (c == MV_CLASS_0) {
cost += class0_fp_cost[d][f];
} else {
cost += fp_cost[f];
}
if (usehp) {
if (c == MV_CLASS_0) {
cost += class0_hp_cost[e];
} else {
cost += hp_cost[e];
}
}
mvcost[v] = cost + sign_cost[0];
mvcost[-v] = cost + sign_cost[1];
}
}
static int update_mv(vp9_writer *w, const unsigned int ct[2], vp9_prob *cur_p,
vp9_prob upd_p) {
const vp9_prob new_p = get_binary_prob(ct[0], ct[1]) | 1;
const int update = cost_branch256(ct, *cur_p) + vp9_cost_zero(upd_p) >
cost_branch256(ct, new_p) + vp9_cost_one(upd_p) + 7 * 256;
vp9_write(w, update, upd_p);
if (update) {
*cur_p = new_p;
vp9_write_literal(w, new_p >> 1, 7);
}
return update;
}
static void write_mv_update(const vp9_tree_index *tree,
vp9_prob probs[/*n - 1*/],
const unsigned int counts[/*n - 1*/],
int n, vp9_writer *w) {
int i;
unsigned int branch_ct[32][2];
// Assuming max number of probabilities <= 32
assert(n <= 32);
vp9_tree_probs_from_distribution(tree, branch_ct, counts);
for (i = 0; i < n - 1; ++i)
update_mv(w, branch_ct[i], &probs[i], MV_UPDATE_PROB);
}
void vp9_write_nmv_probs(VP9_COMMON *cm, int usehp, vp9_writer *w,
nmv_context_counts *const counts) {
int i, j;
nmv_context *const mvc = &cm->fc->nmvc;
write_mv_update(vp9_mv_joint_tree, mvc->joints, counts->joints, MV_JOINTS, w);
for (i = 0; i < 2; ++i) {
nmv_component *comp = &mvc->comps[i];
nmv_component_counts *comp_counts = &counts->comps[i];
update_mv(w, comp_counts->sign, &comp->sign, MV_UPDATE_PROB);
write_mv_update(vp9_mv_class_tree, comp->classes, comp_counts->classes,
MV_CLASSES, w);
write_mv_update(vp9_mv_class0_tree, comp->class0, comp_counts->class0,
CLASS0_SIZE, w);
for (j = 0; j < MV_OFFSET_BITS; ++j)
update_mv(w, comp_counts->bits[j], &comp->bits[j], MV_UPDATE_PROB);
}
for (i = 0; i < 2; ++i) {
for (j = 0; j < CLASS0_SIZE; ++j)
write_mv_update(vp9_mv_fp_tree, mvc->comps[i].class0_fp[j],
counts->comps[i].class0_fp[j], MV_FP_SIZE, w);
write_mv_update(vp9_mv_fp_tree, mvc->comps[i].fp, counts->comps[i].fp,
MV_FP_SIZE, w);
}
if (usehp) {
for (i = 0; i < 2; ++i) {
update_mv(w, counts->comps[i].class0_hp, &mvc->comps[i].class0_hp,
MV_UPDATE_PROB);
update_mv(w, counts->comps[i].hp, &mvc->comps[i].hp, MV_UPDATE_PROB);
}
}
}
void vp9_encode_mv(VP9_COMP* cpi, vp9_writer* w,
const MV* mv, const MV* ref,
const nmv_context* mvctx, int usehp) {
const MV diff = {mv->row - ref->row,
mv->col - ref->col};
const MV_JOINT_TYPE j = vp9_get_mv_joint(&diff);
usehp = usehp && vp9_use_mv_hp(ref);
vp9_write_token(w, vp9_mv_joint_tree, mvctx->joints, &mv_joint_encodings[j]);
if (mv_joint_vertical(j))
encode_mv_component(w, diff.row, &mvctx->comps[0], usehp);
if (mv_joint_horizontal(j))
encode_mv_component(w, diff.col, &mvctx->comps[1], usehp);
// If auto_mv_step_size is enabled then keep track of the largest
// motion vector component used.
if (cpi->sf.mv.auto_mv_step_size) {
unsigned int maxv = MAX(abs(mv->row), abs(mv->col)) >> 3;
cpi->max_mv_magnitude = MAX(maxv, cpi->max_mv_magnitude);
}
}
void vp9_build_nmv_cost_table(int *mvjoint, int *mvcost[2],
const nmv_context* ctx, int usehp) {
vp9_cost_tokens(mvjoint, ctx->joints, vp9_mv_joint_tree);
build_nmv_component_cost_table(mvcost[0], &ctx->comps[0], usehp);
build_nmv_component_cost_table(mvcost[1], &ctx->comps[1], usehp);
}
static void inc_mvs(const MB_MODE_INFO *mbmi, const int_mv mvs[2],
nmv_context_counts *counts) {
int i;
for (i = 0; i < 1 + has_second_ref(mbmi); ++i) {
const MV *ref = &mbmi->ref_mvs[mbmi->ref_frame[i]][0].as_mv;
const MV diff = {mvs[i].as_mv.row - ref->row,
mvs[i].as_mv.col - ref->col};
vp9_inc_mv(&diff, counts);
}
}
void vp9_update_mv_count(ThreadData *td) {
const MACROBLOCKD *xd = &td->mb.e_mbd;
const MODE_INFO *mi = xd->mi[0];
const MB_MODE_INFO *const mbmi = &mi->mbmi;
if (mbmi->sb_type < BLOCK_8X8) {
const int num_4x4_w = num_4x4_blocks_wide_lookup[mbmi->sb_type];
const int num_4x4_h = num_4x4_blocks_high_lookup[mbmi->sb_type];
int idx, idy;
for (idy = 0; idy < 2; idy += num_4x4_h) {
for (idx = 0; idx < 2; idx += num_4x4_w) {
const int i = idy * 2 + idx;
if (mi->bmi[i].as_mode == NEWMV)
inc_mvs(mbmi, mi->bmi[i].as_mv, &td->counts->mv);
}
}
} else {
if (mbmi->mode == NEWMV)
inc_mvs(mbmi, mbmi->mv, &td->counts->mv);
}
}

View file

@ -0,0 +1,38 @@
/*
* 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.
*/
#ifndef VP9_ENCODER_VP9_ENCODEMV_H_
#define VP9_ENCODER_VP9_ENCODEMV_H_
#include "vp9/encoder/vp9_encoder.h"
#ifdef __cplusplus
extern "C" {
#endif
void vp9_entropy_mv_init(void);
void vp9_write_nmv_probs(VP9_COMMON *cm, int usehp, vp9_writer *w,
nmv_context_counts *const counts);
void vp9_encode_mv(VP9_COMP *cpi, vp9_writer* w, const MV* mv, const MV* ref,
const nmv_context* mvctx, int usehp);
void vp9_build_nmv_cost_table(int *mvjoint, int *mvcost[2],
const nmv_context* mvctx, int usehp);
void vp9_update_mv_count(ThreadData *td);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // VP9_ENCODER_VP9_ENCODEMV_H_

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,654 @@
/*
* 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.
*/
#ifndef VP9_ENCODER_VP9_ENCODER_H_
#define VP9_ENCODER_VP9_ENCODER_H_
#include <stdio.h>
#include "./vpx_config.h"
#include "vpx/internal/vpx_codec_internal.h"
#include "vpx/vp8cx.h"
#include "vp9/common/vp9_alloccommon.h"
#include "vp9/common/vp9_ppflags.h"
#include "vp9/common/vp9_entropymode.h"
#include "vp9/common/vp9_thread_common.h"
#include "vp9/common/vp9_onyxc_int.h"
#include "vp9/common/vp9_thread.h"
#include "vp9/encoder/vp9_aq_cyclicrefresh.h"
#include "vp9/encoder/vp9_context_tree.h"
#include "vp9/encoder/vp9_encodemb.h"
#include "vp9/encoder/vp9_firstpass.h"
#include "vp9/encoder/vp9_lookahead.h"
#include "vp9/encoder/vp9_mbgraph.h"
#include "vp9/encoder/vp9_mcomp.h"
#include "vp9/encoder/vp9_quantize.h"
#include "vp9/encoder/vp9_ratectrl.h"
#include "vp9/encoder/vp9_rd.h"
#if CONFIG_INTERNAL_STATS
#include "vp9/encoder/vp9_ssim.h"
#endif
#include "vp9/encoder/vp9_speed_features.h"
#include "vp9/encoder/vp9_svc_layercontext.h"
#include "vp9/encoder/vp9_tokenize.h"
#include "vp9/encoder/vp9_variance.h"
#if CONFIG_VP9_TEMPORAL_DENOISING
#include "vp9/encoder/vp9_denoiser.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
#define DEFAULT_GF_INTERVAL 10
typedef struct {
int nmvjointcost[MV_JOINTS];
int nmvcosts[2][MV_VALS];
int nmvcosts_hp[2][MV_VALS];
vp9_prob segment_pred_probs[PREDICTION_PROBS];
unsigned char *last_frame_seg_map_copy;
// 0 = Intra, Last, GF, ARF
signed char last_ref_lf_deltas[MAX_REF_LF_DELTAS];
// 0 = ZERO_MV, MV
signed char last_mode_lf_deltas[MAX_MODE_LF_DELTAS];
FRAME_CONTEXT fc;
} CODING_CONTEXT;
typedef enum {
// encode_breakout is disabled.
ENCODE_BREAKOUT_DISABLED = 0,
// encode_breakout is enabled.
ENCODE_BREAKOUT_ENABLED = 1,
// encode_breakout is enabled with small max_thresh limit.
ENCODE_BREAKOUT_LIMITED = 2
} ENCODE_BREAKOUT_TYPE;
typedef enum {
NORMAL = 0,
FOURFIVE = 1,
THREEFIVE = 2,
ONETWO = 3
} VPX_SCALING;
typedef 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,
// The encoder places priority on the quality of the output over encoding
// speed. The output is compressed at the highest possible quality. This
// option takes the longest amount of time to encode. Speed setting ignored.
BEST,
// Realtime/Live Encoding. This mode is optimized for realtime encoding (for
// example, capturing a television signal or feed from a live camera). Speed
// setting controls how fast.
REALTIME
} MODE;
typedef enum {
FRAMEFLAGS_KEY = 1 << 0,
FRAMEFLAGS_GOLDEN = 1 << 1,
FRAMEFLAGS_ALTREF = 1 << 2,
} FRAMETYPE_FLAGS;
typedef 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 {
RESIZE_NONE = 0, // No frame resizing allowed (except for SVC).
RESIZE_FIXED = 1, // All frames are coded at the specified dimension.
RESIZE_DYNAMIC = 2 // Coded size of each frame is determined by the codec.
} RESIZE_TYPE;
typedef struct VP9EncoderConfig {
BITSTREAM_PROFILE profile;
vpx_bit_depth_t bit_depth; // Codec bit-depth.
int width; // width of data passed to the compressor
int height; // height of data passed to the compressor
unsigned int input_bit_depth; // Input bit depth.
double init_framerate; // set to passed in framerate
int64_t target_bandwidth; // bandwidth to be used in kilobits per second
int noise_sensitivity; // pre processing blur: recommendation 0
int sharpness; // sharpening output: recommendation 0:
int speed;
// maximum allowed bitrate for any intra frame in % of bitrate target.
unsigned int rc_max_intra_bitrate_pct;
// maximum allowed bitrate for any inter frame in % of bitrate target.
unsigned int rc_max_inter_bitrate_pct;
// percent of rate boost for golden frame in CBR mode.
unsigned int gf_cbr_boost_pct;
MODE mode;
int pass;
// Key Framing Operations
int auto_key; // autodetect cut scenes and set the keyframes
int key_freq; // maximum distance to key frame.
int lag_in_frames; // how many frames lag before we start encoding
// ----------------------------------------------------------------
// DATARATE CONTROL OPTIONS
// vbr, cbr, constrained quality or constant quality
enum vpx_rc_mode rc_mode;
// buffer targeting aggressiveness
int under_shoot_pct;
int over_shoot_pct;
// buffering parameters
int64_t starting_buffer_level_ms;
int64_t optimal_buffer_level_ms;
int64_t maximum_buffer_size_ms;
// Frame drop threshold.
int drop_frames_water_mark;
// controlling quality
int fixed_q;
int worst_allowed_q;
int best_allowed_q;
int cq_level;
AQ_MODE aq_mode; // Adaptive Quantization mode
// Internal frame size scaling.
RESIZE_TYPE resize_mode;
int scaled_frame_width;
int scaled_frame_height;
// Enable feature to reduce the frame quantization every x frames.
int frame_periodic_boost;
// two pass datarate control
int two_pass_vbrbias; // two pass datarate control tweaks
int two_pass_vbrmin_section;
int two_pass_vbrmax_section;
// END DATARATE CONTROL OPTIONS
// ----------------------------------------------------------------
// Spatial and temporal scalability.
int ss_number_layers; // Number of spatial layers.
int ts_number_layers; // Number of temporal layers.
// Bitrate allocation for spatial layers.
int layer_target_bitrate[VPX_MAX_LAYERS];
int ss_target_bitrate[VPX_SS_MAX_LAYERS];
int ss_enable_auto_arf[VPX_SS_MAX_LAYERS];
// Bitrate allocation (CBR mode) and framerate factor, for temporal layers.
int ts_rate_decimator[VPX_TS_MAX_LAYERS];
int enable_auto_arf;
int encode_breakout; // early breakout : for video conf recommend 800
/* Bitfield defining the error resiliency features to enable.
* Can provide decodable frames after losses in previous
* frames and decodable partitions after losses in the same frame.
*/
unsigned int error_resilient_mode;
/* Bitfield defining the parallel decoding mode where the
* decoding in successive frames may be conducted in parallel
* just by decoding the frame headers.
*/
unsigned int frame_parallel_decoding_mode;
int arnr_max_frames;
int arnr_strength;
int tile_columns;
int tile_rows;
int max_threads;
vpx_fixed_buf_t two_pass_stats_in;
struct vpx_codec_pkt_list *output_pkt_list;
#if CONFIG_FP_MB_STATS
vpx_fixed_buf_t firstpass_mb_stats_in;
#endif
vp8e_tuning tuning;
vp9e_tune_content content;
#if CONFIG_VP9_HIGHBITDEPTH
int use_highbitdepth;
#endif
vpx_color_space_t color_space;
VP9E_TEMPORAL_LAYERING_MODE temporal_layering_mode;
} VP9EncoderConfig;
static INLINE int is_lossless_requested(const VP9EncoderConfig *cfg) {
return cfg->best_allowed_q == 0 && cfg->worst_allowed_q == 0;
}
// TODO(jingning) All spatially adaptive variables should go to TileDataEnc.
typedef struct TileDataEnc {
TileInfo tile_info;
int thresh_freq_fact[BLOCK_SIZES][MAX_MODES];
int mode_map[BLOCK_SIZES][MAX_MODES];
} TileDataEnc;
typedef struct RD_COUNTS {
vp9_coeff_count coef_counts[TX_SIZES][PLANE_TYPES];
int64_t comp_pred_diff[REFERENCE_MODES];
int64_t tx_select_diff[TX_MODES];
int64_t filter_diff[SWITCHABLE_FILTER_CONTEXTS];
} RD_COUNTS;
typedef struct ThreadData {
MACROBLOCK mb;
RD_COUNTS rd_counts;
FRAME_COUNTS *counts;
PICK_MODE_CONTEXT *leaf_tree;
PC_TREE *pc_tree;
PC_TREE *pc_root;
} ThreadData;
struct EncWorkerData;
typedef struct ActiveMap {
int enabled;
int update;
unsigned char *map;
} ActiveMap;
typedef enum {
Y,
U,
V,
ALL
} STAT_TYPE;
typedef struct IMAGE_STAT {
double stat[ALL+1];
double worst;
} ImageStat;
typedef struct VP9_COMP {
QUANTS quants;
ThreadData td;
DECLARE_ALIGNED(16, int16_t, y_dequant[QINDEX_RANGE][8]);
DECLARE_ALIGNED(16, int16_t, uv_dequant[QINDEX_RANGE][8]);
VP9_COMMON common;
VP9EncoderConfig oxcf;
struct lookahead_ctx *lookahead;
struct lookahead_entry *alt_ref_source;
YV12_BUFFER_CONFIG *Source;
YV12_BUFFER_CONFIG *Last_Source; // NULL for first frame and alt_ref frames
YV12_BUFFER_CONFIG *un_scaled_source;
YV12_BUFFER_CONFIG scaled_source;
YV12_BUFFER_CONFIG *unscaled_last_source;
YV12_BUFFER_CONFIG scaled_last_source;
TileDataEnc *tile_data;
// For a still frame, this flag is set to 1 to skip partition search.
int partition_search_skippable_frame;
int scaled_ref_idx[MAX_REF_FRAMES];
int lst_fb_idx;
int gld_fb_idx;
int alt_fb_idx;
int refresh_last_frame;
int refresh_golden_frame;
int refresh_alt_ref_frame;
int ext_refresh_frame_flags_pending;
int ext_refresh_last_frame;
int ext_refresh_golden_frame;
int ext_refresh_alt_ref_frame;
int ext_refresh_frame_context_pending;
int ext_refresh_frame_context;
YV12_BUFFER_CONFIG last_frame_uf;
TOKENEXTRA *tile_tok[4][1 << 6];
unsigned int tok_count[4][1 << 6];
// Ambient reconstruction err target for force key frames
int64_t ambient_err;
RD_OPT rd;
CODING_CONTEXT coding_context;
int *nmvcosts[2];
int *nmvcosts_hp[2];
int *nmvsadcosts[2];
int *nmvsadcosts_hp[2];
int64_t last_time_stamp_seen;
int64_t last_end_time_stamp_seen;
int64_t first_time_stamp_ever;
RATE_CONTROL rc;
double framerate;
int interp_filter_selected[MAX_REF_FRAMES][SWITCHABLE];
struct vpx_codec_pkt_list *output_pkt_list;
MBGRAPH_FRAME_STATS mbgraph_stats[MAX_LAG_BUFFERS];
int mbgraph_n_frames; // number of frames filled in the above
int static_mb_pct; // % forced skip mbs by segmentation
int ref_frame_flags;
SPEED_FEATURES sf;
unsigned int max_mv_magnitude;
int mv_step_param;
int allow_comp_inter_inter;
// Default value is 1. From first pass stats, encode_breakout may be disabled.
ENCODE_BREAKOUT_TYPE allow_encode_breakout;
// Get threshold from external input. A suggested threshold is 800 for HD
// clips, and 300 for < HD clips.
int encode_breakout;
unsigned char *segmentation_map;
// segment threashold for encode breakout
int segment_encode_breakout[MAX_SEGMENTS];
CYCLIC_REFRESH *cyclic_refresh;
ActiveMap active_map;
fractional_mv_step_fp *find_fractional_mv_step;
vp9_full_search_fn_t full_search_sad;
vp9_diamond_search_fn_t diamond_search_sad;
vp9_variance_fn_ptr_t fn_ptr[BLOCK_SIZES];
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;
#endif
TWO_PASS twopass;
YV12_BUFFER_CONFIG alt_ref_buffer;
#if CONFIG_INTERNAL_STATS
unsigned int mode_chosen_counts[MAX_MODES];
int count;
uint64_t total_sq_error;
uint64_t total_samples;
ImageStat psnr;
uint64_t totalp_sq_error;
uint64_t totalp_samples;
ImageStat psnrp;
double total_blockiness;
double worst_blockiness;
int bytes;
double summed_quality;
double summed_weights;
double summedp_quality;
double summedp_weights;
unsigned int tot_recode_hits;
double worst_ssim;
ImageStat ssimg;
ImageStat fastssim;
ImageStat psnrhvs;
int b_calculate_ssimg;
int b_calculate_blockiness;
int b_calculate_consistency;
double total_inconsistency;
double worst_consistency;
Ssimv *ssim_vars;
Metrics metrics;
#endif
int b_calculate_psnr;
int droppable;
int initial_width;
int initial_height;
int initial_mbs; // Number of MBs in the full-size frame; to be used to
// normalize the firstpass stats. This will differ from the
// number of MBs in the current frame when the frame is
// scaled.
int use_svc;
SVC svc;
// Store frame variance info in SOURCE_VAR_BASED_PARTITION search type.
diff *source_diff_var;
// The threshold used in SOURCE_VAR_BASED_PARTITION search type.
unsigned int source_var_thresh;
int frames_till_next_var_check;
int frame_flags;
search_site_config ss_cfg;
int mbmode_cost[INTRA_MODES];
unsigned int inter_mode_cost[INTER_MODE_CONTEXTS][INTER_MODES];
int intra_uv_mode_cost[FRAME_TYPES][INTRA_MODES];
int y_mode_costs[INTRA_MODES][INTRA_MODES][INTRA_MODES];
int switchable_interp_costs[SWITCHABLE_FILTER_CONTEXTS][SWITCHABLE_FILTERS];
int partition_cost[PARTITION_CONTEXTS][PARTITION_TYPES];
int multi_arf_allowed;
int multi_arf_enabled;
int multi_arf_last_grp_enabled;
#if CONFIG_VP9_TEMPORAL_DENOISING
VP9_DENOISER denoiser;
#endif
int resize_pending;
// VAR_BASED_PARTITION thresholds
// 0 - threshold_64x64; 1 - threshold_32x32;
// 2 - threshold_16x16; 3 - vbp_threshold_8x8;
int64_t vbp_thresholds[4];
int64_t vbp_threshold_minmax;
int64_t vbp_threshold_sad;
BLOCK_SIZE vbp_bsize_min;
// Multi-threading
int num_workers;
VP9Worker *workers;
struct EncWorkerData *tile_thr_data;
VP9LfSync lf_row_sync;
} VP9_COMP;
void vp9_initialize_enc(void);
struct VP9_COMP *vp9_create_compressor(VP9EncoderConfig *oxcf,
BufferPool *const pool);
void vp9_remove_compressor(VP9_COMP *cpi);
void vp9_change_config(VP9_COMP *cpi, const VP9EncoderConfig *oxcf);
// receive a frames worth of data. caller can assume that a copy of this
// frame is made and not just a copy of the pointer..
int vp9_receive_raw_frame(VP9_COMP *cpi, unsigned int frame_flags,
YV12_BUFFER_CONFIG *sd, int64_t time_stamp,
int64_t end_time_stamp);
int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags,
size_t *size, uint8_t *dest,
int64_t *time_stamp, int64_t *time_end, int flush);
int vp9_get_preview_raw_frame(VP9_COMP *cpi, YV12_BUFFER_CONFIG *dest,
vp9_ppflags_t *flags);
int vp9_use_as_reference(VP9_COMP *cpi, int ref_frame_flags);
void vp9_update_reference(VP9_COMP *cpi, int ref_frame_flags);
int vp9_copy_reference_enc(VP9_COMP *cpi, VP9_REFFRAME ref_frame_flag,
YV12_BUFFER_CONFIG *sd);
int vp9_set_reference_enc(VP9_COMP *cpi, VP9_REFFRAME ref_frame_flag,
YV12_BUFFER_CONFIG *sd);
int vp9_update_entropy(VP9_COMP *cpi, int update);
int vp9_set_active_map(VP9_COMP *cpi, unsigned char *map, int rows, int cols);
int vp9_get_active_map(VP9_COMP *cpi, unsigned char *map, int rows, int cols);
int vp9_set_internal_size(VP9_COMP *cpi,
VPX_SCALING horiz_mode, VPX_SCALING vert_mode);
int vp9_set_size_literal(VP9_COMP *cpi, unsigned int width,
unsigned int height);
void vp9_set_svc(VP9_COMP *cpi, int use_svc);
int vp9_get_quantizer(struct VP9_COMP *cpi);
static INLINE int frame_is_kf_gf_arf(const VP9_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 VP9_COMP *cpi,
MV_REFERENCE_FRAME ref_frame) {
if (ref_frame == LAST_FRAME) {
return cpi->lst_fb_idx;
} else if (ref_frame == GOLDEN_FRAME) {
return cpi->gld_fb_idx;
} else {
return cpi->alt_fb_idx;
}
}
static INLINE int get_ref_frame_buf_idx(const VP9_COMP *const cpi,
int ref_frame) {
const VP9_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;
}
static INLINE YV12_BUFFER_CONFIG *get_ref_frame_buffer(
VP9_COMP *cpi, MV_REFERENCE_FRAME ref_frame) {
VP9_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 int get_token_alloc(int mb_rows, int mb_cols) {
// TODO(JBB): double check we can't exceed this token count if we have a
// 32x32 transform crossing a boundary at a multiple of 16.
// mb_rows, cols are in units of 16 pixels. We assume 3 planes all at full
// resolution. We assume up to 1 token per pixel, and then allow
// a head room of 4.
return mb_rows * mb_cols * (16 * 16 * 3 + 4);
}
// Get the allocated token size for a tile. It does the same calculation as in
// the frame token allocation.
static INLINE int allocated_tokens(TileInfo tile) {
int tile_mb_rows = (tile.mi_row_end - tile.mi_row_start + 1) >> 1;
int tile_mb_cols = (tile.mi_col_end - tile.mi_col_start + 1) >> 1;
return get_token_alloc(tile_mb_rows, tile_mb_cols);
}
int64_t vp9_get_y_sse(const YV12_BUFFER_CONFIG *a, const YV12_BUFFER_CONFIG *b);
#if CONFIG_VP9_HIGHBITDEPTH
int64_t vp9_highbd_get_y_sse(const YV12_BUFFER_CONFIG *a,
const YV12_BUFFER_CONFIG *b);
#endif // CONFIG_VP9_HIGHBITDEPTH
void vp9_alloc_compressor_data(VP9_COMP *cpi);
void vp9_scale_references(VP9_COMP *cpi);
void vp9_update_reference_frames(VP9_COMP *cpi);
void vp9_set_high_precision_mv(VP9_COMP *cpi, int allow_high_precision_mv);
YV12_BUFFER_CONFIG *vp9_scale_if_required(VP9_COMMON *cm,
YV12_BUFFER_CONFIG *unscaled,
YV12_BUFFER_CONFIG *scaled);
void vp9_apply_encoding_flags(VP9_COMP *cpi, vpx_enc_frame_flags_t flags);
static INLINE int is_two_pass_svc(const struct VP9_COMP *const cpi) {
return cpi->use_svc && cpi->oxcf.pass != 0;
}
static INLINE int is_one_pass_cbr_svc(const struct VP9_COMP *const cpi) {
return (cpi->use_svc && cpi->oxcf.pass == 0);
}
static INLINE int is_altref_enabled(const VP9_COMP *const cpi) {
return cpi->oxcf.mode != REALTIME && cpi->oxcf.lag_in_frames > 0 &&
(cpi->oxcf.enable_auto_arf &&
(!is_two_pass_svc(cpi) ||
cpi->oxcf.ss_enable_auto_arf[cpi->svc.spatial_layer_id]));
}
static INLINE void set_ref_ptrs(VP9_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];
}
static INLINE int get_chessboard_index(const int frame_index) {
return frame_index & 0x1;
}
static INLINE int *cond_cost_list(const struct VP9_COMP *cpi, int *cost_list) {
return cpi->sf.mv.subpel_search_method != SUBPEL_TREE ? cost_list : NULL;
}
void vp9_new_framerate(VP9_COMP *cpi, double framerate);
#define LAYER_IDS_TO_IDX(sl, tl, num_tl) ((sl) * (num_tl) + (tl))
#ifdef __cplusplus
} // extern "C"
#endif
#endif // VP9_ENCODER_VP9_ENCODER_H_

View file

@ -0,0 +1,179 @@
/*
* Copyright (c) 2014 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 "vp9/encoder/vp9_encodeframe.h"
#include "vp9/encoder/vp9_encoder.h"
#include "vp9/encoder/vp9_ethread.h"
static void accumulate_rd_opt(ThreadData *td, ThreadData *td_t) {
int i, j, k, l, m, n;
for (i = 0; i < REFERENCE_MODES; i++)
td->rd_counts.comp_pred_diff[i] += td_t->rd_counts.comp_pred_diff[i];
for (i = 0; i < SWITCHABLE_FILTER_CONTEXTS; i++)
td->rd_counts.filter_diff[i] += td_t->rd_counts.filter_diff[i];
for (i = 0; i < TX_MODES; i++)
td->rd_counts.tx_select_diff[i] += td_t->rd_counts.tx_select_diff[i];
for (i = 0; i < TX_SIZES; i++)
for (j = 0; j < PLANE_TYPES; j++)
for (k = 0; k < REF_TYPES; k++)
for (l = 0; l < COEF_BANDS; l++)
for (m = 0; m < COEFF_CONTEXTS; m++)
for (n = 0; n < ENTROPY_TOKENS; n++)
td->rd_counts.coef_counts[i][j][k][l][m][n] +=
td_t->rd_counts.coef_counts[i][j][k][l][m][n];
}
static int enc_worker_hook(EncWorkerData *const thread_data, void *unused) {
VP9_COMP *const cpi = thread_data->cpi;
const VP9_COMMON *const cm = &cpi->common;
const int tile_cols = 1 << cm->log2_tile_cols;
const int tile_rows = 1 << cm->log2_tile_rows;
int t;
(void) unused;
for (t = thread_data->start; t < tile_rows * tile_cols;
t += cpi->num_workers) {
int tile_row = t / tile_cols;
int tile_col = t % tile_cols;
vp9_encode_tile(cpi, thread_data->td, tile_row, tile_col);
}
return 0;
}
void vp9_encode_tiles_mt(VP9_COMP *cpi) {
VP9_COMMON *const cm = &cpi->common;
const int tile_cols = 1 << cm->log2_tile_cols;
const VP9WorkerInterface *const winterface = vp9_get_worker_interface();
const int num_workers = MIN(cpi->oxcf.max_threads, tile_cols);
int i;
vp9_init_tile_data(cpi);
// Only run once to create threads and allocate thread data.
if (cpi->num_workers == 0) {
CHECK_MEM_ERROR(cm, cpi->workers,
vpx_malloc(num_workers * sizeof(*cpi->workers)));
CHECK_MEM_ERROR(cm, cpi->tile_thr_data,
vpx_calloc(num_workers, sizeof(*cpi->tile_thr_data)));
for (i = 0; i < num_workers; i++) {
VP9Worker *const worker = &cpi->workers[i];
EncWorkerData *thread_data = &cpi->tile_thr_data[i];
++cpi->num_workers;
winterface->init(worker);
if (i < num_workers - 1) {
thread_data->cpi = cpi;
// Allocate thread data.
CHECK_MEM_ERROR(cm, thread_data->td,
vpx_memalign(32, sizeof(*thread_data->td)));
vp9_zero(*thread_data->td);
// Set up pc_tree.
thread_data->td->leaf_tree = NULL;
thread_data->td->pc_tree = NULL;
vp9_setup_pc_tree(cm, thread_data->td);
// Allocate frame counters in thread data.
CHECK_MEM_ERROR(cm, thread_data->td->counts,
vpx_calloc(1, sizeof(*thread_data->td->counts)));
// Create threads
if (!winterface->reset(worker))
vpx_internal_error(&cm->error, VPX_CODEC_ERROR,
"Tile encoder thread creation failed");
} else {
// Main thread acts as a worker and uses the thread data in cpi.
thread_data->cpi = cpi;
thread_data->td = &cpi->td;
}
winterface->sync(worker);
}
}
for (i = 0; i < num_workers; i++) {
VP9Worker *const worker = &cpi->workers[i];
EncWorkerData *thread_data;
worker->hook = (VP9WorkerHook)enc_worker_hook;
worker->data1 = &cpi->tile_thr_data[i];
worker->data2 = NULL;
thread_data = (EncWorkerData*)worker->data1;
// Before encoding a frame, copy the thread data from cpi.
if (thread_data->td != &cpi->td) {
thread_data->td->mb = cpi->td.mb;
thread_data->td->rd_counts = cpi->td.rd_counts;
}
if (thread_data->td->counts != &cpi->common.counts) {
memcpy(thread_data->td->counts, &cpi->common.counts,
sizeof(cpi->common.counts));
}
// Handle use_nonrd_pick_mode case.
if (cpi->sf.use_nonrd_pick_mode) {
MACROBLOCK *const x = &thread_data->td->mb;
MACROBLOCKD *const xd = &x->e_mbd;
struct macroblock_plane *const p = x->plane;
struct macroblockd_plane *const pd = xd->plane;
PICK_MODE_CONTEXT *ctx = &thread_data->td->pc_root->none;
int j;
for (j = 0; j < MAX_MB_PLANE; ++j) {
p[j].coeff = ctx->coeff_pbuf[j][0];
p[j].qcoeff = ctx->qcoeff_pbuf[j][0];
pd[j].dqcoeff = ctx->dqcoeff_pbuf[j][0];
p[j].eobs = ctx->eobs_pbuf[j][0];
}
}
}
// Encode a frame
for (i = 0; i < num_workers; i++) {
VP9Worker *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 == num_workers - 1)
winterface->execute(worker);
else
winterface->launch(worker);
}
// Encoding ends.
for (i = 0; i < num_workers; i++) {
VP9Worker *const worker = &cpi->workers[i];
winterface->sync(worker);
}
for (i = 0; i < num_workers; i++) {
VP9Worker *const worker = &cpi->workers[i];
EncWorkerData *const thread_data = (EncWorkerData*)worker->data1;
// Accumulate counters.
if (i < num_workers - 1) {
vp9_accumulate_frame_counts(cm, thread_data->td->counts, 0);
accumulate_rd_opt(&cpi->td, thread_data->td);
}
}
}

View file

@ -0,0 +1,25 @@
/*
* Copyright (c) 2014 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.
*/
#ifndef VP9_ENCODER_VP9_ETHREAD_H_
#define VP9_ENCODER_VP9_ETHREAD_H_
struct VP9_COMP;
struct ThreadData;
typedef struct EncWorkerData {
struct VP9_COMP *cpi;
struct ThreadData *td;
int start;
} EncWorkerData;
void vp9_encode_tiles_mt(struct VP9_COMP *cpi);
#endif // VP9_ENCODER_VP9_ETHREAD_H_

View file

@ -0,0 +1,198 @@
/*
* 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 "vpx_mem/vpx_mem.h"
#include "vpx_ports/mem.h"
#include "vp9/common/vp9_common.h"
#include "vp9/encoder/vp9_extend.h"
static void copy_and_extend_plane(const uint8_t *src, int src_pitch,
uint8_t *dst, int dst_pitch,
int w, int h,
int extend_top, int extend_left,
int extend_bottom, int extend_right) {
int i, linesize;
// copy the left and right most columns out
const uint8_t *src_ptr1 = src;
const uint8_t *src_ptr2 = src + w - 1;
uint8_t *dst_ptr1 = dst - extend_left;
uint8_t *dst_ptr2 = dst + w;
for (i = 0; i < h; i++) {
memset(dst_ptr1, src_ptr1[0], extend_left);
memcpy(dst_ptr1 + extend_left, src_ptr1, w);
memset(dst_ptr2, src_ptr2[0], extend_right);
src_ptr1 += src_pitch;
src_ptr2 += src_pitch;
dst_ptr1 += dst_pitch;
dst_ptr2 += dst_pitch;
}
// Now copy the top and bottom lines into each line of the respective
// borders
src_ptr1 = dst - extend_left;
src_ptr2 = dst + dst_pitch * (h - 1) - extend_left;
dst_ptr1 = dst + dst_pitch * (-extend_top) - extend_left;
dst_ptr2 = dst + dst_pitch * (h) - extend_left;
linesize = extend_left + extend_right + w;
for (i = 0; i < extend_top; i++) {
memcpy(dst_ptr1, src_ptr1, linesize);
dst_ptr1 += dst_pitch;
}
for (i = 0; i < extend_bottom; i++) {
memcpy(dst_ptr2, src_ptr2, linesize);
dst_ptr2 += dst_pitch;
}
}
#if CONFIG_VP9_HIGHBITDEPTH
static void highbd_copy_and_extend_plane(const uint8_t *src8, int src_pitch,
uint8_t *dst8, int dst_pitch,
int w, int h,
int extend_top, int extend_left,
int extend_bottom, int extend_right) {
int i, linesize;
uint16_t *src = CONVERT_TO_SHORTPTR(src8);
uint16_t *dst = CONVERT_TO_SHORTPTR(dst8);
// copy the left and right most columns out
const uint16_t *src_ptr1 = src;
const uint16_t *src_ptr2 = src + w - 1;
uint16_t *dst_ptr1 = dst - extend_left;
uint16_t *dst_ptr2 = dst + w;
for (i = 0; i < h; i++) {
vpx_memset16(dst_ptr1, src_ptr1[0], extend_left);
memcpy(dst_ptr1 + extend_left, src_ptr1, w * sizeof(uint16_t));
vpx_memset16(dst_ptr2, src_ptr2[0], extend_right);
src_ptr1 += src_pitch;
src_ptr2 += src_pitch;
dst_ptr1 += dst_pitch;
dst_ptr2 += dst_pitch;
}
// Now copy the top and bottom lines into each line of the respective
// borders
src_ptr1 = dst - extend_left;
src_ptr2 = dst + dst_pitch * (h - 1) - extend_left;
dst_ptr1 = dst + dst_pitch * (-extend_top) - extend_left;
dst_ptr2 = dst + dst_pitch * (h) - extend_left;
linesize = extend_left + extend_right + w;
for (i = 0; i < extend_top; i++) {
memcpy(dst_ptr1, src_ptr1, linesize * sizeof(uint16_t));
dst_ptr1 += dst_pitch;
}
for (i = 0; i < extend_bottom; i++) {
memcpy(dst_ptr2, src_ptr2, linesize * sizeof(uint16_t));
dst_ptr2 += dst_pitch;
}
}
#endif // CONFIG_VP9_HIGHBITDEPTH
void vp9_copy_and_extend_frame(const YV12_BUFFER_CONFIG *src,
YV12_BUFFER_CONFIG *dst) {
// Extend src frame in buffer
// Altref filtering assumes 16 pixel extension
const int et_y = 16;
const int el_y = 16;
// Motion estimation may use src block variance with the block size up
// to 64x64, so the right and bottom need to be extended to 64 multiple
// or up to 16, whichever is greater.
const int er_y = MAX(src->y_width + 16, ALIGN_POWER_OF_TWO(src->y_width, 6))
- src->y_crop_width;
const int eb_y = MAX(src->y_height + 16, ALIGN_POWER_OF_TWO(src->y_height, 6))
- src->y_crop_height;
const int uv_width_subsampling = (src->uv_width != src->y_width);
const int uv_height_subsampling = (src->uv_height != src->y_height);
const int et_uv = et_y >> uv_height_subsampling;
const int el_uv = el_y >> uv_width_subsampling;
const int eb_uv = eb_y >> uv_height_subsampling;
const int er_uv = er_y >> uv_width_subsampling;
#if CONFIG_VP9_HIGHBITDEPTH
if (src->flags & YV12_FLAG_HIGHBITDEPTH) {
highbd_copy_and_extend_plane(src->y_buffer, src->y_stride,
dst->y_buffer, dst->y_stride,
src->y_crop_width, src->y_crop_height,
et_y, el_y, eb_y, er_y);
highbd_copy_and_extend_plane(src->u_buffer, src->uv_stride,
dst->u_buffer, dst->uv_stride,
src->uv_crop_width, src->uv_crop_height,
et_uv, el_uv, eb_uv, er_uv);
highbd_copy_and_extend_plane(src->v_buffer, src->uv_stride,
dst->v_buffer, dst->uv_stride,
src->uv_crop_width, src->uv_crop_height,
et_uv, el_uv, eb_uv, er_uv);
return;
}
#endif // CONFIG_VP9_HIGHBITDEPTH
copy_and_extend_plane(src->y_buffer, src->y_stride,
dst->y_buffer, dst->y_stride,
src->y_crop_width, src->y_crop_height,
et_y, el_y, eb_y, er_y);
copy_and_extend_plane(src->u_buffer, src->uv_stride,
dst->u_buffer, dst->uv_stride,
src->uv_crop_width, src->uv_crop_height,
et_uv, el_uv, eb_uv, er_uv);
copy_and_extend_plane(src->v_buffer, src->uv_stride,
dst->v_buffer, dst->uv_stride,
src->uv_crop_width, src->uv_crop_height,
et_uv, el_uv, eb_uv, er_uv);
}
void vp9_copy_and_extend_frame_with_rect(const YV12_BUFFER_CONFIG *src,
YV12_BUFFER_CONFIG *dst,
int srcy, int srcx,
int srch, int srcw) {
// If the side is not touching the bounder then don't extend.
const int et_y = srcy ? 0 : dst->border;
const int el_y = srcx ? 0 : dst->border;
const int eb_y = srcy + srch != src->y_height ? 0 :
dst->border + dst->y_height - src->y_height;
const int er_y = srcx + srcw != src->y_width ? 0 :
dst->border + dst->y_width - src->y_width;
const int src_y_offset = srcy * src->y_stride + srcx;
const int dst_y_offset = srcy * dst->y_stride + srcx;
const int et_uv = ROUND_POWER_OF_TWO(et_y, 1);
const int el_uv = ROUND_POWER_OF_TWO(el_y, 1);
const int eb_uv = ROUND_POWER_OF_TWO(eb_y, 1);
const int er_uv = ROUND_POWER_OF_TWO(er_y, 1);
const int src_uv_offset = ((srcy * src->uv_stride) >> 1) + (srcx >> 1);
const int dst_uv_offset = ((srcy * dst->uv_stride) >> 1) + (srcx >> 1);
const int srch_uv = ROUND_POWER_OF_TWO(srch, 1);
const int srcw_uv = ROUND_POWER_OF_TWO(srcw, 1);
copy_and_extend_plane(src->y_buffer + src_y_offset, src->y_stride,
dst->y_buffer + dst_y_offset, dst->y_stride,
srcw, srch,
et_y, el_y, eb_y, er_y);
copy_and_extend_plane(src->u_buffer + src_uv_offset, src->uv_stride,
dst->u_buffer + dst_uv_offset, dst->uv_stride,
srcw_uv, srch_uv,
et_uv, el_uv, eb_uv, er_uv);
copy_and_extend_plane(src->v_buffer + src_uv_offset, src->uv_stride,
dst->v_buffer + dst_uv_offset, dst->uv_stride,
srcw_uv, srch_uv,
et_uv, el_uv, eb_uv, er_uv);
}

View file

@ -0,0 +1,33 @@
/*
* 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.
*/
#ifndef VP9_ENCODER_VP9_EXTEND_H_
#define VP9_ENCODER_VP9_EXTEND_H_
#include "vpx_scale/yv12config.h"
#include "vpx/vpx_integer.h"
#ifdef __cplusplus
extern "C" {
#endif
void vp9_copy_and_extend_frame(const YV12_BUFFER_CONFIG *src,
YV12_BUFFER_CONFIG *dst);
void vp9_copy_and_extend_frame_with_rect(const YV12_BUFFER_CONFIG *src,
YV12_BUFFER_CONFIG *dst,
int srcy, int srcx,
int srch, int srcw);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // VP9_ENCODER_VP9_EXTEND_H_

View file

@ -0,0 +1,465 @@
/*
* 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.
*
* This code was originally written by: Nathan E. Egge, at the Daala
* project.
*/
#include <math.h>
#include <string.h>
#include "./vpx_config.h"
#include "./vp9_rtcd.h"
#include "vp9/encoder/vp9_ssim.h"
/* TODO(jbb): High bit depth version of this code needed */
typedef struct fs_level fs_level;
typedef struct fs_ctx fs_ctx;
#define SSIM_C1 (255 * 255 * 0.01 * 0.01)
#define SSIM_C2 (255 * 255 * 0.03 * 0.03)
#define FS_MINI(_a, _b) ((_a) < (_b) ? (_a) : (_b))
#define FS_MAXI(_a, _b) ((_a) > (_b) ? (_a) : (_b))
struct fs_level {
uint16_t *im1;
uint16_t *im2;
double *ssim;
int w;
int h;
};
struct fs_ctx {
fs_level *level;
int nlevels;
unsigned *col_buf;
};
static void fs_ctx_init(fs_ctx *_ctx, int _w, int _h, int _nlevels) {
unsigned char *data;
size_t data_size;
int lw;
int lh;
int l;
lw = (_w + 1) >> 1;
lh = (_h + 1) >> 1;
data_size = _nlevels * sizeof(fs_level)
+ 2 * (lw + 8) * 8 * sizeof(*_ctx->col_buf);
for (l = 0; l < _nlevels; l++) {
size_t im_size;
size_t level_size;
im_size = lw * (size_t) lh;
level_size = 2 * im_size * sizeof(*_ctx->level[l].im1);
level_size += sizeof(*_ctx->level[l].ssim) - 1;
level_size /= sizeof(*_ctx->level[l].ssim);
level_size += im_size;
level_size *= sizeof(*_ctx->level[l].ssim);
data_size += level_size;
lw = (lw + 1) >> 1;
lh = (lh + 1) >> 1;
}
data = (unsigned char *) malloc(data_size);
_ctx->level = (fs_level *) data;
_ctx->nlevels = _nlevels;
data += _nlevels * sizeof(*_ctx->level);
lw = (_w + 1) >> 1;
lh = (_h + 1) >> 1;
for (l = 0; l < _nlevels; l++) {
size_t im_size;
size_t level_size;
_ctx->level[l].w = lw;
_ctx->level[l].h = lh;
im_size = lw * (size_t) lh;
level_size = 2 * im_size * sizeof(*_ctx->level[l].im1);
level_size += sizeof(*_ctx->level[l].ssim) - 1;
level_size /= sizeof(*_ctx->level[l].ssim);
level_size *= sizeof(*_ctx->level[l].ssim);
_ctx->level[l].im1 = (uint16_t *) data;
_ctx->level[l].im2 = _ctx->level[l].im1 + im_size;
data += level_size;
_ctx->level[l].ssim = (double *) data;
data += im_size * sizeof(*_ctx->level[l].ssim);
lw = (lw + 1) >> 1;
lh = (lh + 1) >> 1;
}
_ctx->col_buf = (unsigned *) data;
}
static void fs_ctx_clear(fs_ctx *_ctx) {
free(_ctx->level);
}
static void fs_downsample_level(fs_ctx *_ctx, int _l) {
const uint16_t *src1;
const uint16_t *src2;
uint16_t *dst1;
uint16_t *dst2;
int w2;
int h2;
int w;
int h;
int i;
int j;
w = _ctx->level[_l].w;
h = _ctx->level[_l].h;
dst1 = _ctx->level[_l].im1;
dst2 = _ctx->level[_l].im2;
w2 = _ctx->level[_l - 1].w;
h2 = _ctx->level[_l - 1].h;
src1 = _ctx->level[_l - 1].im1;
src2 = _ctx->level[_l - 1].im2;
for (j = 0; j < h; j++) {
int j0offs;
int j1offs;
j0offs = 2 * j * w2;
j1offs = FS_MINI(2 * j + 1, h2) * w2;
for (i = 0; i < w; i++) {
int i0;
int i1;
i0 = 2 * i;
i1 = FS_MINI(i0 + 1, w2);
dst1[j * w + i] = src1[j0offs + i0] + src1[j0offs + i1]
+ src1[j1offs + i0] + src1[j1offs + i1];
dst2[j * w + i] = src2[j0offs + i0] + src2[j0offs + i1]
+ src2[j1offs + i0] + src2[j1offs + i1];
}
}
}
static void fs_downsample_level0(fs_ctx *_ctx, const unsigned char *_src1,
int _s1ystride, const unsigned char *_src2,
int _s2ystride, int _w, int _h) {
uint16_t *dst1;
uint16_t *dst2;
int w;
int h;
int i;
int j;
w = _ctx->level[0].w;
h = _ctx->level[0].h;
dst1 = _ctx->level[0].im1;
dst2 = _ctx->level[0].im2;
for (j = 0; j < h; j++) {
int j0;
int j1;
j0 = 2 * j;
j1 = FS_MINI(j0 + 1, _h);
for (i = 0; i < w; i++) {
int i0;
int i1;
i0 = 2 * i;
i1 = FS_MINI(i0 + 1, _w);
dst1[j * w + i] = _src1[j0 * _s1ystride + i0]
+ _src1[j0 * _s1ystride + i1] + _src1[j1 * _s1ystride + i0]
+ _src1[j1 * _s1ystride + i1];
dst2[j * w + i] = _src2[j0 * _s2ystride + i0]
+ _src2[j0 * _s2ystride + i1] + _src2[j1 * _s2ystride + i0]
+ _src2[j1 * _s2ystride + i1];
}
}
}
static void fs_apply_luminance(fs_ctx *_ctx, int _l) {
unsigned *col_sums_x;
unsigned *col_sums_y;
uint16_t *im1;
uint16_t *im2;
double *ssim;
double c1;
int w;
int h;
int j0offs;
int j1offs;
int i;
int j;
w = _ctx->level[_l].w;
h = _ctx->level[_l].h;
col_sums_x = _ctx->col_buf;
col_sums_y = col_sums_x + w;
im1 = _ctx->level[_l].im1;
im2 = _ctx->level[_l].im2;
for (i = 0; i < w; i++)
col_sums_x[i] = 5 * im1[i];
for (i = 0; i < w; i++)
col_sums_y[i] = 5 * im2[i];
for (j = 1; j < 4; j++) {
j1offs = FS_MINI(j, h - 1) * w;
for (i = 0; i < w; i++)
col_sums_x[i] += im1[j1offs + i];
for (i = 0; i < w; i++)
col_sums_y[i] += im2[j1offs + i];
}
ssim = _ctx->level[_l].ssim;
c1 = (double) (SSIM_C1 * 4096 * (1 << 4 * _l));
for (j = 0; j < h; j++) {
unsigned mux;
unsigned muy;
int i0;
int i1;
mux = 5 * col_sums_x[0];
muy = 5 * col_sums_y[0];
for (i = 1; i < 4; i++) {
i1 = FS_MINI(i, w - 1);
mux += col_sums_x[i1];
muy += col_sums_y[i1];
}
for (i = 0; i < w; i++) {
ssim[j * w + i] *= (2 * mux * (double) muy + c1)
/ (mux * (double) mux + muy * (double) muy + c1);
if (i + 1 < w) {
i0 = FS_MAXI(0, i - 4);
i1 = FS_MINI(i + 4, w - 1);
mux += col_sums_x[i1] - col_sums_x[i0];
muy += col_sums_x[i1] - col_sums_x[i0];
}
}
if (j + 1 < h) {
j0offs = FS_MAXI(0, j - 4) * w;
for (i = 0; i < w; i++)
col_sums_x[i] -= im1[j0offs + i];
for (i = 0; i < w; i++)
col_sums_y[i] -= im2[j0offs + i];
j1offs = FS_MINI(j + 4, h - 1) * w;
for (i = 0; i < w; i++)
col_sums_x[i] += im1[j1offs + i];
for (i = 0; i < w; i++)
col_sums_y[i] += im2[j1offs + i];
}
}
}
#define FS_COL_SET(_col, _joffs, _ioffs) \
do { \
unsigned gx; \
unsigned gy; \
gx = gx_buf[((j + (_joffs)) & 7) * stride + i + (_ioffs)]; \
gy = gy_buf[((j + (_joffs)) & 7) * stride + i + (_ioffs)]; \
col_sums_gx2[(_col)] = gx * (double)gx; \
col_sums_gy2[(_col)] = gy * (double)gy; \
col_sums_gxgy[(_col)] = gx * (double)gy; \
} \
while (0)
#define FS_COL_ADD(_col, _joffs, _ioffs) \
do { \
unsigned gx; \
unsigned gy; \
gx = gx_buf[((j + (_joffs)) & 7) * stride + i + (_ioffs)]; \
gy = gy_buf[((j + (_joffs)) & 7) * stride + i + (_ioffs)]; \
col_sums_gx2[(_col)] += gx * (double)gx; \
col_sums_gy2[(_col)] += gy * (double)gy; \
col_sums_gxgy[(_col)] += gx * (double)gy; \
} \
while (0)
#define FS_COL_SUB(_col, _joffs, _ioffs) \
do { \
unsigned gx; \
unsigned gy; \
gx = gx_buf[((j + (_joffs)) & 7) * stride + i + (_ioffs)]; \
gy = gy_buf[((j + (_joffs)) & 7) * stride + i + (_ioffs)]; \
col_sums_gx2[(_col)] -= gx * (double)gx; \
col_sums_gy2[(_col)] -= gy * (double)gy; \
col_sums_gxgy[(_col)] -= gx * (double)gy; \
} \
while (0)
#define FS_COL_COPY(_col1, _col2) \
do { \
col_sums_gx2[(_col1)] = col_sums_gx2[(_col2)]; \
col_sums_gy2[(_col1)] = col_sums_gy2[(_col2)]; \
col_sums_gxgy[(_col1)] = col_sums_gxgy[(_col2)]; \
} \
while (0)
#define FS_COL_HALVE(_col1, _col2) \
do { \
col_sums_gx2[(_col1)] = col_sums_gx2[(_col2)] * 0.5; \
col_sums_gy2[(_col1)] = col_sums_gy2[(_col2)] * 0.5; \
col_sums_gxgy[(_col1)] = col_sums_gxgy[(_col2)] * 0.5; \
} \
while (0)
#define FS_COL_DOUBLE(_col1, _col2) \
do { \
col_sums_gx2[(_col1)] = col_sums_gx2[(_col2)] * 2; \
col_sums_gy2[(_col1)] = col_sums_gy2[(_col2)] * 2; \
col_sums_gxgy[(_col1)] = col_sums_gxgy[(_col2)] * 2; \
} \
while (0)
static void fs_calc_structure(fs_ctx *_ctx, int _l) {
uint16_t *im1;
uint16_t *im2;
unsigned *gx_buf;
unsigned *gy_buf;
double *ssim;
double col_sums_gx2[8];
double col_sums_gy2[8];
double col_sums_gxgy[8];
double c2;
int stride;
int w;
int h;
int i;
int j;
w = _ctx->level[_l].w;
h = _ctx->level[_l].h;
im1 = _ctx->level[_l].im1;
im2 = _ctx->level[_l].im2;
ssim = _ctx->level[_l].ssim;
gx_buf = _ctx->col_buf;
stride = w + 8;
gy_buf = gx_buf + 8 * stride;
memset(gx_buf, 0, 2 * 8 * stride * sizeof(*gx_buf));
c2 = SSIM_C2 * (1 << 4 * _l) * 16 * 104;
for (j = 0; j < h + 4; j++) {
if (j < h - 1) {
for (i = 0; i < w - 1; i++) {
unsigned g1;
unsigned g2;
unsigned gx;
unsigned gy;
g1 = abs(im1[(j + 1) * w + i + 1] - im1[j * w + i]);
g2 = abs(im1[(j + 1) * w + i] - im1[j * w + i + 1]);
gx = 4 * FS_MAXI(g1, g2) + FS_MINI(g1, g2);
g1 = abs(im2[(j + 1) * w + i + 1] - im2[j * w + i]);
g2 = abs(im2[(j + 1) * w + i] - im2[j * w + i + 1]);
gy = 4 * FS_MAXI(g1, g2) + FS_MINI(g1, g2);
gx_buf[(j & 7) * stride + i + 4] = gx;
gy_buf[(j & 7) * stride + i + 4] = gy;
}
} else {
memset(gx_buf + (j & 7) * stride, 0, stride * sizeof(*gx_buf));
memset(gy_buf + (j & 7) * stride, 0, stride * sizeof(*gy_buf));
}
if (j >= 4) {
int k;
col_sums_gx2[3] = col_sums_gx2[2] = col_sums_gx2[1] = col_sums_gx2[0] = 0;
col_sums_gy2[3] = col_sums_gy2[2] = col_sums_gy2[1] = col_sums_gy2[0] = 0;
col_sums_gxgy[3] = col_sums_gxgy[2] = col_sums_gxgy[1] =
col_sums_gxgy[0] = 0;
for (i = 4; i < 8; i++) {
FS_COL_SET(i, -1, 0);
FS_COL_ADD(i, 0, 0);
for (k = 1; k < 8 - i; k++) {
FS_COL_DOUBLE(i, i);
FS_COL_ADD(i, -k - 1, 0);
FS_COL_ADD(i, k, 0);
}
}
for (i = 0; i < w; i++) {
double mugx2;
double mugy2;
double mugxgy;
mugx2 = col_sums_gx2[0];
for (k = 1; k < 8; k++)
mugx2 += col_sums_gx2[k];
mugy2 = col_sums_gy2[0];
for (k = 1; k < 8; k++)
mugy2 += col_sums_gy2[k];
mugxgy = col_sums_gxgy[0];
for (k = 1; k < 8; k++)
mugxgy += col_sums_gxgy[k];
ssim[(j - 4) * w + i] = (2 * mugxgy + c2) / (mugx2 + mugy2 + c2);
if (i + 1 < w) {
FS_COL_SET(0, -1, 1);
FS_COL_ADD(0, 0, 1);
FS_COL_SUB(2, -3, 2);
FS_COL_SUB(2, 2, 2);
FS_COL_HALVE(1, 2);
FS_COL_SUB(3, -4, 3);
FS_COL_SUB(3, 3, 3);
FS_COL_HALVE(2, 3);
FS_COL_COPY(3, 4);
FS_COL_DOUBLE(4, 5);
FS_COL_ADD(4, -4, 5);
FS_COL_ADD(4, 3, 5);
FS_COL_DOUBLE(5, 6);
FS_COL_ADD(5, -3, 6);
FS_COL_ADD(5, 2, 6);
FS_COL_DOUBLE(6, 7);
FS_COL_ADD(6, -2, 7);
FS_COL_ADD(6, 1, 7);
FS_COL_SET(7, -1, 8);
FS_COL_ADD(7, 0, 8);
}
}
}
}
}
#define FS_NLEVELS (4)
/*These weights were derived from the default weights found in Wang's original
Matlab implementation: {0.0448, 0.2856, 0.2363, 0.1333}.
We drop the finest scale and renormalize the rest to sum to 1.*/
static const double FS_WEIGHTS[FS_NLEVELS] = {0.2989654541015625,
0.3141326904296875, 0.2473602294921875, 0.1395416259765625};
static double fs_average(fs_ctx *_ctx, int _l) {
double *ssim;
double ret;
int w;
int h;
int i;
int j;
w = _ctx->level[_l].w;
h = _ctx->level[_l].h;
ssim = _ctx->level[_l].ssim;
ret = 0;
for (j = 0; j < h; j++)
for (i = 0; i < w; i++)
ret += ssim[j * w + i];
return pow(ret / (w * h), FS_WEIGHTS[_l]);
}
static double calc_ssim(const unsigned char *_src, int _systride,
const unsigned char *_dst, int _dystride, int _w, int _h) {
fs_ctx ctx;
double ret;
int l;
ret = 1;
fs_ctx_init(&ctx, _w, _h, FS_NLEVELS);
fs_downsample_level0(&ctx, _src, _systride, _dst, _dystride, _w, _h);
for (l = 0; l < FS_NLEVELS - 1; l++) {
fs_calc_structure(&ctx, l);
ret *= fs_average(&ctx, l);
fs_downsample_level(&ctx, l + 1);
}
fs_calc_structure(&ctx, l);
fs_apply_luminance(&ctx, l);
ret *= fs_average(&ctx, l);
fs_ctx_clear(&ctx);
return ret;
}
static double convert_ssim_db(double _ssim, double _weight) {
return 10 * (log10(_weight) - log10(_weight - _ssim));
}
double vp9_calc_fastssim(YV12_BUFFER_CONFIG *source, YV12_BUFFER_CONFIG *dest,
double *ssim_y, double *ssim_u, double *ssim_v) {
double ssimv;
vp9_clear_system_state();
*ssim_y = calc_ssim(source->y_buffer, source->y_stride, dest->y_buffer,
dest->y_stride, source->y_crop_width,
source->y_crop_height);
*ssim_u = calc_ssim(source->u_buffer, source->uv_stride, dest->u_buffer,
dest->uv_stride, source->uv_crop_width,
source->uv_crop_height);
*ssim_v = calc_ssim(source->v_buffer, source->uv_stride, dest->v_buffer,
dest->uv_stride, source->uv_crop_width,
source->uv_crop_height);
ssimv = (*ssim_y) * .8 + .1 * ((*ssim_u) + (*ssim_v));
return convert_ssim_db(ssimv, 1.0);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,154 @@
/*
* 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.
*/
#ifndef VP9_ENCODER_VP9_FIRSTPASS_H_
#define VP9_ENCODER_VP9_FIRSTPASS_H_
#include "vp9/encoder/vp9_lookahead.h"
#include "vp9/encoder/vp9_ratectrl.h"
#ifdef __cplusplus
extern "C" {
#endif
#if CONFIG_FP_MB_STATS
#define FPMB_DCINTRA_MASK 0x01
#define FPMB_MOTION_ZERO_MASK 0x02
#define FPMB_MOTION_LEFT_MASK 0x04
#define FPMB_MOTION_RIGHT_MASK 0x08
#define FPMB_MOTION_UP_MASK 0x10
#define FPMB_MOTION_DOWN_MASK 0x20
#define FPMB_ERROR_SMALL_MASK 0x40
#define FPMB_ERROR_LARGE_MASK 0x80
#define FPMB_ERROR_SMALL_TH 2000
#define FPMB_ERROR_LARGE_TH 48000
typedef struct {
uint8_t *mb_stats_start;
uint8_t *mb_stats_end;
} FIRSTPASS_MB_STATS;
#endif
#define VLOW_MOTION_THRESHOLD 950
typedef struct {
double frame;
double weight;
double intra_error;
double coded_error;
double sr_coded_error;
double pcnt_inter;
double pcnt_motion;
double pcnt_second_ref;
double pcnt_neutral;
double MVr;
double mvr_abs;
double MVc;
double mvc_abs;
double MVrv;
double MVcv;
double mv_in_out_count;
double new_mv_count;
double duration;
double count;
int64_t spatial_layer_id;
} FIRSTPASS_STATS;
typedef enum {
KF_UPDATE = 0,
LF_UPDATE = 1,
GF_UPDATE = 2,
ARF_UPDATE = 3,
OVERLAY_UPDATE = 4,
FRAME_UPDATE_TYPES = 5
} FRAME_UPDATE_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];
int bit_allocation[(MAX_LAG_BUFFERS * 2) + 1];
} GF_GROUP;
typedef struct {
unsigned int section_intra_rating;
FIRSTPASS_STATS total_stats;
FIRSTPASS_STATS this_frame_stats;
const FIRSTPASS_STATS *stats_in;
const FIRSTPASS_STATS *stats_in_start;
const FIRSTPASS_STATS *stats_in_end;
FIRSTPASS_STATS total_left_stats;
int first_pass_done;
int64_t bits_left;
double modified_error_min;
double modified_error_max;
double modified_error_left;
double mb_av_energy;
#if CONFIG_FP_MB_STATS
uint8_t *frame_mb_stats_buf;
uint8_t *this_frame_mb_stats;
FIRSTPASS_MB_STATS firstpass_mb_stats;
#endif
// Projected total bits available for a key frame group of frames
int64_t kf_group_bits;
// Error score of frames still to be coded in kf group
int64_t kf_group_error_left;
// The fraction for a kf groups total bits allocated to the inter frames
double kfgroup_inter_fraction;
int sr_update_lag;
int kf_zeromotion_pct;
int last_kfgroup_zeromotion_pct;
int gf_zeromotion_pct;
int active_worst_quality;
int baseline_active_worst_quality;
int extend_minq;
int extend_maxq;
int extend_minq_fast;
GF_GROUP gf_group;
} TWO_PASS;
struct VP9_COMP;
void vp9_init_first_pass(struct VP9_COMP *cpi);
void vp9_rc_get_first_pass_params(struct VP9_COMP *cpi);
void vp9_first_pass(struct VP9_COMP *cpi, const struct lookahead_entry *source);
void vp9_end_first_pass(struct VP9_COMP *cpi);
void vp9_init_second_pass(struct VP9_COMP *cpi);
void vp9_rc_get_second_pass_params(struct VP9_COMP *cpi);
void vp9_twopass_postencode_update(struct VP9_COMP *cpi);
// Post encode update of the rate control parameters for 2-pass
void vp9_twopass_postencode_update(struct VP9_COMP *cpi);
void vp9_init_subsampling(struct VP9_COMP *cpi);
void calculate_coded_size(struct VP9_COMP *cpi,
int *scaled_frame_width,
int *scaled_frame_height);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // VP9_ENCODER_VP9_FIRSTPASS_H_

View file

@ -0,0 +1,245 @@
/*
* Copyright (c) 2011 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 <assert.h>
#include <stdlib.h>
#include "./vpx_config.h"
#include "vp9/common/vp9_common.h"
#include "vp9/encoder/vp9_encoder.h"
#include "vp9/encoder/vp9_extend.h"
#include "vp9/encoder/vp9_lookahead.h"
/* Return the buffer at the given absolute index and increment the index */
static struct lookahead_entry *pop(struct lookahead_ctx *ctx,
unsigned int *idx) {
unsigned int index = *idx;
struct lookahead_entry *buf = ctx->buf + index;
assert(index < ctx->max_sz);
if (++index >= ctx->max_sz)
index -= ctx->max_sz;
*idx = index;
return buf;
}
void vp9_lookahead_destroy(struct lookahead_ctx *ctx) {
if (ctx) {
if (ctx->buf) {
unsigned int i;
for (i = 0; i < ctx->max_sz; i++)
vp9_free_frame_buffer(&ctx->buf[i].img);
free(ctx->buf);
}
free(ctx);
}
}
struct lookahead_ctx *vp9_lookahead_init(unsigned int width,
unsigned int height,
unsigned int subsampling_x,
unsigned int subsampling_y,
#if CONFIG_VP9_HIGHBITDEPTH
int use_highbitdepth,
#endif
unsigned int depth) {
struct lookahead_ctx *ctx = NULL;
// Clamp the lookahead queue depth
depth = clamp(depth, 1, MAX_LAG_BUFFERS);
// Allocate memory to keep previous source frames available.
depth += MAX_PRE_FRAMES;
// Allocate the lookahead structures
ctx = calloc(1, sizeof(*ctx));
if (ctx) {
const int legacy_byte_alignment = 0;
unsigned int i;
ctx->max_sz = depth;
ctx->buf = calloc(depth, sizeof(*ctx->buf));
if (!ctx->buf)
goto bail;
for (i = 0; i < depth; i++)
if (vp9_alloc_frame_buffer(&ctx->buf[i].img,
width, height, subsampling_x, subsampling_y,
#if CONFIG_VP9_HIGHBITDEPTH
use_highbitdepth,
#endif
VP9_ENC_BORDER_IN_PIXELS,
legacy_byte_alignment))
goto bail;
}
return ctx;
bail:
vp9_lookahead_destroy(ctx);
return NULL;
}
#define USE_PARTIAL_COPY 0
int vp9_lookahead_push(struct lookahead_ctx *ctx, YV12_BUFFER_CONFIG *src,
int64_t ts_start, int64_t ts_end,
#if CONFIG_VP9_HIGHBITDEPTH
int use_highbitdepth,
#endif
unsigned int flags) {
struct lookahead_entry *buf;
#if USE_PARTIAL_COPY
int row, col, active_end;
int mb_rows = (src->y_height + 15) >> 4;
int mb_cols = (src->y_width + 15) >> 4;
#endif
int width = src->y_crop_width;
int height = src->y_crop_height;
int uv_width = src->uv_crop_width;
int uv_height = src->uv_crop_height;
int subsampling_x = src->subsampling_x;
int subsampling_y = src->subsampling_y;
int larger_dimensions, new_dimensions;
if (ctx->sz + 1 + MAX_PRE_FRAMES > ctx->max_sz)
return 1;
ctx->sz++;
buf = pop(ctx, &ctx->write_idx);
new_dimensions = width != buf->img.y_crop_width ||
height != buf->img.y_crop_height ||
uv_width != buf->img.uv_crop_width ||
uv_height != buf->img.uv_crop_height;
larger_dimensions = width > buf->img.y_width ||
height > buf->img.y_height ||
uv_width > buf->img.uv_width ||
uv_height > buf->img.uv_height;
assert(!larger_dimensions || new_dimensions);
#if USE_PARTIAL_COPY
// TODO(jkoleszar): This is disabled for now, as
// vp9_copy_and_extend_frame_with_rect is not subsampling/alpha aware.
// Only do this partial copy if the following conditions are all met:
// 1. Lookahead queue has has size of 1.
// 2. Active map is provided.
// 3. This is not a key frame, golden nor altref frame.
if (!new_dimensions && ctx->max_sz == 1 && active_map && !flags) {
for (row = 0; row < mb_rows; ++row) {
col = 0;
while (1) {
// Find the first active macroblock in this row.
for (; col < mb_cols; ++col) {
if (active_map[col])
break;
}
// No more active macroblock in this row.
if (col == mb_cols)
break;
// Find the end of active region in this row.
active_end = col;
for (; active_end < mb_cols; ++active_end) {
if (!active_map[active_end])
break;
}
// Only copy this active region.
vp9_copy_and_extend_frame_with_rect(src, &buf->img,
row << 4,
col << 4, 16,
(active_end - col) << 4);
// Start again from the end of this active region.
col = active_end;
}
active_map += mb_cols;
}
} else {
#endif
if (larger_dimensions) {
YV12_BUFFER_CONFIG new_img;
memset(&new_img, 0, sizeof(new_img));
if (vp9_alloc_frame_buffer(&new_img,
width, height, subsampling_x, subsampling_y,
#if CONFIG_VP9_HIGHBITDEPTH
use_highbitdepth,
#endif
VP9_ENC_BORDER_IN_PIXELS,
0))
return 1;
vp9_free_frame_buffer(&buf->img);
buf->img = new_img;
} else if (new_dimensions) {
buf->img.y_crop_width = src->y_crop_width;
buf->img.y_crop_height = src->y_crop_height;
buf->img.uv_crop_width = src->uv_crop_width;
buf->img.uv_crop_height = src->uv_crop_height;
buf->img.subsampling_x = src->subsampling_x;
buf->img.subsampling_y = src->subsampling_y;
}
// Partial copy not implemented yet
vp9_copy_and_extend_frame(src, &buf->img);
#if USE_PARTIAL_COPY
}
#endif
buf->ts_start = ts_start;
buf->ts_end = ts_end;
buf->flags = flags;
return 0;
}
struct lookahead_entry *vp9_lookahead_pop(struct lookahead_ctx *ctx,
int drain) {
struct lookahead_entry *buf = NULL;
if (ctx && ctx->sz && (drain || ctx->sz == ctx->max_sz - MAX_PRE_FRAMES)) {
buf = pop(ctx, &ctx->read_idx);
ctx->sz--;
}
return buf;
}
struct lookahead_entry *vp9_lookahead_peek(struct lookahead_ctx *ctx,
int index) {
struct lookahead_entry *buf = NULL;
if (index >= 0) {
// Forward peek
if (index < (int)ctx->sz) {
index += ctx->read_idx;
if (index >= (int)ctx->max_sz)
index -= ctx->max_sz;
buf = ctx->buf + index;
}
} else if (index < 0) {
// Backward peek
if (-index <= MAX_PRE_FRAMES) {
index += ctx->read_idx;
if (index < 0)
index += ctx->max_sz;
buf = ctx->buf + index;
}
}
return buf;
}
unsigned int vp9_lookahead_depth(struct lookahead_ctx *ctx) {
return ctx->sz;
}

View file

@ -0,0 +1,124 @@
/*
* Copyright (c) 2011 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.
*/
#ifndef VP9_ENCODER_VP9_LOOKAHEAD_H_
#define VP9_ENCODER_VP9_LOOKAHEAD_H_
#include "vpx_scale/yv12config.h"
#include "vpx/vpx_integer.h"
#if CONFIG_SPATIAL_SVC
#include "vpx/vp8cx.h"
#include "vpx/vpx_encoder.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
#define MAX_LAG_BUFFERS 25
struct lookahead_entry {
YV12_BUFFER_CONFIG img;
int64_t ts_start;
int64_t ts_end;
unsigned int flags;
};
// The max of past frames we want to keep in the queue.
#define MAX_PRE_FRAMES 1
struct lookahead_ctx {
unsigned int max_sz; /* Absolute size of the queue */
unsigned int sz; /* Number of buffers currently in the queue */
unsigned int read_idx; /* Read index */
unsigned int write_idx; /* Write index */
struct lookahead_entry *buf; /* Buffer list */
};
/**\brief Initializes the lookahead stage
*
* The lookahead stage is a queue of frame buffers on which some analysis
* may be done when buffers are enqueued.
*/
struct lookahead_ctx *vp9_lookahead_init(unsigned int width,
unsigned int height,
unsigned int subsampling_x,
unsigned int subsampling_y,
#if CONFIG_VP9_HIGHBITDEPTH
int use_highbitdepth,
#endif
unsigned int depth);
/**\brief Destroys the lookahead stage
*/
void vp9_lookahead_destroy(struct lookahead_ctx *ctx);
/**\brief Enqueue a source buffer
*
* This function will copy the source image into a new framebuffer with
* the expected stride/border.
*
* If active_map is non-NULL and there is only one frame in the queue, then copy
* only active macroblocks.
*
* \param[in] ctx Pointer to the lookahead context
* \param[in] src Pointer to the image to enqueue
* \param[in] ts_start Timestamp for the start of this frame
* \param[in] ts_end Timestamp for the end of this frame
* \param[in] flags Flags set on this frame
* \param[in] active_map Map that specifies which macroblock is active
*/
int vp9_lookahead_push(struct lookahead_ctx *ctx, YV12_BUFFER_CONFIG *src,
int64_t ts_start, int64_t ts_end,
#if CONFIG_VP9_HIGHBITDEPTH
int use_highbitdepth,
#endif
unsigned int flags);
/**\brief Get the next source buffer to encode
*
*
* \param[in] ctx Pointer to the lookahead context
* \param[in] drain Flag indicating the buffer should be drained
* (return a buffer regardless of the current queue depth)
*
* \retval NULL, if drain set and queue is empty
* \retval NULL, if drain not set and queue not of the configured depth
*/
struct lookahead_entry *vp9_lookahead_pop(struct lookahead_ctx *ctx,
int drain);
/**\brief Get a future source buffer to encode
*
* \param[in] ctx Pointer to the lookahead context
* \param[in] index Index of the frame to be returned, 0 == next frame
*
* \retval NULL, if no buffer exists at the specified index
*/
struct lookahead_entry *vp9_lookahead_peek(struct lookahead_ctx *ctx,
int index);
/**\brief Get the number of frames currently in the lookahead queue
*
* \param[in] ctx Pointer to the lookahead context
*/
unsigned int vp9_lookahead_depth(struct lookahead_ctx *ctx);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // VP9_ENCODER_VP9_LOOKAHEAD_H_

View file

@ -0,0 +1,416 @@
/*
* Copyright (c) 2010 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <limits.h>
#include "./vp9_rtcd.h"
#include "./vpx_dsp_rtcd.h"
#include "vpx_mem/vpx_mem.h"
#include "vp9/encoder/vp9_segmentation.h"
#include "vp9/encoder/vp9_mcomp.h"
#include "vp9/common/vp9_blockd.h"
#include "vp9/common/vp9_reconinter.h"
#include "vp9/common/vp9_reconintra.h"
#include "vp9/common/vp9_systemdependent.h"
static unsigned int do_16x16_motion_iteration(VP9_COMP *cpi,
const MV *ref_mv,
MV *dst_mv,
int mb_row,
int mb_col) {
MACROBLOCK *const x = &cpi->td.mb;
MACROBLOCKD *const xd = &x->e_mbd;
const MV_SPEED_FEATURES *const mv_sf = &cpi->sf.mv;
const vp9_variance_fn_ptr_t v_fn_ptr = cpi->fn_ptr[BLOCK_16X16];
const int tmp_col_min = x->mv_col_min;
const int tmp_col_max = x->mv_col_max;
const int tmp_row_min = x->mv_row_min;
const int tmp_row_max = x->mv_row_max;
MV ref_full;
int cost_list[5];
// Further step/diamond searches as necessary
int step_param = mv_sf->reduce_first_step_size;
step_param = MIN(step_param, MAX_MVSEARCH_STEPS - 2);
vp9_set_mv_search_range(x, ref_mv);
ref_full.col = ref_mv->col >> 3;
ref_full.row = ref_mv->row >> 3;
/*cpi->sf.search_method == HEX*/
vp9_hex_search(x, &ref_full, step_param, x->errorperbit, 0,
cond_cost_list(cpi, cost_list),
&v_fn_ptr, 0, ref_mv, dst_mv);
// Try sub-pixel MC
// if (bestsme > error_thresh && bestsme < INT_MAX)
{
int distortion;
unsigned int sse;
cpi->find_fractional_mv_step(
x, dst_mv, 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, 0, 0);
}
xd->mi[0]->mbmi.mode = NEWMV;
xd->mi[0]->mbmi.mv[0].as_mv = *dst_mv;
vp9_build_inter_predictors_sby(xd, mb_row, mb_col, BLOCK_16X16);
/* restore UMV window */
x->mv_col_min = tmp_col_min;
x->mv_col_max = tmp_col_max;
x->mv_row_min = tmp_row_min;
x->mv_row_max = tmp_row_max;
return vpx_sad16x16(x->plane[0].src.buf, x->plane[0].src.stride,
xd->plane[0].dst.buf, xd->plane[0].dst.stride);
}
static int do_16x16_motion_search(VP9_COMP *cpi, const MV *ref_mv,
int_mv *dst_mv, int mb_row, int mb_col) {
MACROBLOCK *const x = &cpi->td.mb;
MACROBLOCKD *const xd = &x->e_mbd;
unsigned int err, tmp_err;
MV tmp_mv;
// Try zero MV first
// FIXME should really use something like near/nearest MV and/or MV prediction
err = vpx_sad16x16(x->plane[0].src.buf, x->plane[0].src.stride,
xd->plane[0].pre[0].buf, xd->plane[0].pre[0].stride);
dst_mv->as_int = 0;
// Test last reference frame using the previous best mv as the
// starting point (best reference) for the search
tmp_err = do_16x16_motion_iteration(cpi, ref_mv, &tmp_mv, mb_row, mb_col);
if (tmp_err < err) {
err = tmp_err;
dst_mv->as_mv = tmp_mv;
}
// If the current best reference mv is not centered on 0,0 then do a 0,0
// based search as well.
if (ref_mv->row != 0 || ref_mv->col != 0) {
unsigned int tmp_err;
MV zero_ref_mv = {0, 0}, tmp_mv;
tmp_err = do_16x16_motion_iteration(cpi, &zero_ref_mv, &tmp_mv,
mb_row, mb_col);
if (tmp_err < err) {
dst_mv->as_mv = tmp_mv;
err = tmp_err;
}
}
return err;
}
static int do_16x16_zerozero_search(VP9_COMP *cpi, int_mv *dst_mv) {
MACROBLOCK *const x = &cpi->td.mb;
MACROBLOCKD *const xd = &x->e_mbd;
unsigned int err;
// Try zero MV first
// FIXME should really use something like near/nearest MV and/or MV prediction
err = vpx_sad16x16(x->plane[0].src.buf, x->plane[0].src.stride,
xd->plane[0].pre[0].buf, xd->plane[0].pre[0].stride);
dst_mv->as_int = 0;
return err;
}
static int find_best_16x16_intra(VP9_COMP *cpi, PREDICTION_MODE *pbest_mode) {
MACROBLOCK *const x = &cpi->td.mb;
MACROBLOCKD *const xd = &x->e_mbd;
PREDICTION_MODE best_mode = -1, mode;
unsigned int best_err = INT_MAX;
// calculate SATD for each intra prediction mode;
// we're intentionally not doing 4x4, we just want a rough estimate
for (mode = DC_PRED; mode <= TM_PRED; mode++) {
unsigned int err;
xd->mi[0]->mbmi.mode = mode;
vp9_predict_intra_block(xd, 0, 2, TX_16X16, mode,
x->plane[0].src.buf, x->plane[0].src.stride,
xd->plane[0].dst.buf, xd->plane[0].dst.stride,
0, 0, 0);
err = vpx_sad16x16(x->plane[0].src.buf, x->plane[0].src.stride,
xd->plane[0].dst.buf, xd->plane[0].dst.stride);
// find best
if (err < best_err) {
best_err = err;
best_mode = mode;
}
}
if (pbest_mode)
*pbest_mode = best_mode;
return best_err;
}
static void update_mbgraph_mb_stats
(
VP9_COMP *cpi,
MBGRAPH_MB_STATS *stats,
YV12_BUFFER_CONFIG *buf,
int mb_y_offset,
YV12_BUFFER_CONFIG *golden_ref,
const MV *prev_golden_ref_mv,
YV12_BUFFER_CONFIG *alt_ref,
int mb_row,
int mb_col
) {
MACROBLOCK *const x = &cpi->td.mb;
MACROBLOCKD *const xd = &x->e_mbd;
int intra_error;
VP9_COMMON *cm = &cpi->common;
// FIXME in practice we're completely ignoring chroma here
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;
// do intra 16x16 prediction
intra_error = find_best_16x16_intra(cpi,
&stats->ref[INTRA_FRAME].m.mode);
if (intra_error <= 0)
intra_error = 1;
stats->ref[INTRA_FRAME].err = intra_error;
// Golden frame MV search, if it exists and is different than last frame
if (golden_ref) {
int g_motion_error;
xd->plane[0].pre[0].buf = golden_ref->y_buffer + mb_y_offset;
xd->plane[0].pre[0].stride = golden_ref->y_stride;
g_motion_error = do_16x16_motion_search(cpi,
prev_golden_ref_mv,
&stats->ref[GOLDEN_FRAME].m.mv,
mb_row, mb_col);
stats->ref[GOLDEN_FRAME].err = g_motion_error;
} else {
stats->ref[GOLDEN_FRAME].err = INT_MAX;
stats->ref[GOLDEN_FRAME].m.mv.as_int = 0;
}
// Do an Alt-ref frame MV search, if it exists and is different than
// last/golden frame.
if (alt_ref) {
int a_motion_error;
xd->plane[0].pre[0].buf = alt_ref->y_buffer + mb_y_offset;
xd->plane[0].pre[0].stride = alt_ref->y_stride;
a_motion_error = do_16x16_zerozero_search(cpi,
&stats->ref[ALTREF_FRAME].m.mv);
stats->ref[ALTREF_FRAME].err = a_motion_error;
} else {
stats->ref[ALTREF_FRAME].err = INT_MAX;
stats->ref[ALTREF_FRAME].m.mv.as_int = 0;
}
}
static void update_mbgraph_frame_stats(VP9_COMP *cpi,
MBGRAPH_FRAME_STATS *stats,
YV12_BUFFER_CONFIG *buf,
YV12_BUFFER_CONFIG *golden_ref,
YV12_BUFFER_CONFIG *alt_ref) {
MACROBLOCK *const x = &cpi->td.mb;
MACROBLOCKD *const xd = &x->e_mbd;
VP9_COMMON *const cm = &cpi->common;
int mb_col, mb_row, offset = 0;
int mb_y_offset = 0, arf_y_offset = 0, gld_y_offset = 0;
MV gld_top_mv = {0, 0};
MODE_INFO mi_local;
vp9_zero(mi_local);
// Set up limit values for motion vectors to prevent them extending outside
// the UMV borders.
x->mv_row_min = -BORDER_MV_PIXELS_B16;
x->mv_row_max = (cm->mb_rows - 1) * 8 + BORDER_MV_PIXELS_B16;
xd->up_available = 0;
xd->plane[0].dst.stride = buf->y_stride;
xd->plane[0].pre[0].stride = buf->y_stride;
xd->plane[1].dst.stride = buf->uv_stride;
xd->mi[0] = &mi_local;
mi_local.mbmi.sb_type = BLOCK_16X16;
mi_local.mbmi.ref_frame[0] = LAST_FRAME;
mi_local.mbmi.ref_frame[1] = NONE;
for (mb_row = 0; mb_row < cm->mb_rows; mb_row++) {
MV gld_left_mv = gld_top_mv;
int mb_y_in_offset = mb_y_offset;
int arf_y_in_offset = arf_y_offset;
int gld_y_in_offset = gld_y_offset;
// Set up limit values for motion vectors to prevent them extending outside
// the UMV borders.
x->mv_col_min = -BORDER_MV_PIXELS_B16;
x->mv_col_max = (cm->mb_cols - 1) * 8 + BORDER_MV_PIXELS_B16;
xd->left_available = 0;
for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) {
MBGRAPH_MB_STATS *mb_stats = &stats->mb_stats[offset + mb_col];
update_mbgraph_mb_stats(cpi, mb_stats, buf, mb_y_in_offset,
golden_ref, &gld_left_mv, alt_ref,
mb_row, mb_col);
gld_left_mv = mb_stats->ref[GOLDEN_FRAME].m.mv.as_mv;
if (mb_col == 0) {
gld_top_mv = gld_left_mv;
}
xd->left_available = 1;
mb_y_in_offset += 16;
gld_y_in_offset += 16;
arf_y_in_offset += 16;
x->mv_col_min -= 16;
x->mv_col_max -= 16;
}
xd->up_available = 1;
mb_y_offset += buf->y_stride * 16;
gld_y_offset += golden_ref->y_stride * 16;
if (alt_ref)
arf_y_offset += alt_ref->y_stride * 16;
x->mv_row_min -= 16;
x->mv_row_max -= 16;
offset += cm->mb_cols;
}
}
// void separate_arf_mbs_byzz
static void separate_arf_mbs(VP9_COMP *cpi) {
VP9_COMMON *const cm = &cpi->common;
int mb_col, mb_row, offset, i;
int mi_row, mi_col;
int ncnt[4] = { 0 };
int n_frames = cpi->mbgraph_n_frames;
int *arf_not_zz;
CHECK_MEM_ERROR(cm, arf_not_zz,
vpx_calloc(cm->mb_rows * cm->mb_cols * sizeof(*arf_not_zz),
1));
// We are not interested in results beyond the alt ref itself.
if (n_frames > cpi->rc.frames_till_gf_update_due)
n_frames = cpi->rc.frames_till_gf_update_due;
// defer cost to reference frames
for (i = n_frames - 1; i >= 0; i--) {
MBGRAPH_FRAME_STATS *frame_stats = &cpi->mbgraph_stats[i];
for (offset = 0, mb_row = 0; mb_row < cm->mb_rows;
offset += cm->mb_cols, mb_row++) {
for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) {
MBGRAPH_MB_STATS *mb_stats = &frame_stats->mb_stats[offset + mb_col];
int altref_err = mb_stats->ref[ALTREF_FRAME].err;
int intra_err = mb_stats->ref[INTRA_FRAME ].err;
int golden_err = mb_stats->ref[GOLDEN_FRAME].err;
// Test for altref vs intra and gf and that its mv was 0,0.
if (altref_err > 1000 ||
altref_err > intra_err ||
altref_err > golden_err) {
arf_not_zz[offset + mb_col]++;
}
}
}
}
// arf_not_zz is indexed by MB, but this loop is indexed by MI to avoid out
// of bound access in segmentation_map
for (mi_row = 0; mi_row < cm->mi_rows; mi_row++) {
for (mi_col = 0; mi_col < cm->mi_cols; mi_col++) {
// If any of the blocks in the sequence failed then the MB
// goes in segment 0
if (arf_not_zz[mi_row / 2 * cm->mb_cols + mi_col / 2]) {
ncnt[0]++;
cpi->segmentation_map[mi_row * cm->mi_cols + mi_col] = 0;
} else {
cpi->segmentation_map[mi_row * cm->mi_cols + mi_col] = 1;
ncnt[1]++;
}
}
}
// Only bother with segmentation if over 10% of the MBs in static segment
// if ( ncnt[1] && (ncnt[0] / ncnt[1] < 10) )
if (1) {
// Note % of blocks that are marked as static
if (cm->MBs)
cpi->static_mb_pct = (ncnt[1] * 100) / (cm->mi_rows * cm->mi_cols);
// This error case should not be reachable as this function should
// never be called with the common data structure uninitialized.
else
cpi->static_mb_pct = 0;
vp9_enable_segmentation(&cm->seg);
} else {
cpi->static_mb_pct = 0;
vp9_disable_segmentation(&cm->seg);
}
// Free localy allocated storage
vpx_free(arf_not_zz);
}
void vp9_update_mbgraph_stats(VP9_COMP *cpi) {
VP9_COMMON *const cm = &cpi->common;
int i, n_frames = vp9_lookahead_depth(cpi->lookahead);
YV12_BUFFER_CONFIG *golden_ref = get_ref_frame_buffer(cpi, GOLDEN_FRAME);
assert(golden_ref != NULL);
// we need to look ahead beyond where the ARF transitions into
// being a GF - so exit if we don't look ahead beyond that
if (n_frames <= cpi->rc.frames_till_gf_update_due)
return;
if (n_frames > MAX_LAG_BUFFERS)
n_frames = MAX_LAG_BUFFERS;
cpi->mbgraph_n_frames = n_frames;
for (i = 0; i < n_frames; i++) {
MBGRAPH_FRAME_STATS *frame_stats = &cpi->mbgraph_stats[i];
memset(frame_stats->mb_stats, 0,
cm->mb_rows * cm->mb_cols * sizeof(*cpi->mbgraph_stats[i].mb_stats));
}
// do motion search to find contribution of each reference to data
// later on in this GF group
// FIXME really, the GF/last MC search should be done forward, and
// the ARF MC search backwards, to get optimal results for MV caching
for (i = 0; i < n_frames; i++) {
MBGRAPH_FRAME_STATS *frame_stats = &cpi->mbgraph_stats[i];
struct lookahead_entry *q_cur = vp9_lookahead_peek(cpi->lookahead, i);
assert(q_cur != NULL);
update_mbgraph_frame_stats(cpi, frame_stats, &q_cur->img,
golden_ref, cpi->Source);
}
vp9_clear_system_state();
separate_arf_mbs(cpi);
}

View file

@ -0,0 +1,40 @@
/*
* 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.
*/
#ifndef VP9_ENCODER_VP9_MBGRAPH_H_
#define VP9_ENCODER_VP9_MBGRAPH_H_
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
struct {
int err;
union {
int_mv mv;
PREDICTION_MODE mode;
} m;
} ref[MAX_REF_FRAMES];
} MBGRAPH_MB_STATS;
typedef struct {
MBGRAPH_MB_STATS *mb_stats;
} MBGRAPH_FRAME_STATS;
struct VP9_COMP;
void vp9_update_mbgraph_stats(struct VP9_COMP *cpi);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // VP9_ENCODER_VP9_MBGRAPH_H_

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,165 @@
/*
* 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.
*/
#ifndef VP9_ENCODER_VP9_MCOMP_H_
#define VP9_ENCODER_VP9_MCOMP_H_
#include "vp9/encoder/vp9_block.h"
#include "vp9/encoder/vp9_variance.h"
#ifdef __cplusplus
extern "C" {
#endif
// The maximum number of steps in a step search given the largest
// allowed initial step
#define MAX_MVSEARCH_STEPS 11
// Max full pel mv specified in the unit of full pixel
// Enable the use of motion vector in range [-1023, 1023].
#define MAX_FULL_PEL_VAL ((1 << (MAX_MVSEARCH_STEPS - 1)) - 1)
// Maximum size of the first step in full pel units
#define MAX_FIRST_STEP (1 << (MAX_MVSEARCH_STEPS-1))
// Allowed motion vector pixel distance outside image border
// for Block_16x16
#define BORDER_MV_PIXELS_B16 (16 + VP9_INTERP_EXTEND)
// motion search site
typedef struct search_site {
MV mv;
int offset;
} search_site;
typedef struct search_site_config {
search_site ss[8 * MAX_MVSEARCH_STEPS + 1];
int ss_count;
int searches_per_step;
} search_site_config;
void vp9_init_dsmotion_compensation(search_site_config *cfg, int stride);
void vp9_init3smotion_compensation(search_site_config *cfg, int stride);
void vp9_set_mv_search_range(MACROBLOCK *x, const MV *mv);
int vp9_mv_bit_cost(const MV *mv, const MV *ref,
const int *mvjcost, int *mvcost[2], int weight);
// Utility to compute variance + MV rate cost for a given MV
int vp9_get_mvpred_var(const MACROBLOCK *x,
const MV *best_mv, const MV *center_mv,
const vp9_variance_fn_ptr_t *vfp,
int use_mvcost);
int vp9_get_mvpred_av_var(const MACROBLOCK *x,
const MV *best_mv, const MV *center_mv,
const uint8_t *second_pred,
const vp9_variance_fn_ptr_t *vfp,
int use_mvcost);
struct VP9_COMP;
struct SPEED_FEATURES;
int vp9_init_search_range(int size);
int vp9_refining_search_sad(const struct macroblock *x,
struct mv *ref_mv,
int sad_per_bit, int distance,
const struct vp9_variance_vtable *fn_ptr,
const struct mv *center_mv);
// Runs sequence of diamond searches in smaller steps for RD.
int vp9_full_pixel_diamond(const struct VP9_COMP *cpi, MACROBLOCK *x,
MV *mvp_full, int step_param,
int sadpb, int further_steps, int do_refine,
int *cost_list,
const vp9_variance_fn_ptr_t *fn_ptr,
const MV *ref_mv, MV *dst_mv);
// Perform integral projection based motion estimation.
unsigned int vp9_int_pro_motion_estimation(const struct VP9_COMP *cpi,
MACROBLOCK *x,
BLOCK_SIZE bsize,
int mi_row, int mi_col);
typedef int (integer_mv_pattern_search_fn) (
const MACROBLOCK *x,
MV *ref_mv,
int search_param,
int error_per_bit,
int do_init_search,
int *cost_list,
const vp9_variance_fn_ptr_t *vf,
int use_mvcost,
const MV *center_mv,
MV *best_mv);
integer_mv_pattern_search_fn vp9_hex_search;
integer_mv_pattern_search_fn vp9_bigdia_search;
integer_mv_pattern_search_fn vp9_square_search;
integer_mv_pattern_search_fn vp9_fast_hex_search;
integer_mv_pattern_search_fn vp9_fast_dia_search;
typedef int (fractional_mv_step_fp) (
const MACROBLOCK *x,
MV *bestmv, const MV *ref_mv,
int allow_hp,
int error_per_bit,
const vp9_variance_fn_ptr_t *vfp,
int forced_stop, // 0 - full, 1 - qtr only, 2 - half only
int iters_per_step,
int *cost_list,
int *mvjcost, int *mvcost[2],
int *distortion, unsigned int *sse1,
const uint8_t *second_pred,
int w, int h);
extern fractional_mv_step_fp vp9_find_best_sub_pixel_tree;
extern fractional_mv_step_fp vp9_find_best_sub_pixel_tree_pruned;
extern fractional_mv_step_fp vp9_find_best_sub_pixel_tree_pruned_more;
extern fractional_mv_step_fp vp9_find_best_sub_pixel_tree_pruned_evenmore;
typedef int (*vp9_full_search_fn_t)(const MACROBLOCK *x,
const MV *ref_mv, int sad_per_bit,
int distance,
const vp9_variance_fn_ptr_t *fn_ptr,
const MV *center_mv, MV *best_mv);
typedef int (*vp9_refining_search_fn_t)(const MACROBLOCK *x,
MV *ref_mv, int sad_per_bit,
int distance,
const vp9_variance_fn_ptr_t *fn_ptr,
const MV *center_mv);
typedef int (*vp9_diamond_search_fn_t)(const MACROBLOCK *x,
const search_site_config *cfg,
MV *ref_mv, MV *best_mv,
int search_param, int sad_per_bit,
int *num00,
const vp9_variance_fn_ptr_t *fn_ptr,
const MV *center_mv);
int vp9_refining_search_8p_c(const MACROBLOCK *x,
MV *ref_mv, int error_per_bit,
int search_range,
const vp9_variance_fn_ptr_t *fn_ptr,
const MV *center_mv, const uint8_t *second_pred);
struct VP9_COMP;
int vp9_full_pixel_search(struct VP9_COMP *cpi, MACROBLOCK *x,
BLOCK_SIZE bsize, MV *mvp_full,
int step_param, int error_per_bit,
int *cost_list,
const MV *ref_mv, MV *tmp_mv,
int var_max, int rd);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // VP9_ENCODER_VP9_MCOMP_H_

View file

@ -0,0 +1,192 @@
/*
* 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 <assert.h>
#include <limits.h>
#include "./vpx_scale_rtcd.h"
#include "vpx_mem/vpx_mem.h"
#include "vpx_ports/mem.h"
#include "vp9/common/vp9_loopfilter.h"
#include "vp9/common/vp9_onyxc_int.h"
#include "vp9/common/vp9_quant_common.h"
#include "vp9/encoder/vp9_encoder.h"
#include "vp9/encoder/vp9_picklpf.h"
#include "vp9/encoder/vp9_quantize.h"
static int get_max_filter_level(const VP9_COMP *cpi) {
if (cpi->oxcf.pass == 2) {
return cpi->twopass.section_intra_rating > 8 ? MAX_LOOP_FILTER * 3 / 4
: MAX_LOOP_FILTER;
} else {
return MAX_LOOP_FILTER;
}
}
static int64_t try_filter_frame(const YV12_BUFFER_CONFIG *sd,
VP9_COMP *const cpi,
int filt_level, int partial_frame) {
VP9_COMMON *const cm = &cpi->common;
int64_t filt_err;
if (cpi->num_workers > 1)
vp9_loop_filter_frame_mt(cm->frame_to_show, cm, cpi->td.mb.e_mbd.plane,
filt_level, 1, partial_frame,
cpi->workers, cpi->num_workers, &cpi->lf_row_sync);
else
vp9_loop_filter_frame(cm->frame_to_show, cm, &cpi->td.mb.e_mbd, filt_level,
1, partial_frame);
#if CONFIG_VP9_HIGHBITDEPTH
if (cm->use_highbitdepth) {
filt_err = vp9_highbd_get_y_sse(sd, cm->frame_to_show);
} else {
filt_err = vp9_get_y_sse(sd, cm->frame_to_show);
}
#else
filt_err = vp9_get_y_sse(sd, cm->frame_to_show);
#endif // CONFIG_VP9_HIGHBITDEPTH
// Re-instate the unfiltered frame
vpx_yv12_copy_y(&cpi->last_frame_uf, cm->frame_to_show);
return filt_err;
}
static int search_filter_level(const YV12_BUFFER_CONFIG *sd, VP9_COMP *cpi,
int partial_frame) {
const VP9_COMMON *const cm = &cpi->common;
const struct loopfilter *const lf = &cm->lf;
const int min_filter_level = 0;
const int max_filter_level = get_max_filter_level(cpi);
int filt_direction = 0;
int64_t best_err;
int filt_best;
// Start the search at the previous frame filter level unless it is now out of
// range.
int filt_mid = clamp(lf->filter_level, min_filter_level, max_filter_level);
int filter_step = filt_mid < 16 ? 4 : filt_mid / 4;
// Sum squared error at each filter level
int64_t ss_err[MAX_LOOP_FILTER + 1];
// Set each entry to -1
memset(ss_err, 0xFF, sizeof(ss_err));
// Make a copy of the unfiltered / processed recon buffer
vpx_yv12_copy_y(cm->frame_to_show, &cpi->last_frame_uf);
best_err = try_filter_frame(sd, cpi, filt_mid, partial_frame);
filt_best = filt_mid;
ss_err[filt_mid] = best_err;
while (filter_step > 0) {
const int filt_high = MIN(filt_mid + filter_step, max_filter_level);
const int filt_low = MAX(filt_mid - filter_step, min_filter_level);
// Bias against raising loop filter in favor of lowering it.
int64_t bias = (best_err >> (15 - (filt_mid / 8))) * filter_step;
if ((cpi->oxcf.pass == 2) && (cpi->twopass.section_intra_rating < 20))
bias = (bias * cpi->twopass.section_intra_rating) / 20;
// yx, bias less for large block size
if (cm->tx_mode != ONLY_4X4)
bias >>= 1;
if (filt_direction <= 0 && filt_low != filt_mid) {
// Get Low filter error score
if (ss_err[filt_low] < 0) {
ss_err[filt_low] = try_filter_frame(sd, cpi, filt_low, partial_frame);
}
// If value is close to the best so far then bias towards a lower loop
// filter value.
if ((ss_err[filt_low] - bias) < best_err) {
// Was it actually better than the previous best?
if (ss_err[filt_low] < best_err)
best_err = ss_err[filt_low];
filt_best = filt_low;
}
}
// Now look at filt_high
if (filt_direction >= 0 && filt_high != filt_mid) {
if (ss_err[filt_high] < 0) {
ss_err[filt_high] = try_filter_frame(sd, cpi, filt_high, partial_frame);
}
// Was it better than the previous best?
if (ss_err[filt_high] < (best_err - bias)) {
best_err = ss_err[filt_high];
filt_best = filt_high;
}
}
// Half the step distance if the best filter value was the same as last time
if (filt_best == filt_mid) {
filter_step /= 2;
filt_direction = 0;
} else {
filt_direction = (filt_best < filt_mid) ? -1 : 1;
filt_mid = filt_best;
}
}
return filt_best;
}
void vp9_pick_filter_level(const YV12_BUFFER_CONFIG *sd, VP9_COMP *cpi,
LPF_PICK_METHOD method) {
VP9_COMMON *const cm = &cpi->common;
struct loopfilter *const lf = &cm->lf;
lf->sharpness_level = cm->frame_type == KEY_FRAME ? 0
: cpi->oxcf.sharpness;
if (method == LPF_PICK_MINIMAL_LPF && lf->filter_level) {
lf->filter_level = 0;
} else if (method >= LPF_PICK_FROM_Q) {
const int min_filter_level = 0;
const int max_filter_level = get_max_filter_level(cpi);
const int q = vp9_ac_quant(cm->base_qindex, 0, cm->bit_depth);
// These values were determined by linear fitting the result of the
// searched level, filt_guess = q * 0.316206 + 3.87252
#if CONFIG_VP9_HIGHBITDEPTH
int filt_guess;
switch (cm->bit_depth) {
case VPX_BITS_8:
filt_guess = ROUND_POWER_OF_TWO(q * 20723 + 1015158, 18);
break;
case VPX_BITS_10:
filt_guess = ROUND_POWER_OF_TWO(q * 20723 + 4060632, 20);
break;
case VPX_BITS_12:
filt_guess = ROUND_POWER_OF_TWO(q * 20723 + 16242526, 22);
break;
default:
assert(0 && "bit_depth should be VPX_BITS_8, VPX_BITS_10 "
"or VPX_BITS_12");
return;
}
#else
int filt_guess = ROUND_POWER_OF_TWO(q * 20723 + 1015158, 18);
#endif // CONFIG_VP9_HIGHBITDEPTH
if (cm->frame_type == KEY_FRAME)
filt_guess -= 4;
lf->filter_level = clamp(filt_guess, min_filter_level, max_filter_level);
} else {
lf->filter_level = search_filter_level(sd, cpi,
method == LPF_PICK_FROM_SUBIMAGE);
}
}

View file

@ -0,0 +1,30 @@
/*
* 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.
*/
#ifndef VP9_ENCODER_VP9_PICKLPF_H_
#define VP9_ENCODER_VP9_PICKLPF_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "vp9/encoder/vp9_encoder.h"
struct yv12_buffer_config;
struct VP9_COMP;
void vp9_pick_filter_level(const struct yv12_buffer_config *sd,
struct VP9_COMP *cpi, LPF_PICK_METHOD method);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // VP9_ENCODER_VP9_PICKLPF_H_

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,39 @@
/*
* Copyright (c) 2014 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.
*/
#ifndef VP9_ENCODER_VP9_PICKMODE_H_
#define VP9_ENCODER_VP9_PICKMODE_H_
#include "vp9/encoder/vp9_encoder.h"
#ifdef __cplusplus
extern "C" {
#endif
void vp9_pick_intra_mode(VP9_COMP *cpi, MACROBLOCK *x, RD_COST *rd_cost,
BLOCK_SIZE bsize, PICK_MODE_CONTEXT *ctx);
void vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x,
TileDataEnc *tile_data,
int mi_row, int mi_col, RD_COST *rd_cost,
BLOCK_SIZE bsize,
PICK_MODE_CONTEXT *ctx);
void vp9_pick_inter_mode_sub8x8(VP9_COMP *cpi, MACROBLOCK *x,
TileDataEnc *tile_data,
int mi_row, int mi_col, RD_COST *rd_cost,
BLOCK_SIZE bsize,
PICK_MODE_CONTEXT *ctx);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // VP9_ENCODER_VP9_PICKMODE_H_

View file

@ -0,0 +1,223 @@
/*
* 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.
*
* This code was originally written by: Gregory Maxwell, at the Daala
* project.
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "./vpx_config.h"
#include "./vp9_rtcd.h"
#include "vp9/encoder/vp9_ssim.h"
#if !defined(M_PI)
# define M_PI (3.141592653589793238462643)
#endif
#include <string.h>
void od_bin_fdct8x8(tran_low_t *y, int ystride, const int16_t *x, int xstride) {
(void) xstride;
vp9_fdct8x8_c(x, y, ystride);
}
/* Normalized inverse quantization matrix for 8x8 DCT at the point of
* transparency. This is not the JPEG based matrix from the paper,
this one gives a slightly higher MOS agreement.*/
float csf_y[8][8] = {{1.6193873005, 2.2901594831, 2.08509755623, 1.48366094411,
1.00227514334, 0.678296995242, 0.466224900598, 0.3265091542}, {2.2901594831,
1.94321815382, 2.04793073064, 1.68731108984, 1.2305666963, 0.868920337363,
0.61280991668, 0.436405793551}, {2.08509755623, 2.04793073064,
1.34329019223, 1.09205635862, 0.875748795257, 0.670882927016,
0.501731932449, 0.372504254596}, {1.48366094411, 1.68731108984,
1.09205635862, 0.772819797575, 0.605636379554, 0.48309405692,
0.380429446972, 0.295774038565}, {1.00227514334, 1.2305666963,
0.875748795257, 0.605636379554, 0.448996256676, 0.352889268808,
0.283006984131, 0.226951348204}, {0.678296995242, 0.868920337363,
0.670882927016, 0.48309405692, 0.352889268808, 0.27032073436,
0.215017739696, 0.17408067321}, {0.466224900598, 0.61280991668,
0.501731932449, 0.380429446972, 0.283006984131, 0.215017739696,
0.168869545842, 0.136153931001}, {0.3265091542, 0.436405793551,
0.372504254596, 0.295774038565, 0.226951348204, 0.17408067321,
0.136153931001, 0.109083846276}};
float csf_cb420[8][8] = {
{1.91113096927, 2.46074210438, 1.18284184739, 1.14982565193, 1.05017074788,
0.898018824055, 0.74725392039, 0.615105596242}, {2.46074210438,
1.58529308355, 1.21363250036, 1.38190029285, 1.33100189972,
1.17428548929, 0.996404342439, 0.830890433625}, {1.18284184739,
1.21363250036, 0.978712413627, 1.02624506078, 1.03145147362,
0.960060382087, 0.849823426169, 0.731221236837}, {1.14982565193,
1.38190029285, 1.02624506078, 0.861317501629, 0.801821139099,
0.751437590932, 0.685398513368, 0.608694761374}, {1.05017074788,
1.33100189972, 1.03145147362, 0.801821139099, 0.676555426187,
0.605503172737, 0.55002013668, 0.495804539034}, {0.898018824055,
1.17428548929, 0.960060382087, 0.751437590932, 0.605503172737,
0.514674450957, 0.454353482512, 0.407050308965}, {0.74725392039,
0.996404342439, 0.849823426169, 0.685398513368, 0.55002013668,
0.454353482512, 0.389234902883, 0.342353999733}, {0.615105596242,
0.830890433625, 0.731221236837, 0.608694761374, 0.495804539034,
0.407050308965, 0.342353999733, 0.295530605237}};
float csf_cr420[8][8] = {
{2.03871978502, 2.62502345193, 1.26180942886, 1.11019789803, 1.01397751469,
0.867069376285, 0.721500455585, 0.593906509971}, {2.62502345193,
1.69112867013, 1.17180569821, 1.3342742857, 1.28513006198,
1.13381474809, 0.962064122248, 0.802254508198}, {1.26180942886,
1.17180569821, 0.944981930573, 0.990876405848, 0.995903384143,
0.926972725286, 0.820534991409, 0.706020324706}, {1.11019789803,
1.3342742857, 0.990876405848, 0.831632933426, 0.77418706195,
0.725539939514, 0.661776842059, 0.587716619023}, {1.01397751469,
1.28513006198, 0.995903384143, 0.77418706195, 0.653238524286,
0.584635025748, 0.531064164893, 0.478717061273}, {0.867069376285,
1.13381474809, 0.926972725286, 0.725539939514, 0.584635025748,
0.496936637883, 0.438694579826, 0.393021669543}, {0.721500455585,
0.962064122248, 0.820534991409, 0.661776842059, 0.531064164893,
0.438694579826, 0.375820256136, 0.330555063063}, {0.593906509971,
0.802254508198, 0.706020324706, 0.587716619023, 0.478717061273,
0.393021669543, 0.330555063063, 0.285345396658}};
static double convert_score_db(double _score, double _weight) {
return 10 * (log10(255 * 255) - log10(_weight * _score));
}
static double calc_psnrhvs(const unsigned char *_src, int _systride,
const unsigned char *_dst, int _dystride,
double _par, int _w, int _h, int _step,
float _csf[8][8]) {
float ret;
int16_t dct_s[8 * 8], dct_d[8 * 8];
tran_low_t dct_s_coef[8 * 8], dct_d_coef[8 * 8];
float mask[8][8];
int pixels;
int x;
int y;
(void) _par;
ret = pixels = 0;
/*In the PSNR-HVS-M paper[1] the authors describe the construction of
their masking table as "we have used the quantization table for the
color component Y of JPEG [6] that has been also obtained on the
basis of CSF. Note that the values in quantization table JPEG have
been normalized and then squared." Their CSF matrix (from PSNR-HVS)
was also constructed from the JPEG matrices. I can not find any obvious
scheme of normalizing to produce their table, but if I multiply their
CSF by 0.38857 and square the result I get their masking table.
I have no idea where this constant comes from, but deviating from it
too greatly hurts MOS agreement.
[1] Nikolay Ponomarenko, Flavia Silvestri, Karen Egiazarian, Marco Carli,
Jaakko Astola, Vladimir Lukin, "On between-coefficient contrast masking
of DCT basis functions", CD-ROM Proceedings of the Third
International Workshop on Video Processing and Quality Metrics for Consumer
Electronics VPQM-07, Scottsdale, Arizona, USA, 25-26 January, 2007, 4 p.*/
for (x = 0; x < 8; x++)
for (y = 0; y < 8; y++)
mask[x][y] = (_csf[x][y] * 0.3885746225901003)
* (_csf[x][y] * 0.3885746225901003);
for (y = 0; y < _h - 7; y += _step) {
for (x = 0; x < _w - 7; x += _step) {
int i;
int j;
float s_means[4];
float d_means[4];
float s_vars[4];
float d_vars[4];
float s_gmean = 0;
float d_gmean = 0;
float s_gvar = 0;
float d_gvar = 0;
float s_mask = 0;
float d_mask = 0;
for (i = 0; i < 4; i++)
s_means[i] = d_means[i] = s_vars[i] = d_vars[i] = 0;
for (i = 0; i < 8; i++) {
for (j = 0; j < 8; j++) {
int sub = ((i & 12) >> 2) + ((j & 12) >> 1);
dct_s[i * 8 + j] = _src[(y + i) * _systride + (j + x)];
dct_d[i * 8 + j] = _dst[(y + i) * _dystride + (j + x)];
s_gmean += dct_s[i * 8 + j];
d_gmean += dct_d[i * 8 + j];
s_means[sub] += dct_s[i * 8 + j];
d_means[sub] += dct_d[i * 8 + j];
}
}
s_gmean /= 64.f;
d_gmean /= 64.f;
for (i = 0; i < 4; i++)
s_means[i] /= 16.f;
for (i = 0; i < 4; i++)
d_means[i] /= 16.f;
for (i = 0; i < 8; i++) {
for (j = 0; j < 8; j++) {
int sub = ((i & 12) >> 2) + ((j & 12) >> 1);
s_gvar += (dct_s[i * 8 + j] - s_gmean) * (dct_s[i * 8 + j] - s_gmean);
d_gvar += (dct_d[i * 8 + j] - d_gmean) * (dct_d[i * 8 + j] - d_gmean);
s_vars[sub] += (dct_s[i * 8 + j] - s_means[sub])
* (dct_s[i * 8 + j] - s_means[sub]);
d_vars[sub] += (dct_d[i * 8 + j] - d_means[sub])
* (dct_d[i * 8 + j] - d_means[sub]);
}
}
s_gvar *= 1 / 63.f * 64;
d_gvar *= 1 / 63.f * 64;
for (i = 0; i < 4; i++)
s_vars[i] *= 1 / 15.f * 16;
for (i = 0; i < 4; i++)
d_vars[i] *= 1 / 15.f * 16;
if (s_gvar > 0)
s_gvar = (s_vars[0] + s_vars[1] + s_vars[2] + s_vars[3]) / s_gvar;
if (d_gvar > 0)
d_gvar = (d_vars[0] + d_vars[1] + d_vars[2] + d_vars[3]) / d_gvar;
od_bin_fdct8x8(dct_s_coef, 8, dct_s, 8);
od_bin_fdct8x8(dct_d_coef, 8, dct_d, 8);
for (i = 0; i < 8; i++)
for (j = (i == 0); j < 8; j++)
s_mask += dct_s_coef[i * 8 + j] * dct_s_coef[i * 8 + j] * mask[i][j];
for (i = 0; i < 8; i++)
for (j = (i == 0); j < 8; j++)
d_mask += dct_d_coef[i * 8 + j] * dct_d_coef[i * 8 + j] * mask[i][j];
s_mask = sqrt(s_mask * s_gvar) / 32.f;
d_mask = sqrt(d_mask * d_gvar) / 32.f;
if (d_mask > s_mask)
s_mask = d_mask;
for (i = 0; i < 8; i++) {
for (j = 0; j < 8; j++) {
float err;
err = fabs(dct_s_coef[i * 8 + j] - dct_d_coef[i * 8 + j]);
if (i != 0 || j != 0)
err = err < s_mask / mask[i][j] ? 0 : err - s_mask / mask[i][j];
ret += (err * _csf[i][j]) * (err * _csf[i][j]);
pixels++;
}
}
}
}
ret /= pixels;
return ret;
}
double vp9_psnrhvs(YV12_BUFFER_CONFIG *source, YV12_BUFFER_CONFIG *dest,
double *y_psnrhvs, double *u_psnrhvs, double *v_psnrhvs) {
double psnrhvs;
double par = 1.0;
int step = 7;
vp9_clear_system_state();
*y_psnrhvs = calc_psnrhvs(source->y_buffer, source->y_stride, dest->y_buffer,
dest->y_stride, par, source->y_crop_width,
source->y_crop_height, step, csf_y);
*u_psnrhvs = calc_psnrhvs(source->u_buffer, source->uv_stride, dest->u_buffer,
dest->uv_stride, par, source->uv_crop_width,
source->uv_crop_height, step, csf_cb420);
*v_psnrhvs = calc_psnrhvs(source->v_buffer, source->uv_stride, dest->v_buffer,
dest->uv_stride, par, source->uv_crop_width,
source->uv_crop_height, step, csf_cr420);
psnrhvs = (*y_psnrhvs) * .8 + .1 * ((*u_psnrhvs) + (*v_psnrhvs));
return convert_score_db(psnrhvs, 1.0);
}

View file

@ -0,0 +1,728 @@
/*
* 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 <math.h>
#include "vpx_mem/vpx_mem.h"
#include "vpx_ports/mem.h"
#include "vp9/common/vp9_quant_common.h"
#include "vp9/common/vp9_seg_common.h"
#include "vp9/encoder/vp9_encoder.h"
#include "vp9/encoder/vp9_quantize.h"
#include "vp9/encoder/vp9_rd.h"
void vp9_quantize_dc(const tran_low_t *coeff_ptr,
int n_coeffs, int skip_block,
const int16_t *round_ptr, const int16_t quant,
tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr,
const int16_t dequant_ptr, uint16_t *eob_ptr) {
const int rc = 0;
const int coeff = coeff_ptr[rc];
const int coeff_sign = (coeff >> 31);
const int abs_coeff = (coeff ^ coeff_sign) - coeff_sign;
int tmp, eob = -1;
memset(qcoeff_ptr, 0, n_coeffs * sizeof(*qcoeff_ptr));
memset(dqcoeff_ptr, 0, n_coeffs * sizeof(*dqcoeff_ptr));
if (!skip_block) {
tmp = clamp(abs_coeff + round_ptr[rc != 0], INT16_MIN, INT16_MAX);
tmp = (tmp * quant) >> 16;
qcoeff_ptr[rc] = (tmp ^ coeff_sign) - coeff_sign;
dqcoeff_ptr[rc] = qcoeff_ptr[rc] * dequant_ptr;
if (tmp)
eob = 0;
}
*eob_ptr = eob + 1;
}
#if CONFIG_VP9_HIGHBITDEPTH
void vp9_highbd_quantize_dc(const tran_low_t *coeff_ptr,
int n_coeffs, int skip_block,
const int16_t *round_ptr, const int16_t quant,
tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr,
const int16_t dequant_ptr, uint16_t *eob_ptr) {
int eob = -1;
memset(qcoeff_ptr, 0, n_coeffs * sizeof(*qcoeff_ptr));
memset(dqcoeff_ptr, 0, n_coeffs * sizeof(*dqcoeff_ptr));
if (!skip_block) {
const int rc = 0;
const int coeff = coeff_ptr[rc];
const int coeff_sign = (coeff >> 31);
const int abs_coeff = (coeff ^ coeff_sign) - coeff_sign;
const int64_t tmp =
(clamp(abs_coeff + round_ptr[rc != 0], INT32_MIN, INT32_MAX) *
quant) >> 16;
qcoeff_ptr[rc] = (tran_low_t)((tmp ^ coeff_sign) - coeff_sign);
dqcoeff_ptr[rc] = qcoeff_ptr[rc] * dequant_ptr;
if (tmp)
eob = 0;
}
*eob_ptr = eob + 1;
}
#endif
void vp9_quantize_dc_32x32(const tran_low_t *coeff_ptr, int skip_block,
const int16_t *round_ptr, const int16_t quant,
tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr,
const int16_t dequant_ptr, uint16_t *eob_ptr) {
const int n_coeffs = 1024;
const int rc = 0;
const int coeff = coeff_ptr[rc];
const int coeff_sign = (coeff >> 31);
const int abs_coeff = (coeff ^ coeff_sign) - coeff_sign;
int tmp, eob = -1;
memset(qcoeff_ptr, 0, n_coeffs * sizeof(*qcoeff_ptr));
memset(dqcoeff_ptr, 0, n_coeffs * sizeof(*dqcoeff_ptr));
if (!skip_block) {
tmp = clamp(abs_coeff + ROUND_POWER_OF_TWO(round_ptr[rc != 0], 1),
INT16_MIN, INT16_MAX);
tmp = (tmp * quant) >> 15;
qcoeff_ptr[rc] = (tmp ^ coeff_sign) - coeff_sign;
dqcoeff_ptr[rc] = qcoeff_ptr[rc] * dequant_ptr / 2;
if (tmp)
eob = 0;
}
*eob_ptr = eob + 1;
}
#if CONFIG_VP9_HIGHBITDEPTH
void vp9_highbd_quantize_dc_32x32(const tran_low_t *coeff_ptr,
int skip_block,
const int16_t *round_ptr,
const int16_t quant,
tran_low_t *qcoeff_ptr,
tran_low_t *dqcoeff_ptr,
const int16_t dequant_ptr,
uint16_t *eob_ptr) {
const int n_coeffs = 1024;
int eob = -1;
memset(qcoeff_ptr, 0, n_coeffs * sizeof(*qcoeff_ptr));
memset(dqcoeff_ptr, 0, n_coeffs * sizeof(*dqcoeff_ptr));
if (!skip_block) {
const int rc = 0;
const int coeff = coeff_ptr[rc];
const int coeff_sign = (coeff >> 31);
const int abs_coeff = (coeff ^ coeff_sign) - coeff_sign;
const int64_t tmp =
(clamp(abs_coeff + ROUND_POWER_OF_TWO(round_ptr[rc != 0], 1),
INT32_MIN, INT32_MAX) * quant) >> 15;
qcoeff_ptr[rc] = (tran_low_t)((tmp ^ coeff_sign) - coeff_sign);
dqcoeff_ptr[rc] = qcoeff_ptr[rc] * dequant_ptr / 2;
if (tmp)
eob = 0;
}
*eob_ptr = eob + 1;
}
#endif
void vp9_quantize_fp_c(const tran_low_t *coeff_ptr, intptr_t n_coeffs,
int skip_block,
const int16_t *zbin_ptr, const int16_t *round_ptr,
const int16_t *quant_ptr, const int16_t *quant_shift_ptr,
tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr,
const int16_t *dequant_ptr,
uint16_t *eob_ptr,
const int16_t *scan, const int16_t *iscan) {
int i, eob = -1;
// 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 (!skip_block) {
// Quantization pass: All coefficients with index >= zero_flag are
// skippable. Note: zero_flag can be zero.
for (i = 0; i < n_coeffs; i++) {
const int rc = scan[i];
const int coeff = coeff_ptr[rc];
const int coeff_sign = (coeff >> 31);
const int abs_coeff = (coeff ^ coeff_sign) - coeff_sign;
int tmp = clamp(abs_coeff + round_ptr[rc != 0], INT16_MIN, INT16_MAX);
tmp = (tmp * quant_ptr[rc != 0]) >> 16;
qcoeff_ptr[rc] = (tmp ^ coeff_sign) - coeff_sign;
dqcoeff_ptr[rc] = qcoeff_ptr[rc] * dequant_ptr[rc != 0];
if (tmp)
eob = i;
}
}
*eob_ptr = eob + 1;
}
#if CONFIG_VP9_HIGHBITDEPTH
void vp9_highbd_quantize_fp_c(const tran_low_t *coeff_ptr,
intptr_t count,
int skip_block,
const int16_t *zbin_ptr,
const int16_t *round_ptr,
const int16_t *quant_ptr,
const int16_t *quant_shift_ptr,
tran_low_t *qcoeff_ptr,
tran_low_t *dqcoeff_ptr,
const int16_t *dequant_ptr,
uint16_t *eob_ptr,
const int16_t *scan,
const int16_t *iscan) {
int i;
int eob = -1;
// 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, count * sizeof(*qcoeff_ptr));
memset(dqcoeff_ptr, 0, count * sizeof(*dqcoeff_ptr));
if (!skip_block) {
// Quantization pass: All coefficients with index >= zero_flag are
// skippable. Note: zero_flag can be zero.
for (i = 0; i < count; i++) {
const int rc = scan[i];
const int coeff = coeff_ptr[rc];
const int coeff_sign = (coeff >> 31);
const int abs_coeff = (coeff ^ coeff_sign) - coeff_sign;
const int64_t tmp =
(clamp(abs_coeff + round_ptr[rc != 0], INT32_MIN, INT32_MAX) *
quant_ptr[rc != 0]) >> 16;
qcoeff_ptr[rc] = (tran_low_t)((tmp ^ coeff_sign) - coeff_sign);
dqcoeff_ptr[rc] = qcoeff_ptr[rc] * dequant_ptr[rc != 0];
if (tmp)
eob = i;
}
}
*eob_ptr = eob + 1;
}
#endif
// TODO(jingning) Refactor this file and combine functions with similar
// operations.
void vp9_quantize_fp_32x32_c(const tran_low_t *coeff_ptr, intptr_t n_coeffs,
int skip_block,
const int16_t *zbin_ptr, const int16_t *round_ptr,
const int16_t *quant_ptr,
const int16_t *quant_shift_ptr,
tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr,
const int16_t *dequant_ptr,
uint16_t *eob_ptr,
const int16_t *scan, const int16_t *iscan) {
int i, eob = -1;
(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 (!skip_block) {
for (i = 0; i < n_coeffs; i++) {
const int rc = scan[i];
const int coeff = coeff_ptr[rc];
const int coeff_sign = (coeff >> 31);
int tmp = 0;
int abs_coeff = (coeff ^ coeff_sign) - coeff_sign;
if (abs_coeff >= (dequant_ptr[rc != 0] >> 2)) {
abs_coeff += ROUND_POWER_OF_TWO(round_ptr[rc != 0], 1);
abs_coeff = clamp(abs_coeff, INT16_MIN, INT16_MAX);
tmp = (abs_coeff * quant_ptr[rc != 0]) >> 15;
qcoeff_ptr[rc] = (tmp ^ coeff_sign) - coeff_sign;
dqcoeff_ptr[rc] = qcoeff_ptr[rc] * dequant_ptr[rc != 0] / 2;
}
if (tmp)
eob = i;
}
}
*eob_ptr = eob + 1;
}
#if CONFIG_VP9_HIGHBITDEPTH
void vp9_highbd_quantize_fp_32x32_c(const tran_low_t *coeff_ptr,
intptr_t n_coeffs, int skip_block,
const int16_t *zbin_ptr,
const int16_t *round_ptr,
const int16_t *quant_ptr,
const int16_t *quant_shift_ptr,
tran_low_t *qcoeff_ptr,
tran_low_t *dqcoeff_ptr,
const int16_t *dequant_ptr,
uint16_t *eob_ptr,
const int16_t *scan, const int16_t *iscan) {
int i, eob = -1;
(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 (!skip_block) {
for (i = 0; i < n_coeffs; i++) {
const int rc = scan[i];
const int coeff = coeff_ptr[rc];
const int coeff_sign = (coeff >> 31);
int64_t tmp = 0;
const int abs_coeff = (coeff ^ coeff_sign) - coeff_sign;
if (abs_coeff >= (dequant_ptr[rc != 0] >> 2)) {
tmp = clamp(abs_coeff + ROUND_POWER_OF_TWO(round_ptr[rc != 0], 1),
INT32_MIN, INT32_MAX);
tmp = (tmp * quant_ptr[rc != 0]) >> 15;
qcoeff_ptr[rc] = (tran_low_t)((tmp ^ coeff_sign) - coeff_sign);
dqcoeff_ptr[rc] = qcoeff_ptr[rc] * dequant_ptr[rc != 0] / 2;
}
if (tmp)
eob = i;
}
}
*eob_ptr = eob + 1;
}
#endif
void vp9_quantize_b_c(const tran_low_t *coeff_ptr, intptr_t n_coeffs,
int skip_block,
const int16_t *zbin_ptr, const int16_t *round_ptr,
const int16_t *quant_ptr, const int16_t *quant_shift_ptr,
tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr,
const int16_t *dequant_ptr,
uint16_t *eob_ptr,
const int16_t *scan, const int16_t *iscan) {
int i, non_zero_count = (int)n_coeffs, eob = -1;
const int zbins[2] = {zbin_ptr[0], zbin_ptr[1]};
const int nzbins[2] = {zbins[0] * -1, zbins[1] * -1};
(void)iscan;
memset(qcoeff_ptr, 0, n_coeffs * sizeof(*qcoeff_ptr));
memset(dqcoeff_ptr, 0, n_coeffs * sizeof(*dqcoeff_ptr));
if (!skip_block) {
// Pre-scan pass
for (i = (int)n_coeffs - 1; i >= 0; i--) {
const int rc = scan[i];
const int coeff = coeff_ptr[rc];
if (coeff < zbins[rc != 0] && coeff > nzbins[rc != 0])
non_zero_count--;
else
break;
}
// Quantization pass: All coefficients with index >= zero_flag are
// skippable. Note: zero_flag can be zero.
for (i = 0; i < non_zero_count; i++) {
const int rc = scan[i];
const int coeff = coeff_ptr[rc];
const int coeff_sign = (coeff >> 31);
const int abs_coeff = (coeff ^ coeff_sign) - coeff_sign;
if (abs_coeff >= zbins[rc != 0]) {
int tmp = clamp(abs_coeff + round_ptr[rc != 0], INT16_MIN, INT16_MAX);
tmp = ((((tmp * quant_ptr[rc != 0]) >> 16) + tmp) *
quant_shift_ptr[rc != 0]) >> 16; // quantization
qcoeff_ptr[rc] = (tmp ^ coeff_sign) - coeff_sign;
dqcoeff_ptr[rc] = qcoeff_ptr[rc] * dequant_ptr[rc != 0];
if (tmp)
eob = i;
}
}
}
*eob_ptr = eob + 1;
}
#if CONFIG_VP9_HIGHBITDEPTH
void vp9_highbd_quantize_b_c(const tran_low_t *coeff_ptr, intptr_t n_coeffs,
int skip_block, const int16_t *zbin_ptr,
const int16_t *round_ptr, const int16_t *quant_ptr,
const int16_t *quant_shift_ptr,
tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr,
const int16_t *dequant_ptr,
uint16_t *eob_ptr, const int16_t *scan,
const int16_t *iscan) {
int i, non_zero_count = (int)n_coeffs, eob = -1;
const int zbins[2] = {zbin_ptr[0], zbin_ptr[1]};
const int nzbins[2] = {zbins[0] * -1, zbins[1] * -1};
(void)iscan;
memset(qcoeff_ptr, 0, n_coeffs * sizeof(*qcoeff_ptr));
memset(dqcoeff_ptr, 0, n_coeffs * sizeof(*dqcoeff_ptr));
if (!skip_block) {
// Pre-scan pass
for (i = (int)n_coeffs - 1; i >= 0; i--) {
const int rc = scan[i];
const int coeff = coeff_ptr[rc];
if (coeff < zbins[rc != 0] && coeff > nzbins[rc != 0])
non_zero_count--;
else
break;
}
// Quantization pass: All coefficients with index >= zero_flag are
// skippable. Note: zero_flag can be zero.
for (i = 0; i < non_zero_count; i++) {
const int rc = scan[i];
const int coeff = coeff_ptr[rc];
const int coeff_sign = (coeff >> 31);
const int abs_coeff = (coeff ^ coeff_sign) - coeff_sign;
if (abs_coeff >= zbins[rc != 0]) {
int64_t tmp = clamp(abs_coeff + round_ptr[rc != 0],
INT32_MIN, INT32_MAX);
tmp = ((((tmp * quant_ptr[rc != 0]) >> 16) + tmp) *
quant_shift_ptr[rc != 0]) >> 16; // quantization
qcoeff_ptr[rc] = (tran_low_t)((tmp ^ coeff_sign) - coeff_sign);
dqcoeff_ptr[rc] = qcoeff_ptr[rc] * dequant_ptr[rc != 0];
if (tmp)
eob = i;
}
}
}
*eob_ptr = eob + 1;
}
#endif
void vp9_quantize_b_32x32_c(const tran_low_t *coeff_ptr, intptr_t n_coeffs,
int skip_block,
const int16_t *zbin_ptr, const int16_t *round_ptr,
const int16_t *quant_ptr,
const int16_t *quant_shift_ptr,
tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr,
const int16_t *dequant_ptr,
uint16_t *eob_ptr,
const int16_t *scan, const int16_t *iscan) {
const int zbins[2] = {ROUND_POWER_OF_TWO(zbin_ptr[0], 1),
ROUND_POWER_OF_TWO(zbin_ptr[1], 1)};
const int nzbins[2] = {zbins[0] * -1, zbins[1] * -1};
int idx = 0;
int idx_arr[1024];
int i, eob = -1;
(void)iscan;
memset(qcoeff_ptr, 0, n_coeffs * sizeof(*qcoeff_ptr));
memset(dqcoeff_ptr, 0, n_coeffs * sizeof(*dqcoeff_ptr));
if (!skip_block) {
// Pre-scan pass
for (i = 0; i < n_coeffs; i++) {
const int rc = scan[i];
const int coeff = coeff_ptr[rc];
// If the coefficient is out of the base ZBIN range, keep it for
// quantization.
if (coeff >= zbins[rc != 0] || coeff <= nzbins[rc != 0])
idx_arr[idx++] = i;
}
// Quantization pass: only process the coefficients selected in
// pre-scan pass. Note: idx can be zero.
for (i = 0; i < idx; i++) {
const int rc = scan[idx_arr[i]];
const int coeff = coeff_ptr[rc];
const int coeff_sign = (coeff >> 31);
int tmp;
int abs_coeff = (coeff ^ coeff_sign) - coeff_sign;
abs_coeff += ROUND_POWER_OF_TWO(round_ptr[rc != 0], 1);
abs_coeff = clamp(abs_coeff, INT16_MIN, INT16_MAX);
tmp = ((((abs_coeff * quant_ptr[rc != 0]) >> 16) + abs_coeff) *
quant_shift_ptr[rc != 0]) >> 15;
qcoeff_ptr[rc] = (tmp ^ coeff_sign) - coeff_sign;
dqcoeff_ptr[rc] = qcoeff_ptr[rc] * dequant_ptr[rc != 0] / 2;
if (tmp)
eob = idx_arr[i];
}
}
*eob_ptr = eob + 1;
}
#if CONFIG_VP9_HIGHBITDEPTH
void vp9_highbd_quantize_b_32x32_c(const tran_low_t *coeff_ptr,
intptr_t n_coeffs, int skip_block,
const int16_t *zbin_ptr,
const int16_t *round_ptr,
const int16_t *quant_ptr,
const int16_t *quant_shift_ptr,
tran_low_t *qcoeff_ptr,
tran_low_t *dqcoeff_ptr,
const int16_t *dequant_ptr,
uint16_t *eob_ptr,
const int16_t *scan, const int16_t *iscan) {
const int zbins[2] = {ROUND_POWER_OF_TWO(zbin_ptr[0], 1),
ROUND_POWER_OF_TWO(zbin_ptr[1], 1)};
const int nzbins[2] = {zbins[0] * -1, zbins[1] * -1};
int idx = 0;
int idx_arr[1024];
int i, eob = -1;
(void)iscan;
memset(qcoeff_ptr, 0, n_coeffs * sizeof(*qcoeff_ptr));
memset(dqcoeff_ptr, 0, n_coeffs * sizeof(*dqcoeff_ptr));
if (!skip_block) {
// Pre-scan pass
for (i = 0; i < n_coeffs; i++) {
const int rc = scan[i];
const int coeff = coeff_ptr[rc];
// If the coefficient is out of the base ZBIN range, keep it for
// quantization.
if (coeff >= zbins[rc != 0] || coeff <= nzbins[rc != 0])
idx_arr[idx++] = i;
}
// Quantization pass: only process the coefficients selected in
// pre-scan pass. Note: idx can be zero.
for (i = 0; i < idx; i++) {
const int rc = scan[idx_arr[i]];
const int coeff = coeff_ptr[rc];
const int coeff_sign = (coeff >> 31);
const int abs_coeff = (coeff ^ coeff_sign) - coeff_sign;
int64_t tmp = clamp(abs_coeff +
ROUND_POWER_OF_TWO(round_ptr[rc != 0], 1),
INT32_MIN, INT32_MAX);
tmp = ((((tmp * quant_ptr[rc != 0]) >> 16) + tmp) *
quant_shift_ptr[rc != 0]) >> 15;
qcoeff_ptr[rc] = (tran_low_t)((tmp ^ coeff_sign) - coeff_sign);
dqcoeff_ptr[rc] = qcoeff_ptr[rc] * dequant_ptr[rc != 0] / 2;
if (tmp)
eob = idx_arr[i];
}
}
*eob_ptr = eob + 1;
}
#endif
void vp9_regular_quantize_b_4x4(MACROBLOCK *x, int plane, int block,
const int16_t *scan, const int16_t *iscan) {
MACROBLOCKD *const xd = &x->e_mbd;
struct macroblock_plane *p = &x->plane[plane];
struct macroblockd_plane *pd = &xd->plane[plane];
#if CONFIG_VP9_HIGHBITDEPTH
if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) {
vp9_highbd_quantize_b(BLOCK_OFFSET(p->coeff, block),
16, x->skip_block,
p->zbin, p->round, p->quant, p->quant_shift,
BLOCK_OFFSET(p->qcoeff, block),
BLOCK_OFFSET(pd->dqcoeff, block),
pd->dequant, &p->eobs[block],
scan, iscan);
return;
}
#endif
vp9_quantize_b(BLOCK_OFFSET(p->coeff, block),
16, x->skip_block,
p->zbin, p->round, p->quant, p->quant_shift,
BLOCK_OFFSET(p->qcoeff, block),
BLOCK_OFFSET(pd->dqcoeff, block),
pd->dequant, &p->eobs[block], scan, iscan);
}
static void invert_quant(int16_t *quant, int16_t *shift, int d) {
unsigned t;
int l;
t = d;
for (l = 0; t > 1; l++)
t >>= 1;
t = 1 + (1 << (16 + l)) / d;
*quant = (int16_t)(t - (1 << 16));
*shift = 1 << (16 - l);
}
static int get_qzbin_factor(int q, vpx_bit_depth_t bit_depth) {
const int quant = vp9_dc_quant(q, 0, bit_depth);
#if CONFIG_VP9_HIGHBITDEPTH
switch (bit_depth) {
case VPX_BITS_8:
return q == 0 ? 64 : (quant < 148 ? 84 : 80);
case VPX_BITS_10:
return q == 0 ? 64 : (quant < 592 ? 84 : 80);
case VPX_BITS_12:
return q == 0 ? 64 : (quant < 2368 ? 84 : 80);
default:
assert(0 && "bit_depth should be VPX_BITS_8, VPX_BITS_10 or VPX_BITS_12");
return -1;
}
#else
(void) bit_depth;
return q == 0 ? 64 : (quant < 148 ? 84 : 80);
#endif
}
void vp9_init_quantizer(VP9_COMP *cpi) {
VP9_COMMON *const cm = &cpi->common;
QUANTS *const quants = &cpi->quants;
int i, q, quant;
for (q = 0; q < QINDEX_RANGE; q++) {
const int qzbin_factor = get_qzbin_factor(q, cm->bit_depth);
const int qrounding_factor = q == 0 ? 64 : 48;
for (i = 0; i < 2; ++i) {
int qrounding_factor_fp = i == 0 ? 48 : 42;
if (q == 0)
qrounding_factor_fp = 64;
// y
quant = i == 0 ? vp9_dc_quant(q, cm->y_dc_delta_q, cm->bit_depth)
: vp9_ac_quant(q, 0, cm->bit_depth);
invert_quant(&quants->y_quant[q][i], &quants->y_quant_shift[q][i], quant);
quants->y_quant_fp[q][i] = (1 << 16) / quant;
quants->y_round_fp[q][i] = (qrounding_factor_fp * quant) >> 7;
quants->y_zbin[q][i] = ROUND_POWER_OF_TWO(qzbin_factor * quant, 7);
quants->y_round[q][i] = (qrounding_factor * quant) >> 7;
cpi->y_dequant[q][i] = quant;
// uv
quant = i == 0 ? vp9_dc_quant(q, cm->uv_dc_delta_q, cm->bit_depth)
: vp9_ac_quant(q, cm->uv_ac_delta_q, cm->bit_depth);
invert_quant(&quants->uv_quant[q][i],
&quants->uv_quant_shift[q][i], quant);
quants->uv_quant_fp[q][i] = (1 << 16) / quant;
quants->uv_round_fp[q][i] = (qrounding_factor_fp * quant) >> 7;
quants->uv_zbin[q][i] = ROUND_POWER_OF_TWO(qzbin_factor * quant, 7);
quants->uv_round[q][i] = (qrounding_factor * quant) >> 7;
cpi->uv_dequant[q][i] = quant;
}
for (i = 2; i < 8; i++) {
quants->y_quant[q][i] = quants->y_quant[q][1];
quants->y_quant_fp[q][i] = quants->y_quant_fp[q][1];
quants->y_round_fp[q][i] = quants->y_round_fp[q][1];
quants->y_quant_shift[q][i] = quants->y_quant_shift[q][1];
quants->y_zbin[q][i] = quants->y_zbin[q][1];
quants->y_round[q][i] = quants->y_round[q][1];
cpi->y_dequant[q][i] = cpi->y_dequant[q][1];
quants->uv_quant[q][i] = quants->uv_quant[q][1];
quants->uv_quant_fp[q][i] = quants->uv_quant_fp[q][1];
quants->uv_round_fp[q][i] = quants->uv_round_fp[q][1];
quants->uv_quant_shift[q][i] = quants->uv_quant_shift[q][1];
quants->uv_zbin[q][i] = quants->uv_zbin[q][1];
quants->uv_round[q][i] = quants->uv_round[q][1];
cpi->uv_dequant[q][i] = cpi->uv_dequant[q][1];
}
}
}
void vp9_init_plane_quantizers(VP9_COMP *cpi, MACROBLOCK *x) {
const VP9_COMMON *const cm = &cpi->common;
MACROBLOCKD *const xd = &x->e_mbd;
QUANTS *const quants = &cpi->quants;
const int segment_id = xd->mi[0]->mbmi.segment_id;
const int qindex = vp9_get_qindex(&cm->seg, segment_id, cm->base_qindex);
const int rdmult = vp9_compute_rd_mult(cpi, qindex + cm->y_dc_delta_q);
int i;
// Y
x->plane[0].quant = quants->y_quant[qindex];
x->plane[0].quant_fp = quants->y_quant_fp[qindex];
x->plane[0].round_fp = quants->y_round_fp[qindex];
x->plane[0].quant_shift = quants->y_quant_shift[qindex];
x->plane[0].zbin = quants->y_zbin[qindex];
x->plane[0].round = quants->y_round[qindex];
xd->plane[0].dequant = cpi->y_dequant[qindex];
x->plane[0].quant_thred[0] = x->plane[0].zbin[0] * x->plane[0].zbin[0];
x->plane[0].quant_thred[1] = x->plane[0].zbin[1] * x->plane[0].zbin[1];
// UV
for (i = 1; i < 3; i++) {
x->plane[i].quant = quants->uv_quant[qindex];
x->plane[i].quant_fp = quants->uv_quant_fp[qindex];
x->plane[i].round_fp = quants->uv_round_fp[qindex];
x->plane[i].quant_shift = quants->uv_quant_shift[qindex];
x->plane[i].zbin = quants->uv_zbin[qindex];
x->plane[i].round = quants->uv_round[qindex];
xd->plane[i].dequant = cpi->uv_dequant[qindex];
x->plane[i].quant_thred[0] = x->plane[i].zbin[0] * x->plane[i].zbin[0];
x->plane[i].quant_thred[1] = x->plane[i].zbin[1] * x->plane[i].zbin[1];
}
x->skip_block = vp9_segfeature_active(&cm->seg, segment_id, SEG_LVL_SKIP);
x->q_index = qindex;
x->errorperbit = rdmult >> 6;
x->errorperbit += (x->errorperbit == 0);
vp9_initialize_me_consts(cpi, x, x->q_index);
}
void vp9_frame_init_quantizer(VP9_COMP *cpi) {
vp9_init_plane_quantizers(cpi, &cpi->td.mb);
}
void vp9_set_quantizer(VP9_COMMON *cm, int q) {
// quantizer has to be reinitialized with vp9_init_quantizer() if any
// delta_q changes.
cm->base_qindex = q;
cm->y_dc_delta_q = 0;
cm->uv_dc_delta_q = 0;
cm->uv_ac_delta_q = 0;
}
// Table that converts 0-63 Q-range values passed in outside to the Qindex
// range used internally.
static const int quantizer_to_qindex[] = {
0, 4, 8, 12, 16, 20, 24, 28,
32, 36, 40, 44, 48, 52, 56, 60,
64, 68, 72, 76, 80, 84, 88, 92,
96, 100, 104, 108, 112, 116, 120, 124,
128, 132, 136, 140, 144, 148, 152, 156,
160, 164, 168, 172, 176, 180, 184, 188,
192, 196, 200, 204, 208, 212, 216, 220,
224, 228, 232, 236, 240, 244, 249, 255,
};
int vp9_quantizer_to_qindex(int quantizer) {
return quantizer_to_qindex[quantizer];
}
int vp9_qindex_to_quantizer(int qindex) {
int quantizer;
for (quantizer = 0; quantizer < 64; ++quantizer)
if (quantizer_to_qindex[quantizer] >= qindex)
return quantizer;
return 63;
}

View file

@ -0,0 +1,87 @@
/*
* 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.
*/
#ifndef VP9_ENCODER_VP9_QUANTIZE_H_
#define VP9_ENCODER_VP9_QUANTIZE_H_
#include "./vpx_config.h"
#include "vp9/encoder/vp9_block.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
DECLARE_ALIGNED(16, int16_t, y_quant[QINDEX_RANGE][8]);
DECLARE_ALIGNED(16, int16_t, y_quant_shift[QINDEX_RANGE][8]);
DECLARE_ALIGNED(16, int16_t, y_zbin[QINDEX_RANGE][8]);
DECLARE_ALIGNED(16, int16_t, y_round[QINDEX_RANGE][8]);
// TODO(jingning): in progress of re-working the quantization. will decide
// if we want to deprecate the current use of y_quant.
DECLARE_ALIGNED(16, int16_t, y_quant_fp[QINDEX_RANGE][8]);
DECLARE_ALIGNED(16, int16_t, uv_quant_fp[QINDEX_RANGE][8]);
DECLARE_ALIGNED(16, int16_t, y_round_fp[QINDEX_RANGE][8]);
DECLARE_ALIGNED(16, int16_t, uv_round_fp[QINDEX_RANGE][8]);
DECLARE_ALIGNED(16, int16_t, uv_quant[QINDEX_RANGE][8]);
DECLARE_ALIGNED(16, int16_t, uv_quant_shift[QINDEX_RANGE][8]);
DECLARE_ALIGNED(16, int16_t, uv_zbin[QINDEX_RANGE][8]);
DECLARE_ALIGNED(16, int16_t, uv_round[QINDEX_RANGE][8]);
} QUANTS;
void vp9_quantize_dc(const tran_low_t *coeff_ptr,
int n_coeffs, int skip_block,
const int16_t *round_ptr, const int16_t quant_ptr,
tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr,
const int16_t dequant_ptr, uint16_t *eob_ptr);
void vp9_quantize_dc_32x32(const tran_low_t *coeff_ptr, int skip_block,
const int16_t *round_ptr, const int16_t quant_ptr,
tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr,
const int16_t dequant_ptr, uint16_t *eob_ptr);
void vp9_regular_quantize_b_4x4(MACROBLOCK *x, int plane, int block,
const int16_t *scan, const int16_t *iscan);
#if CONFIG_VP9_HIGHBITDEPTH
void vp9_highbd_quantize_dc(const tran_low_t *coeff_ptr,
int n_coeffs, int skip_block,
const int16_t *round_ptr, const int16_t quant_ptr,
tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr,
const int16_t dequant_ptr, uint16_t *eob_ptr);
void vp9_highbd_quantize_dc_32x32(const tran_low_t *coeff_ptr,
int skip_block,
const int16_t *round_ptr,
const int16_t quant_ptr,
tran_low_t *qcoeff_ptr,
tran_low_t *dqcoeff_ptr,
const int16_t dequant_ptr,
uint16_t *eob_ptr);
#endif
struct VP9_COMP;
struct VP9Common;
void vp9_frame_init_quantizer(struct VP9_COMP *cpi);
void vp9_init_plane_quantizers(struct VP9_COMP *cpi, MACROBLOCK *x);
void vp9_init_quantizer(struct VP9_COMP *cpi);
void vp9_set_quantizer(struct VP9Common *cm, int q);
int vp9_quantizer_to_qindex(int quantizer);
int vp9_qindex_to_quantizer(int qindex);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // VP9_ENCODER_VP9_QUANTIZE_H_

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,252 @@
/*
* 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.
*/
#ifndef VP9_ENCODER_VP9_RATECTRL_H_
#define VP9_ENCODER_VP9_RATECTRL_H_
#include "vpx/vpx_codec.h"
#include "vpx/vpx_integer.h"
#include "vp9/common/vp9_blockd.h"
#ifdef __cplusplus
extern "C" {
#endif
// Bits Per MB at different Q (Multiplied by 512)
#define BPER_MB_NORMBITS 9
typedef enum {
INTER_NORMAL = 0,
INTER_HIGH = 1,
GF_ARF_LOW = 2,
GF_ARF_STD = 3,
KF_STD = 4,
RATE_FACTOR_LEVELS = 5
} RATE_FACTOR_LEVEL;
// Internal frame scaling level.
typedef enum {
UNSCALED = 0, // Frame is unscaled.
SCALE_STEP1 = 1, // First-level down-scaling.
FRAME_SCALE_STEPS
} FRAME_SCALE_LEVEL;
// Frame dimensions multiplier wrt the native frame size, in 1/16ths,
// specified for the scale-up case.
// e.g. 24 => 16/24 = 2/3 of native size. The restriction to 1/16th is
// intended to match the capabilities of the normative scaling filters,
// giving precedence to the up-scaling accuracy.
static const int frame_scale_factor[FRAME_SCALE_STEPS] = {16, 24};
// Multiplier of the target rate to be used as threshold for triggering scaling.
static const double rate_thresh_mult[FRAME_SCALE_STEPS] = {1.0, 2.0};
// Scale dependent Rate Correction Factor multipliers. Compensates for the
// greater number of bits per pixel generated in down-scaled frames.
static const double rcf_mult[FRAME_SCALE_STEPS] = {1.0, 2.0};
typedef struct {
// Rate targetting variables
int base_frame_target; // A baseline frame target before adjustment
// for previous under or over shoot.
int this_frame_target; // Actual frame target after rc adjustment.
int projected_frame_size;
int sb64_target_rate;
int last_q[FRAME_TYPES]; // Separate values for Intra/Inter
int last_boosted_qindex; // Last boosted GF/KF/ARF q
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];
int frames_since_golden;
int frames_till_gf_update_due;
int min_gf_interval;
int max_gf_interval;
int static_scene_max_gf_interval;
int baseline_gf_interval;
int constrained_gf_group;
int frames_to_key;
int frames_since_key;
int this_key_frame_forced;
int next_key_frame_forced;
int source_alt_ref_pending;
int source_alt_ref_active;
int is_src_frame_alt_ref;
int avg_frame_bandwidth; // Average frame size target for clip
int min_frame_bandwidth; // Minimum allocation used for any frame
int max_frame_bandwidth; // Maximum burst rate allowed for a frame.
int ni_av_qi;
int ni_tot_qi;
int ni_frames;
int avg_frame_qindex[FRAME_TYPES];
double tot_q;
double avg_q;
int64_t buffer_level;
int64_t bits_off_target;
int64_t vbr_bits_off_target;
int64_t vbr_bits_off_target_fast;
int decimation_factor;
int decimation_count;
int rolling_target_bits;
int rolling_actual_bits;
int long_rolling_target_bits;
int long_rolling_actual_bits;
int rate_error_estimate;
int64_t total_actual_bits;
int64_t total_target_bits;
int64_t total_target_vs_actual;
int worst_quality;
int best_quality;
int64_t starting_buffer_level;
int64_t optimal_buffer_level;
int64_t maximum_buffer_size;
// rate control history for last frame(1) and the frame before(2).
// -1: undershot
// 1: overshoot
// 0: not initialized.
int rc_1_frame;
int rc_2_frame;
int q_1_frame;
int q_2_frame;
// Auto frame-scaling variables.
FRAME_SCALE_LEVEL frame_size_selector;
FRAME_SCALE_LEVEL next_frame_size_selector;
int frame_width[FRAME_SCALE_STEPS];
int frame_height[FRAME_SCALE_STEPS];
int rf_level_maxq[RATE_FACTOR_LEVELS];
} RATE_CONTROL;
struct VP9_COMP;
struct VP9EncoderConfig;
void vp9_rc_init(const struct VP9EncoderConfig *oxcf, int pass,
RATE_CONTROL *rc);
int vp9_estimate_bits_at_q(FRAME_TYPE frame_kind, int q, int mbs,
double correction_factor,
vpx_bit_depth_t bit_depth);
double vp9_convert_qindex_to_q(int qindex, vpx_bit_depth_t bit_depth);
void vp9_rc_init_minq_luts(void);
// Generally at the high level, the following flow is expected
// to be enforced for rate control:
// First call per frame, one of:
// vp9_rc_get_one_pass_vbr_params()
// vp9_rc_get_one_pass_cbr_params()
// vp9_rc_get_svc_params()
// vp9_rc_get_first_pass_params()
// vp9_rc_get_second_pass_params()
// depending on the usage to set the rate control encode parameters desired.
//
// Then, call encode_frame_to_data_rate() to perform the
// actual encode. This function will in turn call encode_frame()
// one or more times, followed by one of:
// vp9_rc_postencode_update()
// vp9_rc_postencode_update_drop_frame()
//
// The majority of rate control parameters are only expected
// to be set in the vp9_rc_get_..._params() functions and
// updated during the vp9_rc_postencode_update...() functions.
// The only exceptions are vp9_rc_drop_frame() and
// vp9_rc_update_rate_correction_factors() functions.
// Functions to set parameters for encoding before the actual
// encode_frame_to_data_rate() function.
void vp9_rc_get_one_pass_vbr_params(struct VP9_COMP *cpi);
void vp9_rc_get_one_pass_cbr_params(struct VP9_COMP *cpi);
void vp9_rc_get_svc_params(struct VP9_COMP *cpi);
// Post encode update of the rate control parameters based
// on bytes used
void vp9_rc_postencode_update(struct VP9_COMP *cpi, uint64_t bytes_used);
// Post encode update of the rate control parameters for dropped frames
void vp9_rc_postencode_update_drop_frame(struct VP9_COMP *cpi);
// Updates rate correction factors
// Changes only the rate correction factors in the rate control structure.
void vp9_rc_update_rate_correction_factors(struct VP9_COMP *cpi);
// Decide if we should drop this frame: For 1-pass CBR.
// Changes only the decimation count in the rate control structure
int vp9_rc_drop_frame(struct VP9_COMP *cpi);
// Computes frame size bounds.
void vp9_rc_compute_frame_size_bounds(const struct VP9_COMP *cpi,
int this_frame_target,
int *frame_under_shoot_limit,
int *frame_over_shoot_limit);
// Picks q and q bounds given the target for bits
int vp9_rc_pick_q_and_bounds(const struct VP9_COMP *cpi,
int *bottom_index,
int *top_index);
// Estimates q to achieve a target bits per frame
int vp9_rc_regulate_q(const struct VP9_COMP *cpi, int target_bits_per_frame,
int active_best_quality, int active_worst_quality);
// Estimates bits per mb for a given qindex and correction factor.
int vp9_rc_bits_per_mb(FRAME_TYPE frame_type, int qindex,
double correction_factor, vpx_bit_depth_t bit_depth);
// Clamping utilities for bitrate targets for iframes and pframes.
int vp9_rc_clamp_iframe_target_size(const struct VP9_COMP *const cpi,
int target);
int vp9_rc_clamp_pframe_target_size(const struct VP9_COMP *const cpi,
int target);
// Utility to set frame_target into the RATE_CONTROL structure
// This function is called only from the vp9_rc_get_..._params() functions.
void vp9_rc_set_frame_target(struct VP9_COMP *cpi, int target);
// Computes a q delta (in "q index" terms) to get from a starting q value
// to a target q value
int vp9_compute_qdelta(const RATE_CONTROL *rc, double qstart, double qtarget,
vpx_bit_depth_t bit_depth);
// Computes a q delta (in "q index" terms) to get from a starting q value
// to a value that should equate to the given rate ratio.
int vp9_compute_qdelta_by_rate(const RATE_CONTROL *rc, FRAME_TYPE frame_type,
int qindex, double rate_target_ratio,
vpx_bit_depth_t bit_depth);
int vp9_frame_type_qdelta(const struct VP9_COMP *cpi, int rf_level, int q);
void vp9_rc_update_framerate(struct VP9_COMP *cpi);
void vp9_rc_set_gf_interval_range(const struct VP9_COMP *const cpi,
RATE_CONTROL *const rc);
void vp9_set_target_rate(struct VP9_COMP *cpi);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // VP9_ENCODER_VP9_RATECTRL_H_

View file

@ -0,0 +1,664 @@
/*
* 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 <assert.h>
#include <math.h>
#include <stdio.h>
#include "./vp9_rtcd.h"
#include "vpx_mem/vpx_mem.h"
#include "vpx_ports/mem.h"
#include "vp9/common/vp9_common.h"
#include "vp9/common/vp9_entropy.h"
#include "vp9/common/vp9_entropymode.h"
#include "vp9/common/vp9_mvref_common.h"
#include "vp9/common/vp9_pred_common.h"
#include "vp9/common/vp9_quant_common.h"
#include "vp9/common/vp9_reconinter.h"
#include "vp9/common/vp9_reconintra.h"
#include "vp9/common/vp9_seg_common.h"
#include "vp9/common/vp9_systemdependent.h"
#include "vp9/encoder/vp9_cost.h"
#include "vp9/encoder/vp9_encodemb.h"
#include "vp9/encoder/vp9_encodemv.h"
#include "vp9/encoder/vp9_encoder.h"
#include "vp9/encoder/vp9_mcomp.h"
#include "vp9/encoder/vp9_quantize.h"
#include "vp9/encoder/vp9_ratectrl.h"
#include "vp9/encoder/vp9_rd.h"
#include "vp9/encoder/vp9_tokenize.h"
#include "vp9/encoder/vp9_variance.h"
#define RD_THRESH_POW 1.25
#define RD_MULT_EPB_RATIO 64
// Factor to weigh the rate for switchable interp filters.
#define SWITCHABLE_INTERP_RATE_FACTOR 1
void vp9_rd_cost_reset(RD_COST *rd_cost) {
rd_cost->rate = INT_MAX;
rd_cost->dist = INT64_MAX;
rd_cost->rdcost = INT64_MAX;
}
void vp9_rd_cost_init(RD_COST *rd_cost) {
rd_cost->rate = 0;
rd_cost->dist = 0;
rd_cost->rdcost = 0;
}
// The baseline rd thresholds for breaking out of the rd loop for
// certain modes are assumed to be based on 8x8 blocks.
// This table is used to correct for block size.
// The factors here are << 2 (2 = x0.5, 32 = x8 etc).
static const uint8_t rd_thresh_block_size_factor[BLOCK_SIZES] = {
2, 3, 3, 4, 6, 6, 8, 12, 12, 16, 24, 24, 32
};
static void fill_mode_costs(VP9_COMP *cpi) {
const FRAME_CONTEXT *const fc = cpi->common.fc;
int i, j;
for (i = 0; i < INTRA_MODES; ++i)
for (j = 0; j < INTRA_MODES; ++j)
vp9_cost_tokens(cpi->y_mode_costs[i][j], vp9_kf_y_mode_prob[i][j],
vp9_intra_mode_tree);
vp9_cost_tokens(cpi->mbmode_cost, fc->y_mode_prob[1], vp9_intra_mode_tree);
vp9_cost_tokens(cpi->intra_uv_mode_cost[KEY_FRAME],
vp9_kf_uv_mode_prob[TM_PRED], vp9_intra_mode_tree);
vp9_cost_tokens(cpi->intra_uv_mode_cost[INTER_FRAME],
fc->uv_mode_prob[TM_PRED], vp9_intra_mode_tree);
for (i = 0; i < SWITCHABLE_FILTER_CONTEXTS; ++i)
vp9_cost_tokens(cpi->switchable_interp_costs[i],
fc->switchable_interp_prob[i], vp9_switchable_interp_tree);
}
static void fill_token_costs(vp9_coeff_cost *c,
vp9_coeff_probs_model (*p)[PLANE_TYPES]) {
int i, j, k, l;
TX_SIZE t;
for (t = TX_4X4; t <= TX_32X32; ++t)
for (i = 0; i < PLANE_TYPES; ++i)
for (j = 0; j < REF_TYPES; ++j)
for (k = 0; k < COEF_BANDS; ++k)
for (l = 0; l < BAND_COEFF_CONTEXTS(k); ++l) {
vp9_prob probs[ENTROPY_NODES];
vp9_model_to_full_probs(p[t][i][j][k][l], probs);
vp9_cost_tokens((int *)c[t][i][j][k][0][l], probs,
vp9_coef_tree);
vp9_cost_tokens_skip((int *)c[t][i][j][k][1][l], probs,
vp9_coef_tree);
assert(c[t][i][j][k][0][l][EOB_TOKEN] ==
c[t][i][j][k][1][l][EOB_TOKEN]);
}
}
// Values are now correlated to quantizer.
static int sad_per_bit16lut_8[QINDEX_RANGE];
static int sad_per_bit4lut_8[QINDEX_RANGE];
#if CONFIG_VP9_HIGHBITDEPTH
static int sad_per_bit16lut_10[QINDEX_RANGE];
static int sad_per_bit4lut_10[QINDEX_RANGE];
static int sad_per_bit16lut_12[QINDEX_RANGE];
static int sad_per_bit4lut_12[QINDEX_RANGE];
#endif
static void init_me_luts_bd(int *bit16lut, int *bit4lut, int range,
vpx_bit_depth_t bit_depth) {
int i;
// Initialize the sad lut tables using a formulaic calculation for now.
// This is to make it easier to resolve the impact of experimental changes
// to the quantizer tables.
for (i = 0; i < range; i++) {
const double q = vp9_convert_qindex_to_q(i, bit_depth);
bit16lut[i] = (int)(0.0418 * q + 2.4107);
bit4lut[i] = (int)(0.063 * q + 2.742);
}
}
void vp9_init_me_luts(void) {
init_me_luts_bd(sad_per_bit16lut_8, sad_per_bit4lut_8, QINDEX_RANGE,
VPX_BITS_8);
#if CONFIG_VP9_HIGHBITDEPTH
init_me_luts_bd(sad_per_bit16lut_10, sad_per_bit4lut_10, QINDEX_RANGE,
VPX_BITS_10);
init_me_luts_bd(sad_per_bit16lut_12, sad_per_bit4lut_12, QINDEX_RANGE,
VPX_BITS_12);
#endif
}
static const int rd_boost_factor[16] = {
64, 32, 32, 32, 24, 16, 12, 12,
8, 8, 4, 4, 2, 2, 1, 0
};
static const int rd_frame_type_factor[FRAME_UPDATE_TYPES] = {
128, 144, 128, 128, 144
};
int vp9_compute_rd_mult(const VP9_COMP *cpi, int qindex) {
const int64_t q = vp9_dc_quant(qindex, 0, cpi->common.bit_depth);
#if CONFIG_VP9_HIGHBITDEPTH
int64_t rdmult = 0;
switch (cpi->common.bit_depth) {
case VPX_BITS_8:
rdmult = 88 * q * q / 24;
break;
case VPX_BITS_10:
rdmult = ROUND_POWER_OF_TWO(88 * q * q / 24, 4);
break;
case VPX_BITS_12:
rdmult = ROUND_POWER_OF_TWO(88 * q * q / 24, 8);
break;
default:
assert(0 && "bit_depth should be VPX_BITS_8, VPX_BITS_10 or VPX_BITS_12");
return -1;
}
#else
int64_t rdmult = 88 * q * q / 24;
#endif // CONFIG_VP9_HIGHBITDEPTH
if (cpi->oxcf.pass == 2 && (cpi->common.frame_type != KEY_FRAME)) {
const GF_GROUP *const gf_group = &cpi->twopass.gf_group;
const FRAME_UPDATE_TYPE frame_type = gf_group->update_type[gf_group->index];
const int boost_index = MIN(15, (cpi->rc.gfu_boost / 100));
rdmult = (rdmult * rd_frame_type_factor[frame_type]) >> 7;
rdmult += ((rdmult * rd_boost_factor[boost_index]) >> 7);
}
return (int)rdmult;
}
static int compute_rd_thresh_factor(int qindex, vpx_bit_depth_t bit_depth) {
double q;
#if CONFIG_VP9_HIGHBITDEPTH
switch (bit_depth) {
case VPX_BITS_8:
q = vp9_dc_quant(qindex, 0, VPX_BITS_8) / 4.0;
break;
case VPX_BITS_10:
q = vp9_dc_quant(qindex, 0, VPX_BITS_10) / 16.0;
break;
case VPX_BITS_12:
q = vp9_dc_quant(qindex, 0, VPX_BITS_12) / 64.0;
break;
default:
assert(0 && "bit_depth should be VPX_BITS_8, VPX_BITS_10 or VPX_BITS_12");
return -1;
}
#else
(void) bit_depth;
q = vp9_dc_quant(qindex, 0, VPX_BITS_8) / 4.0;
#endif // CONFIG_VP9_HIGHBITDEPTH
// TODO(debargha): Adjust the function below.
return MAX((int)(pow(q, RD_THRESH_POW) * 5.12), 8);
}
void vp9_initialize_me_consts(VP9_COMP *cpi, MACROBLOCK *x, int qindex) {
#if CONFIG_VP9_HIGHBITDEPTH
switch (cpi->common.bit_depth) {
case VPX_BITS_8:
x->sadperbit16 = sad_per_bit16lut_8[qindex];
x->sadperbit4 = sad_per_bit4lut_8[qindex];
break;
case VPX_BITS_10:
x->sadperbit16 = sad_per_bit16lut_10[qindex];
x->sadperbit4 = sad_per_bit4lut_10[qindex];
break;
case VPX_BITS_12:
x->sadperbit16 = sad_per_bit16lut_12[qindex];
x->sadperbit4 = sad_per_bit4lut_12[qindex];
break;
default:
assert(0 && "bit_depth should be VPX_BITS_8, VPX_BITS_10 or VPX_BITS_12");
}
#else
(void)cpi;
x->sadperbit16 = sad_per_bit16lut_8[qindex];
x->sadperbit4 = sad_per_bit4lut_8[qindex];
#endif // CONFIG_VP9_HIGHBITDEPTH
}
static void set_block_thresholds(const VP9_COMMON *cm, RD_OPT *rd) {
int i, bsize, segment_id;
for (segment_id = 0; segment_id < MAX_SEGMENTS; ++segment_id) {
const int qindex =
clamp(vp9_get_qindex(&cm->seg, segment_id, cm->base_qindex) +
cm->y_dc_delta_q, 0, MAXQ);
const int q = compute_rd_thresh_factor(qindex, cm->bit_depth);
for (bsize = 0; bsize < BLOCK_SIZES; ++bsize) {
// Threshold here seems unnecessarily harsh but fine given actual
// range of values used for cpi->sf.thresh_mult[].
const int t = q * rd_thresh_block_size_factor[bsize];
const int thresh_max = INT_MAX / t;
if (bsize >= BLOCK_8X8) {
for (i = 0; i < MAX_MODES; ++i)
rd->threshes[segment_id][bsize][i] =
rd->thresh_mult[i] < thresh_max
? rd->thresh_mult[i] * t / 4
: INT_MAX;
} else {
for (i = 0; i < MAX_REFS; ++i)
rd->threshes[segment_id][bsize][i] =
rd->thresh_mult_sub8x8[i] < thresh_max
? rd->thresh_mult_sub8x8[i] * t / 4
: INT_MAX;
}
}
}
}
void vp9_initialize_rd_consts(VP9_COMP *cpi) {
VP9_COMMON *const cm = &cpi->common;
MACROBLOCK *const x = &cpi->td.mb;
RD_OPT *const rd = &cpi->rd;
int i;
vp9_clear_system_state();
rd->RDDIV = RDDIV_BITS; // In bits (to multiply D by 128).
rd->RDMULT = vp9_compute_rd_mult(cpi, cm->base_qindex + cm->y_dc_delta_q);
x->errorperbit = rd->RDMULT / RD_MULT_EPB_RATIO;
x->errorperbit += (x->errorperbit == 0);
x->select_tx_size = (cpi->sf.tx_size_search_method == USE_LARGESTALL &&
cm->frame_type != KEY_FRAME) ? 0 : 1;
set_block_thresholds(cm, rd);
if (!cpi->sf.use_nonrd_pick_mode || cm->frame_type == KEY_FRAME)
fill_token_costs(x->token_costs, cm->fc->coef_probs);
if (cpi->sf.partition_search_type != VAR_BASED_PARTITION ||
cm->frame_type == KEY_FRAME) {
for (i = 0; i < PARTITION_CONTEXTS; ++i)
vp9_cost_tokens(cpi->partition_cost[i], get_partition_probs(cm, i),
vp9_partition_tree);
}
if (!cpi->sf.use_nonrd_pick_mode || (cm->current_video_frame & 0x07) == 1 ||
cm->frame_type == KEY_FRAME) {
fill_mode_costs(cpi);
if (!frame_is_intra_only(cm)) {
vp9_build_nmv_cost_table(x->nmvjointcost,
cm->allow_high_precision_mv ? x->nmvcost_hp
: x->nmvcost,
&cm->fc->nmvc, cm->allow_high_precision_mv);
for (i = 0; i < INTER_MODE_CONTEXTS; ++i)
vp9_cost_tokens((int *)cpi->inter_mode_cost[i],
cm->fc->inter_mode_probs[i], vp9_inter_mode_tree);
}
}
}
static void model_rd_norm(int xsq_q10, int *r_q10, int *d_q10) {
// NOTE: The tables below must be of the same size.
// The functions described below are sampled at the four most significant
// bits of x^2 + 8 / 256.
// Normalized rate:
// This table models the rate for a Laplacian source with given variance
// when quantized with a uniform quantizer with given stepsize. The
// closed form expression is:
// Rn(x) = H(sqrt(r)) + sqrt(r)*[1 + H(r)/(1 - r)],
// where r = exp(-sqrt(2) * x) and x = qpstep / sqrt(variance),
// and H(x) is the binary entropy function.
static const int rate_tab_q10[] = {
65536, 6086, 5574, 5275, 5063, 4899, 4764, 4651,
4553, 4389, 4255, 4142, 4044, 3958, 3881, 3811,
3748, 3635, 3538, 3453, 3376, 3307, 3244, 3186,
3133, 3037, 2952, 2877, 2809, 2747, 2690, 2638,
2589, 2501, 2423, 2353, 2290, 2232, 2179, 2130,
2084, 2001, 1928, 1862, 1802, 1748, 1698, 1651,
1608, 1530, 1460, 1398, 1342, 1290, 1243, 1199,
1159, 1086, 1021, 963, 911, 864, 821, 781,
745, 680, 623, 574, 530, 490, 455, 424,
395, 345, 304, 269, 239, 213, 190, 171,
154, 126, 104, 87, 73, 61, 52, 44,
38, 28, 21, 16, 12, 10, 8, 6,
5, 3, 2, 1, 1, 1, 0, 0,
};
// Normalized distortion:
// This table models the normalized distortion for a Laplacian source
// with given variance when quantized with a uniform quantizer
// with given stepsize. The closed form expression is:
// Dn(x) = 1 - 1/sqrt(2) * x / sinh(x/sqrt(2))
// where x = qpstep / sqrt(variance).
// Note the actual distortion is Dn * variance.
static const int dist_tab_q10[] = {
0, 0, 1, 1, 1, 2, 2, 2,
3, 3, 4, 5, 5, 6, 7, 7,
8, 9, 11, 12, 13, 15, 16, 17,
18, 21, 24, 26, 29, 31, 34, 36,
39, 44, 49, 54, 59, 64, 69, 73,
78, 88, 97, 106, 115, 124, 133, 142,
151, 167, 184, 200, 215, 231, 245, 260,
274, 301, 327, 351, 375, 397, 418, 439,
458, 495, 528, 559, 587, 613, 637, 659,
680, 717, 749, 777, 801, 823, 842, 859,
874, 899, 919, 936, 949, 960, 969, 977,
983, 994, 1001, 1006, 1010, 1013, 1015, 1017,
1018, 1020, 1022, 1022, 1023, 1023, 1023, 1024,
};
static const int xsq_iq_q10[] = {
0, 4, 8, 12, 16, 20, 24, 28,
32, 40, 48, 56, 64, 72, 80, 88,
96, 112, 128, 144, 160, 176, 192, 208,
224, 256, 288, 320, 352, 384, 416, 448,
480, 544, 608, 672, 736, 800, 864, 928,
992, 1120, 1248, 1376, 1504, 1632, 1760, 1888,
2016, 2272, 2528, 2784, 3040, 3296, 3552, 3808,
4064, 4576, 5088, 5600, 6112, 6624, 7136, 7648,
8160, 9184, 10208, 11232, 12256, 13280, 14304, 15328,
16352, 18400, 20448, 22496, 24544, 26592, 28640, 30688,
32736, 36832, 40928, 45024, 49120, 53216, 57312, 61408,
65504, 73696, 81888, 90080, 98272, 106464, 114656, 122848,
131040, 147424, 163808, 180192, 196576, 212960, 229344, 245728,
};
const int tmp = (xsq_q10 >> 2) + 8;
const int k = get_msb(tmp) - 3;
const int xq = (k << 3) + ((tmp >> k) & 0x7);
const int one_q10 = 1 << 10;
const int a_q10 = ((xsq_q10 - xsq_iq_q10[xq]) << 10) >> (2 + k);
const int b_q10 = one_q10 - a_q10;
*r_q10 = (rate_tab_q10[xq] * b_q10 + rate_tab_q10[xq + 1] * a_q10) >> 10;
*d_q10 = (dist_tab_q10[xq] * b_q10 + dist_tab_q10[xq + 1] * a_q10) >> 10;
}
void vp9_model_rd_from_var_lapndz(unsigned int var, unsigned int n_log2,
unsigned int qstep, int *rate,
int64_t *dist) {
// This function models the rate and distortion for a Laplacian
// source with given variance when quantized with a uniform quantizer
// with given stepsize. The closed form expressions are in:
// Hang and Chen, "Source Model for transform video coder and its
// application - Part I: Fundamental Theory", IEEE Trans. Circ.
// Sys. for Video Tech., April 1997.
if (var == 0) {
*rate = 0;
*dist = 0;
} else {
int d_q10, r_q10;
static const uint32_t MAX_XSQ_Q10 = 245727;
const uint64_t xsq_q10_64 =
(((uint64_t)qstep * qstep << (n_log2 + 10)) + (var >> 1)) / var;
const int xsq_q10 = (int)MIN(xsq_q10_64, MAX_XSQ_Q10);
model_rd_norm(xsq_q10, &r_q10, &d_q10);
*rate = ((r_q10 << n_log2) + 2) >> 2;
*dist = (var * (int64_t)d_q10 + 512) >> 10;
}
}
void vp9_get_entropy_contexts(BLOCK_SIZE bsize, TX_SIZE tx_size,
const struct macroblockd_plane *pd,
ENTROPY_CONTEXT t_above[16],
ENTROPY_CONTEXT t_left[16]) {
const BLOCK_SIZE plane_bsize = get_plane_block_size(bsize, pd);
const int num_4x4_w = num_4x4_blocks_wide_lookup[plane_bsize];
const int num_4x4_h = num_4x4_blocks_high_lookup[plane_bsize];
const ENTROPY_CONTEXT *const above = pd->above_context;
const ENTROPY_CONTEXT *const left = pd->left_context;
int i;
switch (tx_size) {
case TX_4X4:
memcpy(t_above, above, sizeof(ENTROPY_CONTEXT) * num_4x4_w);
memcpy(t_left, left, sizeof(ENTROPY_CONTEXT) * num_4x4_h);
break;
case TX_8X8:
for (i = 0; i < num_4x4_w; i += 2)
t_above[i] = !!*(const uint16_t *)&above[i];
for (i = 0; i < num_4x4_h; i += 2)
t_left[i] = !!*(const uint16_t *)&left[i];
break;
case TX_16X16:
for (i = 0; i < num_4x4_w; i += 4)
t_above[i] = !!*(const uint32_t *)&above[i];
for (i = 0; i < num_4x4_h; i += 4)
t_left[i] = !!*(const uint32_t *)&left[i];
break;
case TX_32X32:
for (i = 0; i < num_4x4_w; i += 8)
t_above[i] = !!*(const uint64_t *)&above[i];
for (i = 0; i < num_4x4_h; i += 8)
t_left[i] = !!*(const uint64_t *)&left[i];
break;
default:
assert(0 && "Invalid transform size.");
break;
}
}
void vp9_mv_pred(VP9_COMP *cpi, MACROBLOCK *x,
uint8_t *ref_y_buffer, int ref_y_stride,
int ref_frame, BLOCK_SIZE block_size) {
MACROBLOCKD *xd = &x->e_mbd;
MB_MODE_INFO *mbmi = &xd->mi[0]->mbmi;
int i;
int zero_seen = 0;
int best_index = 0;
int best_sad = INT_MAX;
int this_sad = INT_MAX;
int max_mv = 0;
int near_same_nearest;
uint8_t *src_y_ptr = x->plane[0].src.buf;
uint8_t *ref_y_ptr;
const int num_mv_refs = MAX_MV_REF_CANDIDATES +
(cpi->sf.adaptive_motion_search &&
block_size < x->max_partition_size);
MV pred_mv[3];
pred_mv[0] = mbmi->ref_mvs[ref_frame][0].as_mv;
pred_mv[1] = mbmi->ref_mvs[ref_frame][1].as_mv;
pred_mv[2] = x->pred_mv[ref_frame];
assert(num_mv_refs <= (int)(sizeof(pred_mv) / sizeof(pred_mv[0])));
near_same_nearest =
mbmi->ref_mvs[ref_frame][0].as_int == mbmi->ref_mvs[ref_frame][1].as_int;
// Get the sad for each candidate reference mv.
for (i = 0; i < num_mv_refs; ++i) {
const MV *this_mv = &pred_mv[i];
int fp_row, fp_col;
if (i == 1 && near_same_nearest)
continue;
fp_row = (this_mv->row + 3 + (this_mv->row >= 0)) >> 3;
fp_col = (this_mv->col + 3 + (this_mv->col >= 0)) >> 3;
max_mv = MAX(max_mv, MAX(abs(this_mv->row), abs(this_mv->col)) >> 3);
if (fp_row ==0 && fp_col == 0 && zero_seen)
continue;
zero_seen |= (fp_row ==0 && fp_col == 0);
ref_y_ptr =&ref_y_buffer[ref_y_stride * fp_row + fp_col];
// Find sad for current vector.
this_sad = cpi->fn_ptr[block_size].sdf(src_y_ptr, x->plane[0].src.stride,
ref_y_ptr, ref_y_stride);
// Note if it is the best so far.
if (this_sad < best_sad) {
best_sad = this_sad;
best_index = i;
}
}
// Note the index of the mv that worked best in the reference list.
x->mv_best_ref_index[ref_frame] = best_index;
x->max_mv_context[ref_frame] = max_mv;
x->pred_mv_sad[ref_frame] = best_sad;
}
void vp9_setup_pred_block(const MACROBLOCKD *xd,
struct buf_2d dst[MAX_MB_PLANE],
const YV12_BUFFER_CONFIG *src,
int mi_row, int mi_col,
const struct scale_factors *scale,
const struct scale_factors *scale_uv) {
int i;
dst[0].buf = src->y_buffer;
dst[0].stride = src->y_stride;
dst[1].buf = src->u_buffer;
dst[2].buf = src->v_buffer;
dst[1].stride = dst[2].stride = src->uv_stride;
for (i = 0; i < MAX_MB_PLANE; ++i) {
setup_pred_plane(dst + i, dst[i].buf, dst[i].stride, mi_row, mi_col,
i ? scale_uv : scale,
xd->plane[i].subsampling_x, xd->plane[i].subsampling_y);
}
}
int vp9_raster_block_offset(BLOCK_SIZE plane_bsize,
int raster_block, int stride) {
const int bw = b_width_log2_lookup[plane_bsize];
const int y = 4 * (raster_block >> bw);
const int x = 4 * (raster_block & ((1 << bw) - 1));
return y * stride + x;
}
int16_t* vp9_raster_block_offset_int16(BLOCK_SIZE plane_bsize,
int raster_block, int16_t *base) {
const int stride = 4 * num_4x4_blocks_wide_lookup[plane_bsize];
return base + vp9_raster_block_offset(plane_bsize, raster_block, stride);
}
YV12_BUFFER_CONFIG *vp9_get_scaled_ref_frame(const VP9_COMP *cpi,
int ref_frame) {
const VP9_COMMON *const cm = &cpi->common;
const int scaled_idx = cpi->scaled_ref_idx[ref_frame - 1];
const int ref_idx = get_ref_frame_buf_idx(cpi, ref_frame);
return
(scaled_idx != ref_idx && scaled_idx != INVALID_IDX) ?
&cm->buffer_pool->frame_bufs[scaled_idx].buf : NULL;
}
int vp9_get_switchable_rate(const VP9_COMP *cpi, const MACROBLOCKD *const xd) {
const MB_MODE_INFO *const mbmi = &xd->mi[0]->mbmi;
const int ctx = vp9_get_pred_context_switchable_interp(xd);
return SWITCHABLE_INTERP_RATE_FACTOR *
cpi->switchable_interp_costs[ctx][mbmi->interp_filter];
}
void vp9_set_rd_speed_thresholds(VP9_COMP *cpi) {
int i;
RD_OPT *const rd = &cpi->rd;
SPEED_FEATURES *const sf = &cpi->sf;
// Set baseline threshold values.
for (i = 0; i < MAX_MODES; ++i)
rd->thresh_mult[i] = cpi->oxcf.mode == BEST ? -500 : 0;
if (sf->adaptive_rd_thresh) {
rd->thresh_mult[THR_NEARESTMV] = 300;
rd->thresh_mult[THR_NEARESTG] = 300;
rd->thresh_mult[THR_NEARESTA] = 300;
} else {
rd->thresh_mult[THR_NEARESTMV] = 0;
rd->thresh_mult[THR_NEARESTG] = 0;
rd->thresh_mult[THR_NEARESTA] = 0;
}
rd->thresh_mult[THR_DC] += 1000;
rd->thresh_mult[THR_NEWMV] += 1000;
rd->thresh_mult[THR_NEWA] += 1000;
rd->thresh_mult[THR_NEWG] += 1000;
rd->thresh_mult[THR_NEARMV] += 1000;
rd->thresh_mult[THR_NEARA] += 1000;
rd->thresh_mult[THR_COMP_NEARESTLA] += 1000;
rd->thresh_mult[THR_COMP_NEARESTGA] += 1000;
rd->thresh_mult[THR_TM] += 1000;
rd->thresh_mult[THR_COMP_NEARLA] += 1500;
rd->thresh_mult[THR_COMP_NEWLA] += 2000;
rd->thresh_mult[THR_NEARG] += 1000;
rd->thresh_mult[THR_COMP_NEARGA] += 1500;
rd->thresh_mult[THR_COMP_NEWGA] += 2000;
rd->thresh_mult[THR_ZEROMV] += 2000;
rd->thresh_mult[THR_ZEROG] += 2000;
rd->thresh_mult[THR_ZEROA] += 2000;
rd->thresh_mult[THR_COMP_ZEROLA] += 2500;
rd->thresh_mult[THR_COMP_ZEROGA] += 2500;
rd->thresh_mult[THR_H_PRED] += 2000;
rd->thresh_mult[THR_V_PRED] += 2000;
rd->thresh_mult[THR_D45_PRED ] += 2500;
rd->thresh_mult[THR_D135_PRED] += 2500;
rd->thresh_mult[THR_D117_PRED] += 2500;
rd->thresh_mult[THR_D153_PRED] += 2500;
rd->thresh_mult[THR_D207_PRED] += 2500;
rd->thresh_mult[THR_D63_PRED] += 2500;
}
void vp9_set_rd_speed_thresholds_sub8x8(VP9_COMP *cpi) {
static const int thresh_mult[2][MAX_REFS] =
{{2500, 2500, 2500, 4500, 4500, 2500},
{2000, 2000, 2000, 4000, 4000, 2000}};
RD_OPT *const rd = &cpi->rd;
const int idx = cpi->oxcf.mode == BEST;
memcpy(rd->thresh_mult_sub8x8, thresh_mult[idx], sizeof(thresh_mult[idx]));
}
void vp9_update_rd_thresh_fact(int (*factor_buf)[MAX_MODES], int rd_thresh,
int bsize, int best_mode_index) {
if (rd_thresh > 0) {
const int top_mode = bsize < BLOCK_8X8 ? MAX_REFS : MAX_MODES;
int mode;
for (mode = 0; mode < top_mode; ++mode) {
const BLOCK_SIZE min_size = MAX(bsize - 1, BLOCK_4X4);
const BLOCK_SIZE max_size = MIN(bsize + 2, BLOCK_64X64);
BLOCK_SIZE bs;
for (bs = min_size; bs <= max_size; ++bs) {
int *const fact = &factor_buf[bs][mode];
if (mode == best_mode_index) {
*fact -= (*fact >> 4);
} else {
*fact = MIN(*fact + RD_THRESH_INC,
rd_thresh * RD_THRESH_MAX_FACT);
}
}
}
}
}
int vp9_get_intra_cost_penalty(int qindex, int qdelta,
vpx_bit_depth_t bit_depth) {
const int q = vp9_dc_quant(qindex, qdelta, bit_depth);
#if CONFIG_VP9_HIGHBITDEPTH
switch (bit_depth) {
case VPX_BITS_8:
return 20 * q;
case VPX_BITS_10:
return 5 * q;
case VPX_BITS_12:
return ROUND_POWER_OF_TWO(5 * q, 2);
default:
assert(0 && "bit_depth should be VPX_BITS_8, VPX_BITS_10 or VPX_BITS_12");
return -1;
}
#else
return 20 * q;
#endif // CONFIG_VP9_HIGHBITDEPTH
}

View file

@ -0,0 +1,190 @@
/*
* 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.
*/
#ifndef VP9_ENCODER_VP9_RD_H_
#define VP9_ENCODER_VP9_RD_H_
#include <limits.h>
#include "vp9/common/vp9_blockd.h"
#include "vp9/encoder/vp9_block.h"
#include "vp9/encoder/vp9_context_tree.h"
#ifdef __cplusplus
extern "C" {
#endif
#define RDDIV_BITS 7
#define RDCOST(RM, DM, R, D) \
(((128 + ((int64_t)R) * (RM)) >> 8) + (D << DM))
#define QIDX_SKIP_THRESH 115
#define MV_COST_WEIGHT 108
#define MV_COST_WEIGHT_SUB 120
#define INVALID_MV 0x80008000
#define MAX_MODES 30
#define MAX_REFS 6
#define RD_THRESH_MAX_FACT 64
#define RD_THRESH_INC 1
// This enumerator type needs to be kept aligned with the mode order in
// const MODE_DEFINITION vp9_mode_order[MAX_MODES] used in the rd code.
typedef enum {
THR_NEARESTMV,
THR_NEARESTA,
THR_NEARESTG,
THR_DC,
THR_NEWMV,
THR_NEWA,
THR_NEWG,
THR_NEARMV,
THR_NEARA,
THR_NEARG,
THR_ZEROMV,
THR_ZEROG,
THR_ZEROA,
THR_COMP_NEARESTLA,
THR_COMP_NEARESTGA,
THR_TM,
THR_COMP_NEARLA,
THR_COMP_NEWLA,
THR_COMP_NEARGA,
THR_COMP_NEWGA,
THR_COMP_ZEROLA,
THR_COMP_ZEROGA,
THR_H_PRED,
THR_V_PRED,
THR_D135_PRED,
THR_D207_PRED,
THR_D153_PRED,
THR_D63_PRED,
THR_D117_PRED,
THR_D45_PRED,
} THR_MODES;
typedef enum {
THR_LAST,
THR_GOLD,
THR_ALTR,
THR_COMP_LA,
THR_COMP_GA,
THR_INTRA,
} THR_MODES_SUB8X8;
typedef struct RD_OPT {
// Thresh_mult is used to set a threshold for the rd score. A higher value
// means that we will accept the best mode so far more often. This number
// 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][MAX_MODES];
int64_t prediction_type_threshes[MAX_REF_FRAMES][REFERENCE_MODES];
// TODO(agrange): can this overflow?
int tx_select_threshes[MAX_REF_FRAMES][TX_MODES];
int64_t filter_threshes[MAX_REF_FRAMES][SWITCHABLE_FILTER_CONTEXTS];
int RDMULT;
int RDDIV;
} RD_OPT;
typedef struct RD_COST {
int rate;
int64_t dist;
int64_t rdcost;
} RD_COST;
// Reset the rate distortion cost values to maximum (invalid) value.
void vp9_rd_cost_reset(RD_COST *rd_cost);
// Initialize the rate distortion cost values to zero.
void vp9_rd_cost_init(RD_COST *rd_cost);
struct TileInfo;
struct TileDataEnc;
struct VP9_COMP;
struct macroblock;
int vp9_compute_rd_mult(const struct VP9_COMP *cpi, int qindex);
void vp9_initialize_rd_consts(struct VP9_COMP *cpi);
void vp9_initialize_me_consts(struct VP9_COMP *cpi, MACROBLOCK *x, int qindex);
void vp9_model_rd_from_var_lapndz(unsigned int var, unsigned int n,
unsigned int qstep, int *rate,
int64_t *dist);
int vp9_get_switchable_rate(const struct VP9_COMP *cpi,
const MACROBLOCKD *const xd);
int vp9_raster_block_offset(BLOCK_SIZE plane_bsize,
int raster_block, int stride);
int16_t* vp9_raster_block_offset_int16(BLOCK_SIZE plane_bsize,
int raster_block, int16_t *base);
YV12_BUFFER_CONFIG *vp9_get_scaled_ref_frame(const struct VP9_COMP *cpi,
int ref_frame);
void vp9_init_me_luts(void);
void vp9_get_entropy_contexts(BLOCK_SIZE bsize, TX_SIZE tx_size,
const struct macroblockd_plane *pd,
ENTROPY_CONTEXT t_above[16],
ENTROPY_CONTEXT t_left[16]);
void vp9_set_rd_speed_thresholds(struct VP9_COMP *cpi);
void vp9_set_rd_speed_thresholds_sub8x8(struct VP9_COMP *cpi);
void vp9_update_rd_thresh_fact(int (*fact)[MAX_MODES], int rd_thresh,
int bsize, int best_mode_index);
static INLINE int rd_less_than_thresh(int64_t best_rd, int thresh,
int thresh_fact) {
return best_rd < ((int64_t)thresh * thresh_fact >> 5) || thresh == INT_MAX;
}
void vp9_mv_pred(struct VP9_COMP *cpi, MACROBLOCK *x,
uint8_t *ref_y_buffer, int ref_y_stride,
int ref_frame, BLOCK_SIZE block_size);
void vp9_setup_pred_block(const MACROBLOCKD *xd,
struct buf_2d dst[MAX_MB_PLANE],
const YV12_BUFFER_CONFIG *src,
int mi_row, int mi_col,
const struct scale_factors *scale,
const struct scale_factors *scale_uv);
int vp9_get_intra_cost_penalty(int qindex, int qdelta,
vpx_bit_depth_t bit_depth);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // VP9_ENCODER_VP9_RD_H_

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,68 @@
/*
* 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.
*/
#ifndef VP9_ENCODER_VP9_RDOPT_H_
#define VP9_ENCODER_VP9_RDOPT_H_
#include "vp9/common/vp9_blockd.h"
#include "vp9/encoder/vp9_block.h"
#include "vp9/encoder/vp9_context_tree.h"
#ifdef __cplusplus
extern "C" {
#endif
struct TileInfo;
struct VP9_COMP;
struct macroblock;
struct RD_COST;
void vp9_rd_pick_intra_mode_sb(struct VP9_COMP *cpi, struct macroblock *x,
struct RD_COST *rd_cost, BLOCK_SIZE bsize,
PICK_MODE_CONTEXT *ctx, int64_t best_rd);
unsigned int vp9_get_sby_perpixel_variance(VP9_COMP *cpi,
const struct buf_2d *ref,
BLOCK_SIZE bs);
#if CONFIG_VP9_HIGHBITDEPTH
unsigned int vp9_high_get_sby_perpixel_variance(VP9_COMP *cpi,
const struct buf_2d *ref,
BLOCK_SIZE bs, int bd);
#endif
void vp9_rd_pick_inter_mode_sb(struct VP9_COMP *cpi,
struct TileDataEnc *tile_data,
struct macroblock *x,
int mi_row, int mi_col,
struct RD_COST *rd_cost,
BLOCK_SIZE bsize, PICK_MODE_CONTEXT *ctx,
int64_t best_rd_so_far);
void vp9_rd_pick_inter_mode_sb_seg_skip(struct VP9_COMP *cpi,
struct TileDataEnc *tile_data,
struct macroblock *x,
struct RD_COST *rd_cost,
BLOCK_SIZE bsize,
PICK_MODE_CONTEXT *ctx,
int64_t best_rd_so_far);
void vp9_rd_pick_inter_mode_sub8x8(struct VP9_COMP *cpi,
struct TileDataEnc *tile_data,
struct macroblock *x,
int mi_row, int mi_col,
struct RD_COST *rd_cost,
BLOCK_SIZE bsize, PICK_MODE_CONTEXT *ctx,
int64_t best_rd_so_far);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // VP9_ENCODER_VP9_RDOPT_H_

View file

@ -0,0 +1,925 @@
/*
* Copyright (c) 2014 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 <assert.h>
#include <limits.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "vpx_ports/mem.h"
#include "vp9/common/vp9_common.h"
#include "vp9/encoder/vp9_resize.h"
#define FILTER_BITS 7
#define INTERP_TAPS 8
#define SUBPEL_BITS 5
#define SUBPEL_MASK ((1 << SUBPEL_BITS) - 1)
#define INTERP_PRECISION_BITS 32
typedef int16_t interp_kernel[INTERP_TAPS];
// Filters for interpolation (0.5-band) - note this also filters integer pels.
const interp_kernel vp9_filteredinterp_filters500[(1 << SUBPEL_BITS)] = {
{-3, 0, 35, 64, 35, 0, -3, 0},
{-3, -1, 34, 64, 36, 1, -3, 0},
{-3, -1, 32, 64, 38, 1, -3, 0},
{-2, -2, 31, 63, 39, 2, -3, 0},
{-2, -2, 29, 63, 41, 2, -3, 0},
{-2, -2, 28, 63, 42, 3, -4, 0},
{-2, -3, 27, 63, 43, 4, -4, 0},
{-2, -3, 25, 62, 45, 5, -4, 0},
{-2, -3, 24, 62, 46, 5, -4, 0},
{-2, -3, 23, 61, 47, 6, -4, 0},
{-2, -3, 21, 60, 49, 7, -4, 0},
{-1, -4, 20, 60, 50, 8, -4, -1},
{-1, -4, 19, 59, 51, 9, -4, -1},
{-1, -4, 17, 58, 52, 10, -4, 0},
{-1, -4, 16, 57, 53, 12, -4, -1},
{-1, -4, 15, 56, 54, 13, -4, -1},
{-1, -4, 14, 55, 55, 14, -4, -1},
{-1, -4, 13, 54, 56, 15, -4, -1},
{-1, -4, 12, 53, 57, 16, -4, -1},
{0, -4, 10, 52, 58, 17, -4, -1},
{-1, -4, 9, 51, 59, 19, -4, -1},
{-1, -4, 8, 50, 60, 20, -4, -1},
{0, -4, 7, 49, 60, 21, -3, -2},
{0, -4, 6, 47, 61, 23, -3, -2},
{0, -4, 5, 46, 62, 24, -3, -2},
{0, -4, 5, 45, 62, 25, -3, -2},
{0, -4, 4, 43, 63, 27, -3, -2},
{0, -4, 3, 42, 63, 28, -2, -2},
{0, -3, 2, 41, 63, 29, -2, -2},
{0, -3, 2, 39, 63, 31, -2, -2},
{0, -3, 1, 38, 64, 32, -1, -3},
{0, -3, 1, 36, 64, 34, -1, -3}
};
// Filters for interpolation (0.625-band) - note this also filters integer pels.
const interp_kernel vp9_filteredinterp_filters625[(1 << SUBPEL_BITS)] = {
{-1, -8, 33, 80, 33, -8, -1, 0},
{-1, -8, 30, 80, 35, -8, -1, 1},
{-1, -8, 28, 80, 37, -7, -2, 1},
{0, -8, 26, 79, 39, -7, -2, 1},
{0, -8, 24, 79, 41, -7, -2, 1},
{0, -8, 22, 78, 43, -6, -2, 1},
{0, -8, 20, 78, 45, -5, -3, 1},
{0, -8, 18, 77, 48, -5, -3, 1},
{0, -8, 16, 76, 50, -4, -3, 1},
{0, -8, 15, 75, 52, -3, -4, 1},
{0, -7, 13, 74, 54, -3, -4, 1},
{0, -7, 11, 73, 56, -2, -4, 1},
{0, -7, 10, 71, 58, -1, -4, 1},
{1, -7, 8, 70, 60, 0, -5, 1},
{1, -6, 6, 68, 62, 1, -5, 1},
{1, -6, 5, 67, 63, 2, -5, 1},
{1, -6, 4, 65, 65, 4, -6, 1},
{1, -5, 2, 63, 67, 5, -6, 1},
{1, -5, 1, 62, 68, 6, -6, 1},
{1, -5, 0, 60, 70, 8, -7, 1},
{1, -4, -1, 58, 71, 10, -7, 0},
{1, -4, -2, 56, 73, 11, -7, 0},
{1, -4, -3, 54, 74, 13, -7, 0},
{1, -4, -3, 52, 75, 15, -8, 0},
{1, -3, -4, 50, 76, 16, -8, 0},
{1, -3, -5, 48, 77, 18, -8, 0},
{1, -3, -5, 45, 78, 20, -8, 0},
{1, -2, -6, 43, 78, 22, -8, 0},
{1, -2, -7, 41, 79, 24, -8, 0},
{1, -2, -7, 39, 79, 26, -8, 0},
{1, -2, -7, 37, 80, 28, -8, -1},
{1, -1, -8, 35, 80, 30, -8, -1},
};
// Filters for interpolation (0.75-band) - note this also filters integer pels.
const interp_kernel vp9_filteredinterp_filters750[(1 << SUBPEL_BITS)] = {
{2, -11, 25, 96, 25, -11, 2, 0},
{2, -11, 22, 96, 28, -11, 2, 0},
{2, -10, 19, 95, 31, -11, 2, 0},
{2, -10, 17, 95, 34, -12, 2, 0},
{2, -9, 14, 94, 37, -12, 2, 0},
{2, -8, 12, 93, 40, -12, 1, 0},
{2, -8, 9, 92, 43, -12, 1, 1},
{2, -7, 7, 91, 46, -12, 1, 0},
{2, -7, 5, 90, 49, -12, 1, 0},
{2, -6, 3, 88, 52, -12, 0, 1},
{2, -5, 1, 86, 55, -12, 0, 1},
{2, -5, -1, 84, 58, -11, 0, 1},
{2, -4, -2, 82, 61, -11, -1, 1},
{2, -4, -4, 80, 64, -10, -1, 1},
{1, -3, -5, 77, 67, -9, -1, 1},
{1, -3, -6, 75, 70, -8, -2, 1},
{1, -2, -7, 72, 72, -7, -2, 1},
{1, -2, -8, 70, 75, -6, -3, 1},
{1, -1, -9, 67, 77, -5, -3, 1},
{1, -1, -10, 64, 80, -4, -4, 2},
{1, -1, -11, 61, 82, -2, -4, 2},
{1, 0, -11, 58, 84, -1, -5, 2},
{1, 0, -12, 55, 86, 1, -5, 2},
{1, 0, -12, 52, 88, 3, -6, 2},
{0, 1, -12, 49, 90, 5, -7, 2},
{0, 1, -12, 46, 91, 7, -7, 2},
{1, 1, -12, 43, 92, 9, -8, 2},
{0, 1, -12, 40, 93, 12, -8, 2},
{0, 2, -12, 37, 94, 14, -9, 2},
{0, 2, -12, 34, 95, 17, -10, 2},
{0, 2, -11, 31, 95, 19, -10, 2},
{0, 2, -11, 28, 96, 22, -11, 2}
};
// Filters for interpolation (0.875-band) - note this also filters integer pels.
const interp_kernel vp9_filteredinterp_filters875[(1 << SUBPEL_BITS)] = {
{3, -8, 13, 112, 13, -8, 3, 0},
{3, -7, 10, 112, 17, -9, 3, -1},
{2, -6, 7, 111, 21, -9, 3, -1},
{2, -5, 4, 111, 24, -10, 3, -1},
{2, -4, 1, 110, 28, -11, 3, -1},
{1, -3, -1, 108, 32, -12, 4, -1},
{1, -2, -3, 106, 36, -13, 4, -1},
{1, -1, -6, 105, 40, -14, 4, -1},
{1, -1, -7, 102, 44, -14, 4, -1},
{1, 0, -9, 100, 48, -15, 4, -1},
{1, 1, -11, 97, 53, -16, 4, -1},
{0, 1, -12, 95, 57, -16, 4, -1},
{0, 2, -13, 91, 61, -16, 4, -1},
{0, 2, -14, 88, 65, -16, 4, -1},
{0, 3, -15, 84, 69, -17, 4, 0},
{0, 3, -16, 81, 73, -16, 3, 0},
{0, 3, -16, 77, 77, -16, 3, 0},
{0, 3, -16, 73, 81, -16, 3, 0},
{0, 4, -17, 69, 84, -15, 3, 0},
{-1, 4, -16, 65, 88, -14, 2, 0},
{-1, 4, -16, 61, 91, -13, 2, 0},
{-1, 4, -16, 57, 95, -12, 1, 0},
{-1, 4, -16, 53, 97, -11, 1, 1},
{-1, 4, -15, 48, 100, -9, 0, 1},
{-1, 4, -14, 44, 102, -7, -1, 1},
{-1, 4, -14, 40, 105, -6, -1, 1},
{-1, 4, -13, 36, 106, -3, -2, 1},
{-1, 4, -12, 32, 108, -1, -3, 1},
{-1, 3, -11, 28, 110, 1, -4, 2},
{-1, 3, -10, 24, 111, 4, -5, 2},
{-1, 3, -9, 21, 111, 7, -6, 2},
{-1, 3, -9, 17, 112, 10, -7, 3}
};
// Filters for interpolation (full-band) - no filtering for integer pixels
const interp_kernel vp9_filteredinterp_filters1000[(1 << SUBPEL_BITS)] = {
{0, 0, 0, 128, 0, 0, 0, 0},
{0, 1, -3, 128, 3, -1, 0, 0},
{-1, 2, -6, 127, 7, -2, 1, 0},
{-1, 3, -9, 126, 12, -4, 1, 0},
{-1, 4, -12, 125, 16, -5, 1, 0},
{-1, 4, -14, 123, 20, -6, 2, 0},
{-1, 5, -15, 120, 25, -8, 2, 0},
{-1, 5, -17, 118, 30, -9, 3, -1},
{-1, 6, -18, 114, 35, -10, 3, -1},
{-1, 6, -19, 111, 41, -12, 3, -1},
{-1, 6, -20, 107, 46, -13, 4, -1},
{-1, 6, -21, 103, 52, -14, 4, -1},
{-1, 6, -21, 99, 57, -16, 5, -1},
{-1, 6, -21, 94, 63, -17, 5, -1},
{-1, 6, -20, 89, 68, -18, 5, -1},
{-1, 6, -20, 84, 73, -19, 6, -1},
{-1, 6, -20, 79, 79, -20, 6, -1},
{-1, 6, -19, 73, 84, -20, 6, -1},
{-1, 5, -18, 68, 89, -20, 6, -1},
{-1, 5, -17, 63, 94, -21, 6, -1},
{-1, 5, -16, 57, 99, -21, 6, -1},
{-1, 4, -14, 52, 103, -21, 6, -1},
{-1, 4, -13, 46, 107, -20, 6, -1},
{-1, 3, -12, 41, 111, -19, 6, -1},
{-1, 3, -10, 35, 114, -18, 6, -1},
{-1, 3, -9, 30, 118, -17, 5, -1},
{0, 2, -8, 25, 120, -15, 5, -1},
{0, 2, -6, 20, 123, -14, 4, -1},
{0, 1, -5, 16, 125, -12, 4, -1},
{0, 1, -4, 12, 126, -9, 3, -1},
{0, 1, -2, 7, 127, -6, 2, -1},
{0, 0, -1, 3, 128, -3, 1, 0}
};
// Filters for factor of 2 downsampling.
static const int16_t vp9_down2_symeven_half_filter[] = {56, 12, -3, -1};
static const int16_t vp9_down2_symodd_half_filter[] = {64, 35, 0, -3};
static const interp_kernel *choose_interp_filter(int inlength, int outlength) {
int outlength16 = outlength * 16;
if (outlength16 >= inlength * 16)
return vp9_filteredinterp_filters1000;
else if (outlength16 >= inlength * 13)
return vp9_filteredinterp_filters875;
else if (outlength16 >= inlength * 11)
return vp9_filteredinterp_filters750;
else if (outlength16 >= inlength * 9)
return vp9_filteredinterp_filters625;
else
return vp9_filteredinterp_filters500;
}
static void interpolate(const uint8_t *const input, int inlength,
uint8_t *output, int outlength) {
const int64_t delta = (((uint64_t)inlength << 32) + outlength / 2) /
outlength;
const int64_t offset = inlength > outlength ?
(((int64_t)(inlength - outlength) << 31) + outlength / 2) / outlength :
-(((int64_t)(outlength - inlength) << 31) + outlength / 2) / outlength;
uint8_t *optr = output;
int x, x1, x2, sum, k, int_pel, sub_pel;
int64_t y;
const interp_kernel *interp_filters =
choose_interp_filter(inlength, outlength);
x = 0;
y = offset;
while ((y >> INTERP_PRECISION_BITS) < (INTERP_TAPS / 2 - 1)) {
x++;
y += delta;
}
x1 = x;
x = outlength - 1;
y = delta * x + offset;
while ((y >> INTERP_PRECISION_BITS) +
(int64_t)(INTERP_TAPS / 2) >= inlength) {
x--;
y -= delta;
}
x2 = x;
if (x1 > x2) {
for (x = 0, y = offset; x < outlength; ++x, y += delta) {
const int16_t *filter;
int_pel = y >> INTERP_PRECISION_BITS;
sub_pel = (y >> (INTERP_PRECISION_BITS - SUBPEL_BITS)) & SUBPEL_MASK;
filter = interp_filters[sub_pel];
sum = 0;
for (k = 0; k < INTERP_TAPS; ++k) {
const int pk = int_pel - INTERP_TAPS / 2 + 1 + k;
sum += filter[k] * input[(pk < 0 ? 0 :
(pk >= inlength ? inlength - 1 : pk))];
}
*optr++ = clip_pixel(ROUND_POWER_OF_TWO(sum, FILTER_BITS));
}
} else {
// Initial part.
for (x = 0, y = offset; x < x1; ++x, y += delta) {
const int16_t *filter;
int_pel = y >> INTERP_PRECISION_BITS;
sub_pel = (y >> (INTERP_PRECISION_BITS - SUBPEL_BITS)) & SUBPEL_MASK;
filter = interp_filters[sub_pel];
sum = 0;
for (k = 0; k < INTERP_TAPS; ++k)
sum += filter[k] * input[(int_pel - INTERP_TAPS / 2 + 1 + k < 0 ?
0 :
int_pel - INTERP_TAPS / 2 + 1 + k)];
*optr++ = clip_pixel(ROUND_POWER_OF_TWO(sum, FILTER_BITS));
}
// Middle part.
for (; x <= x2; ++x, y += delta) {
const int16_t *filter;
int_pel = y >> INTERP_PRECISION_BITS;
sub_pel = (y >> (INTERP_PRECISION_BITS - SUBPEL_BITS)) & SUBPEL_MASK;
filter = interp_filters[sub_pel];
sum = 0;
for (k = 0; k < INTERP_TAPS; ++k)
sum += filter[k] * input[int_pel - INTERP_TAPS / 2 + 1 + k];
*optr++ = clip_pixel(ROUND_POWER_OF_TWO(sum, FILTER_BITS));
}
// End part.
for (; x < outlength; ++x, y += delta) {
const int16_t *filter;
int_pel = y >> INTERP_PRECISION_BITS;
sub_pel = (y >> (INTERP_PRECISION_BITS - SUBPEL_BITS)) & SUBPEL_MASK;
filter = interp_filters[sub_pel];
sum = 0;
for (k = 0; k < INTERP_TAPS; ++k)
sum += filter[k] * input[(int_pel - INTERP_TAPS / 2 + 1 + k >=
inlength ? inlength - 1 :
int_pel - INTERP_TAPS / 2 + 1 + k)];
*optr++ = clip_pixel(ROUND_POWER_OF_TWO(sum, FILTER_BITS));
}
}
}
static void down2_symeven(const uint8_t *const input, int length,
uint8_t *output) {
// Actual filter len = 2 * filter_len_half.
const int16_t *filter = vp9_down2_symeven_half_filter;
const int filter_len_half = sizeof(vp9_down2_symeven_half_filter) / 2;
int i, j;
uint8_t *optr = output;
int l1 = filter_len_half;
int l2 = (length - filter_len_half);
l1 += (l1 & 1);
l2 += (l2 & 1);
if (l1 > l2) {
// Short input length.
for (i = 0; i < length; i += 2) {
int sum = (1 << (FILTER_BITS - 1));
for (j = 0; j < filter_len_half; ++j) {
sum += (input[(i - j < 0 ? 0 : i - j)] +
input[(i + 1 + j >= length ? length - 1 : i + 1 + j)]) *
filter[j];
}
sum >>= FILTER_BITS;
*optr++ = clip_pixel(sum);
}
} else {
// Initial part.
for (i = 0; i < l1; i += 2) {
int sum = (1 << (FILTER_BITS - 1));
for (j = 0; j < filter_len_half; ++j) {
sum += (input[(i - j < 0 ? 0 : i - j)] + input[i + 1 + j]) * filter[j];
}
sum >>= FILTER_BITS;
*optr++ = clip_pixel(sum);
}
// Middle part.
for (; i < l2; i += 2) {
int sum = (1 << (FILTER_BITS - 1));
for (j = 0; j < filter_len_half; ++j) {
sum += (input[i - j] + input[i + 1 + j]) * filter[j];
}
sum >>= FILTER_BITS;
*optr++ = clip_pixel(sum);
}
// End part.
for (; i < length; i += 2) {
int sum = (1 << (FILTER_BITS - 1));
for (j = 0; j < filter_len_half; ++j) {
sum += (input[i - j] +
input[(i + 1 + j >= length ? length - 1 : i + 1 + j)]) *
filter[j];
}
sum >>= FILTER_BITS;
*optr++ = clip_pixel(sum);
}
}
}
static void down2_symodd(const uint8_t *const input, int length,
uint8_t *output) {
// Actual filter len = 2 * filter_len_half - 1.
const int16_t *filter = vp9_down2_symodd_half_filter;
const int filter_len_half = sizeof(vp9_down2_symodd_half_filter) / 2;
int i, j;
uint8_t *optr = output;
int l1 = filter_len_half - 1;
int l2 = (length - filter_len_half + 1);
l1 += (l1 & 1);
l2 += (l2 & 1);
if (l1 > l2) {
// Short input length.
for (i = 0; i < length; i += 2) {
int sum = (1 << (FILTER_BITS - 1)) + input[i] * filter[0];
for (j = 1; j < filter_len_half; ++j) {
sum += (input[(i - j < 0 ? 0 : i - j)] +
input[(i + j >= length ? length - 1 : i + j)]) *
filter[j];
}
sum >>= FILTER_BITS;
*optr++ = clip_pixel(sum);
}
} else {
// Initial part.
for (i = 0; i < l1; i += 2) {
int sum = (1 << (FILTER_BITS - 1)) + input[i] * filter[0];
for (j = 1; j < filter_len_half; ++j) {
sum += (input[(i - j < 0 ? 0 : i - j)] + input[i + j]) * filter[j];
}
sum >>= FILTER_BITS;
*optr++ = clip_pixel(sum);
}
// Middle part.
for (; i < l2; i += 2) {
int sum = (1 << (FILTER_BITS - 1)) + input[i] * filter[0];
for (j = 1; j < filter_len_half; ++j) {
sum += (input[i - j] + input[i + j]) * filter[j];
}
sum >>= FILTER_BITS;
*optr++ = clip_pixel(sum);
}
// End part.
for (; i < length; i += 2) {
int sum = (1 << (FILTER_BITS - 1)) + input[i] * filter[0];
for (j = 1; j < filter_len_half; ++j) {
sum += (input[i - j] + input[(i + j >= length ? length - 1 : i + j)]) *
filter[j];
}
sum >>= FILTER_BITS;
*optr++ = clip_pixel(sum);
}
}
}
static int get_down2_length(int length, int steps) {
int s;
for (s = 0; s < steps; ++s)
length = (length + 1) >> 1;
return length;
}
static int get_down2_steps(int in_length, int out_length) {
int steps = 0;
int proj_in_length;
while ((proj_in_length = get_down2_length(in_length, 1)) >= out_length) {
++steps;
in_length = proj_in_length;
}
return steps;
}
static void resize_multistep(const uint8_t *const input,
int length,
uint8_t *output,
int olength,
uint8_t *buf) {
int steps;
if (length == olength) {
memcpy(output, input, sizeof(uint8_t) * length);
return;
}
steps = get_down2_steps(length, olength);
if (steps > 0) {
int s;
uint8_t *out = NULL;
uint8_t *tmpbuf = NULL;
uint8_t *otmp, *otmp2;
int filteredlength = length;
if (!tmpbuf) {
tmpbuf = (uint8_t *)malloc(sizeof(uint8_t) * length);
otmp = tmpbuf;
} else {
otmp = buf;
}
otmp2 = otmp + get_down2_length(length, 1);
for (s = 0; s < steps; ++s) {
const int proj_filteredlength = get_down2_length(filteredlength, 1);
const uint8_t *const in = (s == 0 ? input : out);
if (s == steps - 1 && proj_filteredlength == olength)
out = output;
else
out = (s & 1 ? otmp2 : otmp);
if (filteredlength & 1)
down2_symodd(in, filteredlength, out);
else
down2_symeven(in, filteredlength, out);
filteredlength = proj_filteredlength;
}
if (filteredlength != olength) {
interpolate(out, filteredlength, output, olength);
}
if (tmpbuf)
free(tmpbuf);
} else {
interpolate(input, length, output, olength);
}
}
static void fill_col_to_arr(uint8_t *img, int stride, int len, uint8_t *arr) {
int i;
uint8_t *iptr = img;
uint8_t *aptr = arr;
for (i = 0; i < len; ++i, iptr += stride) {
*aptr++ = *iptr;
}
}
static void fill_arr_to_col(uint8_t *img, int stride, int len, uint8_t *arr) {
int i;
uint8_t *iptr = img;
uint8_t *aptr = arr;
for (i = 0; i < len; ++i, iptr += stride) {
*iptr = *aptr++;
}
}
void vp9_resize_plane(const uint8_t *const input,
int height,
int width,
int in_stride,
uint8_t *output,
int height2,
int width2,
int out_stride) {
int i;
uint8_t *intbuf = (uint8_t *)malloc(sizeof(uint8_t) * width2 * height);
uint8_t *tmpbuf = (uint8_t *)malloc(sizeof(uint8_t) *
(width < height ? height : width));
uint8_t *arrbuf = (uint8_t *)malloc(sizeof(uint8_t) * (height + height2));
assert(width > 0);
assert(height > 0);
assert(width2 > 0);
assert(height2 > 0);
for (i = 0; i < height; ++i)
resize_multistep(input + in_stride * i, width,
intbuf + width2 * i, width2, tmpbuf);
for (i = 0; i < width2; ++i) {
fill_col_to_arr(intbuf + i, width2, height, arrbuf);
resize_multistep(arrbuf, height, arrbuf + height, height2, tmpbuf);
fill_arr_to_col(output + i, out_stride, height2, arrbuf + height);
}
free(intbuf);
free(tmpbuf);
free(arrbuf);
}
#if CONFIG_VP9_HIGHBITDEPTH
static void highbd_interpolate(const uint16_t *const input, int inlength,
uint16_t *output, int outlength, int bd) {
const int64_t delta =
(((uint64_t)inlength << 32) + outlength / 2) / outlength;
const int64_t offset = inlength > outlength ?
(((int64_t)(inlength - outlength) << 31) + outlength / 2) / outlength :
-(((int64_t)(outlength - inlength) << 31) + outlength / 2) / outlength;
uint16_t *optr = output;
int x, x1, x2, sum, k, int_pel, sub_pel;
int64_t y;
const interp_kernel *interp_filters =
choose_interp_filter(inlength, outlength);
x = 0;
y = offset;
while ((y >> INTERP_PRECISION_BITS) < (INTERP_TAPS / 2 - 1)) {
x++;
y += delta;
}
x1 = x;
x = outlength - 1;
y = delta * x + offset;
while ((y >> INTERP_PRECISION_BITS) +
(int64_t)(INTERP_TAPS / 2) >= inlength) {
x--;
y -= delta;
}
x2 = x;
if (x1 > x2) {
for (x = 0, y = offset; x < outlength; ++x, y += delta) {
const int16_t *filter;
int_pel = y >> INTERP_PRECISION_BITS;
sub_pel = (y >> (INTERP_PRECISION_BITS - SUBPEL_BITS)) & SUBPEL_MASK;
filter = interp_filters[sub_pel];
sum = 0;
for (k = 0; k < INTERP_TAPS; ++k) {
const int pk = int_pel - INTERP_TAPS / 2 + 1 + k;
sum += filter[k] *
input[(pk < 0 ? 0 : (pk >= inlength ? inlength - 1 : pk))];
}
*optr++ = clip_pixel_highbd(ROUND_POWER_OF_TWO(sum, FILTER_BITS), bd);
}
} else {
// Initial part.
for (x = 0, y = offset; x < x1; ++x, y += delta) {
const int16_t *filter;
int_pel = y >> INTERP_PRECISION_BITS;
sub_pel = (y >> (INTERP_PRECISION_BITS - SUBPEL_BITS)) & SUBPEL_MASK;
filter = interp_filters[sub_pel];
sum = 0;
for (k = 0; k < INTERP_TAPS; ++k)
sum += filter[k] *
input[(int_pel - INTERP_TAPS / 2 + 1 + k < 0 ?
0 : int_pel - INTERP_TAPS / 2 + 1 + k)];
*optr++ = clip_pixel_highbd(ROUND_POWER_OF_TWO(sum, FILTER_BITS), bd);
}
// Middle part.
for (; x <= x2; ++x, y += delta) {
const int16_t *filter;
int_pel = y >> INTERP_PRECISION_BITS;
sub_pel = (y >> (INTERP_PRECISION_BITS - SUBPEL_BITS)) & SUBPEL_MASK;
filter = interp_filters[sub_pel];
sum = 0;
for (k = 0; k < INTERP_TAPS; ++k)
sum += filter[k] * input[int_pel - INTERP_TAPS / 2 + 1 + k];
*optr++ = clip_pixel_highbd(ROUND_POWER_OF_TWO(sum, FILTER_BITS), bd);
}
// End part.
for (; x < outlength; ++x, y += delta) {
const int16_t *filter;
int_pel = y >> INTERP_PRECISION_BITS;
sub_pel = (y >> (INTERP_PRECISION_BITS - SUBPEL_BITS)) & SUBPEL_MASK;
filter = interp_filters[sub_pel];
sum = 0;
for (k = 0; k < INTERP_TAPS; ++k)
sum += filter[k] * input[(int_pel - INTERP_TAPS / 2 + 1 + k >=
inlength ? inlength - 1 :
int_pel - INTERP_TAPS / 2 + 1 + k)];
*optr++ = clip_pixel_highbd(ROUND_POWER_OF_TWO(sum, FILTER_BITS), bd);
}
}
}
static void highbd_down2_symeven(const uint16_t *const input, int length,
uint16_t *output, int bd) {
// Actual filter len = 2 * filter_len_half.
static const int16_t *filter = vp9_down2_symeven_half_filter;
const int filter_len_half = sizeof(vp9_down2_symeven_half_filter) / 2;
int i, j;
uint16_t *optr = output;
int l1 = filter_len_half;
int l2 = (length - filter_len_half);
l1 += (l1 & 1);
l2 += (l2 & 1);
if (l1 > l2) {
// Short input length.
for (i = 0; i < length; i += 2) {
int sum = (1 << (FILTER_BITS - 1));
for (j = 0; j < filter_len_half; ++j) {
sum += (input[(i - j < 0 ? 0 : i - j)] +
input[(i + 1 + j >= length ? length - 1 : i + 1 + j)]) *
filter[j];
}
sum >>= FILTER_BITS;
*optr++ = clip_pixel_highbd(sum, bd);
}
} else {
// Initial part.
for (i = 0; i < l1; i += 2) {
int sum = (1 << (FILTER_BITS - 1));
for (j = 0; j < filter_len_half; ++j) {
sum += (input[(i - j < 0 ? 0 : i - j)] + input[i + 1 + j]) * filter[j];
}
sum >>= FILTER_BITS;
*optr++ = clip_pixel_highbd(sum, bd);
}
// Middle part.
for (; i < l2; i += 2) {
int sum = (1 << (FILTER_BITS - 1));
for (j = 0; j < filter_len_half; ++j) {
sum += (input[i - j] + input[i + 1 + j]) * filter[j];
}
sum >>= FILTER_BITS;
*optr++ = clip_pixel_highbd(sum, bd);
}
// End part.
for (; i < length; i += 2) {
int sum = (1 << (FILTER_BITS - 1));
for (j = 0; j < filter_len_half; ++j) {
sum += (input[i - j] +
input[(i + 1 + j >= length ? length - 1 : i + 1 + j)]) *
filter[j];
}
sum >>= FILTER_BITS;
*optr++ = clip_pixel_highbd(sum, bd);
}
}
}
static void highbd_down2_symodd(const uint16_t *const input, int length,
uint16_t *output, int bd) {
// Actual filter len = 2 * filter_len_half - 1.
static const int16_t *filter = vp9_down2_symodd_half_filter;
const int filter_len_half = sizeof(vp9_down2_symodd_half_filter) / 2;
int i, j;
uint16_t *optr = output;
int l1 = filter_len_half - 1;
int l2 = (length - filter_len_half + 1);
l1 += (l1 & 1);
l2 += (l2 & 1);
if (l1 > l2) {
// Short input length.
for (i = 0; i < length; i += 2) {
int sum = (1 << (FILTER_BITS - 1)) + input[i] * filter[0];
for (j = 1; j < filter_len_half; ++j) {
sum += (input[(i - j < 0 ? 0 : i - j)] +
input[(i + j >= length ? length - 1 : i + j)]) *
filter[j];
}
sum >>= FILTER_BITS;
*optr++ = clip_pixel_highbd(sum, bd);
}
} else {
// Initial part.
for (i = 0; i < l1; i += 2) {
int sum = (1 << (FILTER_BITS - 1)) + input[i] * filter[0];
for (j = 1; j < filter_len_half; ++j) {
sum += (input[(i - j < 0 ? 0 : i - j)] + input[i + j]) * filter[j];
}
sum >>= FILTER_BITS;
*optr++ = clip_pixel_highbd(sum, bd);
}
// Middle part.
for (; i < l2; i += 2) {
int sum = (1 << (FILTER_BITS - 1)) + input[i] * filter[0];
for (j = 1; j < filter_len_half; ++j) {
sum += (input[i - j] + input[i + j]) * filter[j];
}
sum >>= FILTER_BITS;
*optr++ = clip_pixel_highbd(sum, bd);
}
// End part.
for (; i < length; i += 2) {
int sum = (1 << (FILTER_BITS - 1)) + input[i] * filter[0];
for (j = 1; j < filter_len_half; ++j) {
sum += (input[i - j] + input[(i + j >= length ? length - 1 : i + j)]) *
filter[j];
}
sum >>= FILTER_BITS;
*optr++ = clip_pixel_highbd(sum, bd);
}
}
}
static void highbd_resize_multistep(const uint16_t *const input,
int length,
uint16_t *output,
int olength,
uint16_t *buf,
int bd) {
int steps;
if (length == olength) {
memcpy(output, input, sizeof(uint16_t) * length);
return;
}
steps = get_down2_steps(length, olength);
if (steps > 0) {
int s;
uint16_t *out = NULL;
uint16_t *tmpbuf = NULL;
uint16_t *otmp, *otmp2;
int filteredlength = length;
if (!tmpbuf) {
tmpbuf = (uint16_t *)malloc(sizeof(uint16_t) * length);
otmp = tmpbuf;
} else {
otmp = buf;
}
otmp2 = otmp + get_down2_length(length, 1);
for (s = 0; s < steps; ++s) {
const int proj_filteredlength = get_down2_length(filteredlength, 1);
const uint16_t *const in = (s == 0 ? input : out);
if (s == steps - 1 && proj_filteredlength == olength)
out = output;
else
out = (s & 1 ? otmp2 : otmp);
if (filteredlength & 1)
highbd_down2_symodd(in, filteredlength, out, bd);
else
highbd_down2_symeven(in, filteredlength, out, bd);
filteredlength = proj_filteredlength;
}
if (filteredlength != olength) {
highbd_interpolate(out, filteredlength, output, olength, bd);
}
if (tmpbuf)
free(tmpbuf);
} else {
highbd_interpolate(input, length, output, olength, bd);
}
}
static void highbd_fill_col_to_arr(uint16_t *img, int stride, int len,
uint16_t *arr) {
int i;
uint16_t *iptr = img;
uint16_t *aptr = arr;
for (i = 0; i < len; ++i, iptr += stride) {
*aptr++ = *iptr;
}
}
static void highbd_fill_arr_to_col(uint16_t *img, int stride, int len,
uint16_t *arr) {
int i;
uint16_t *iptr = img;
uint16_t *aptr = arr;
for (i = 0; i < len; ++i, iptr += stride) {
*iptr = *aptr++;
}
}
void vp9_highbd_resize_plane(const uint8_t *const input,
int height,
int width,
int in_stride,
uint8_t *output,
int height2,
int width2,
int out_stride,
int bd) {
int i;
uint16_t *intbuf = (uint16_t *)malloc(sizeof(uint16_t) * width2 * height);
uint16_t *tmpbuf = (uint16_t *)malloc(sizeof(uint16_t) *
(width < height ? height : width));
uint16_t *arrbuf = (uint16_t *)malloc(sizeof(uint16_t) * (height + height2));
for (i = 0; i < height; ++i) {
highbd_resize_multistep(CONVERT_TO_SHORTPTR(input + in_stride * i), width,
intbuf + width2 * i, width2, tmpbuf, bd);
}
for (i = 0; i < width2; ++i) {
highbd_fill_col_to_arr(intbuf + i, width2, height, arrbuf);
highbd_resize_multistep(arrbuf, height, arrbuf + height, height2, tmpbuf,
bd);
highbd_fill_arr_to_col(CONVERT_TO_SHORTPTR(output + i), out_stride, height2,
arrbuf + height);
}
free(intbuf);
free(tmpbuf);
free(arrbuf);
}
#endif // CONFIG_VP9_HIGHBITDEPTH
void vp9_resize_frame420(const uint8_t *const y,
int y_stride,
const uint8_t *const u, const uint8_t *const v,
int uv_stride,
int height, int width,
uint8_t *oy, int oy_stride,
uint8_t *ou, uint8_t *ov, int ouv_stride,
int oheight, int owidth) {
vp9_resize_plane(y, height, width, y_stride,
oy, oheight, owidth, oy_stride);
vp9_resize_plane(u, height / 2, width / 2, uv_stride,
ou, oheight / 2, owidth / 2, ouv_stride);
vp9_resize_plane(v, height / 2, width / 2, uv_stride,
ov, oheight / 2, owidth / 2, ouv_stride);
}
void vp9_resize_frame422(const uint8_t *const y, int y_stride,
const uint8_t *const u, const uint8_t *const v,
int uv_stride,
int height, int width,
uint8_t *oy, int oy_stride,
uint8_t *ou, uint8_t *ov, int ouv_stride,
int oheight, int owidth) {
vp9_resize_plane(y, height, width, y_stride,
oy, oheight, owidth, oy_stride);
vp9_resize_plane(u, height, width / 2, uv_stride,
ou, oheight, owidth / 2, ouv_stride);
vp9_resize_plane(v, height, width / 2, uv_stride,
ov, oheight, owidth / 2, ouv_stride);
}
void vp9_resize_frame444(const uint8_t *const y, int y_stride,
const uint8_t *const u, const uint8_t *const v,
int uv_stride,
int height, int width,
uint8_t *oy, int oy_stride,
uint8_t *ou, uint8_t *ov, int ouv_stride,
int oheight, int owidth) {
vp9_resize_plane(y, height, width, y_stride,
oy, oheight, owidth, oy_stride);
vp9_resize_plane(u, height, width, uv_stride,
ou, oheight, owidth, ouv_stride);
vp9_resize_plane(v, height, width, uv_stride,
ov, oheight, owidth, ouv_stride);
}
#if CONFIG_VP9_HIGHBITDEPTH
void vp9_highbd_resize_frame420(const uint8_t *const y,
int y_stride,
const uint8_t *const u, const uint8_t *const v,
int uv_stride,
int height, int width,
uint8_t *oy, int oy_stride,
uint8_t *ou, uint8_t *ov, int ouv_stride,
int oheight, int owidth, int bd) {
vp9_highbd_resize_plane(y, height, width, y_stride,
oy, oheight, owidth, oy_stride, bd);
vp9_highbd_resize_plane(u, height / 2, width / 2, uv_stride,
ou, oheight / 2, owidth / 2, ouv_stride, bd);
vp9_highbd_resize_plane(v, height / 2, width / 2, uv_stride,
ov, oheight / 2, owidth / 2, ouv_stride, bd);
}
void vp9_highbd_resize_frame422(const uint8_t *const y, int y_stride,
const uint8_t *const u, const uint8_t *const v,
int uv_stride,
int height, int width,
uint8_t *oy, int oy_stride,
uint8_t *ou, uint8_t *ov, int ouv_stride,
int oheight, int owidth, int bd) {
vp9_highbd_resize_plane(y, height, width, y_stride,
oy, oheight, owidth, oy_stride, bd);
vp9_highbd_resize_plane(u, height, width / 2, uv_stride,
ou, oheight, owidth / 2, ouv_stride, bd);
vp9_highbd_resize_plane(v, height, width / 2, uv_stride,
ov, oheight, owidth / 2, ouv_stride, bd);
}
void vp9_highbd_resize_frame444(const uint8_t *const y, int y_stride,
const uint8_t *const u, const uint8_t *const v,
int uv_stride,
int height, int width,
uint8_t *oy, int oy_stride,
uint8_t *ou, uint8_t *ov, int ouv_stride,
int oheight, int owidth, int bd) {
vp9_highbd_resize_plane(y, height, width, y_stride,
oy, oheight, owidth, oy_stride, bd);
vp9_highbd_resize_plane(u, height, width, uv_stride,
ou, oheight, owidth, ouv_stride, bd);
vp9_highbd_resize_plane(v, height, width, uv_stride,
ov, oheight, owidth, ouv_stride, bd);
}
#endif // CONFIG_VP9_HIGHBITDEPTH

View file

@ -0,0 +1,124 @@
/*
* Copyright (c) 2014 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.
*/
#ifndef VP9_ENCODER_VP9_RESIZE_H_
#define VP9_ENCODER_VP9_RESIZE_H_
#include <stdio.h>
#include "vpx/vpx_integer.h"
void vp9_resize_plane(const uint8_t *const input,
int height,
int width,
int in_stride,
uint8_t *output,
int height2,
int width2,
int out_stride);
void vp9_resize_frame420(const uint8_t *const y,
int y_stride,
const uint8_t *const u,
const uint8_t *const v,
int uv_stride,
int height,
int width,
uint8_t *oy,
int oy_stride,
uint8_t *ou,
uint8_t *ov,
int ouv_stride,
int oheight,
int owidth);
void vp9_resize_frame422(const uint8_t *const y,
int y_stride,
const uint8_t *const u,
const uint8_t *const v,
int uv_stride,
int height,
int width,
uint8_t *oy,
int oy_stride,
uint8_t *ou,
uint8_t *ov,
int ouv_stride,
int oheight,
int owidth);
void vp9_resize_frame444(const uint8_t *const y,
int y_stride,
const uint8_t *const u,
const uint8_t *const v,
int uv_stride,
int height,
int width,
uint8_t *oy,
int oy_stride,
uint8_t *ou,
uint8_t *ov,
int ouv_stride,
int oheight,
int owidth);
#if CONFIG_VP9_HIGHBITDEPTH
void vp9_highbd_resize_plane(const uint8_t *const input,
int height,
int width,
int in_stride,
uint8_t *output,
int height2,
int width2,
int out_stride,
int bd);
void vp9_highbd_resize_frame420(const uint8_t *const y,
int y_stride,
const uint8_t *const u,
const uint8_t *const v,
int uv_stride,
int height,
int width,
uint8_t *oy,
int oy_stride,
uint8_t *ou,
uint8_t *ov,
int ouv_stride,
int oheight,
int owidth,
int bd);
void vp9_highbd_resize_frame422(const uint8_t *const y,
int y_stride,
const uint8_t *const u,
const uint8_t *const v,
int uv_stride,
int height,
int width,
uint8_t *oy,
int oy_stride,
uint8_t *ou,
uint8_t *ov,
int ouv_stride,
int oheight,
int owidth,
int bd);
void vp9_highbd_resize_frame444(const uint8_t *const y,
int y_stride,
const uint8_t *const u,
const uint8_t *const v,
int uv_stride,
int height,
int width,
uint8_t *oy,
int oy_stride,
uint8_t *ou,
uint8_t *ov,
int ouv_stride,
int oheight,
int owidth,
int bd);
#endif // CONFIG_VP9_HIGHBITDEPTH
#endif // VP9_ENCODER_VP9_RESIZE_H_

View file

@ -0,0 +1,281 @@
/*
* Copyright (c) 2012 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <limits.h>
#include "vpx_mem/vpx_mem.h"
#include "vp9/common/vp9_pred_common.h"
#include "vp9/common/vp9_tile_common.h"
#include "vp9/encoder/vp9_cost.h"
#include "vp9/encoder/vp9_segmentation.h"
void vp9_enable_segmentation(struct segmentation *seg) {
seg->enabled = 1;
seg->update_map = 1;
seg->update_data = 1;
}
void vp9_disable_segmentation(struct segmentation *seg) {
seg->enabled = 0;
seg->update_map = 0;
seg->update_data = 0;
}
void vp9_set_segment_data(struct segmentation *seg,
signed char *feature_data,
unsigned char abs_delta) {
seg->abs_delta = abs_delta;
memcpy(seg->feature_data, feature_data, sizeof(seg->feature_data));
}
void vp9_disable_segfeature(struct segmentation *seg, int segment_id,
SEG_LVL_FEATURES feature_id) {
seg->feature_mask[segment_id] &= ~(1 << feature_id);
}
void vp9_clear_segdata(struct segmentation *seg, int segment_id,
SEG_LVL_FEATURES feature_id) {
seg->feature_data[segment_id][feature_id] = 0;
}
// Based on set of segment counts calculate a probability tree
static void calc_segtree_probs(int *segcounts, vp9_prob *segment_tree_probs) {
// Work out probabilities of each segment
const int c01 = segcounts[0] + segcounts[1];
const int c23 = segcounts[2] + segcounts[3];
const int c45 = segcounts[4] + segcounts[5];
const int c67 = segcounts[6] + segcounts[7];
segment_tree_probs[0] = get_binary_prob(c01 + c23, c45 + c67);
segment_tree_probs[1] = get_binary_prob(c01, c23);
segment_tree_probs[2] = get_binary_prob(c45, c67);
segment_tree_probs[3] = get_binary_prob(segcounts[0], segcounts[1]);
segment_tree_probs[4] = get_binary_prob(segcounts[2], segcounts[3]);
segment_tree_probs[5] = get_binary_prob(segcounts[4], segcounts[5]);
segment_tree_probs[6] = get_binary_prob(segcounts[6], segcounts[7]);
}
// Based on set of segment counts and probabilities calculate a cost estimate
static int cost_segmap(int *segcounts, vp9_prob *probs) {
const int c01 = segcounts[0] + segcounts[1];
const int c23 = segcounts[2] + segcounts[3];
const int c45 = segcounts[4] + segcounts[5];
const int c67 = segcounts[6] + segcounts[7];
const int c0123 = c01 + c23;
const int c4567 = c45 + c67;
// Cost the top node of the tree
int cost = c0123 * vp9_cost_zero(probs[0]) +
c4567 * vp9_cost_one(probs[0]);
// Cost subsequent levels
if (c0123 > 0) {
cost += c01 * vp9_cost_zero(probs[1]) +
c23 * vp9_cost_one(probs[1]);
if (c01 > 0)
cost += segcounts[0] * vp9_cost_zero(probs[3]) +
segcounts[1] * vp9_cost_one(probs[3]);
if (c23 > 0)
cost += segcounts[2] * vp9_cost_zero(probs[4]) +
segcounts[3] * vp9_cost_one(probs[4]);
}
if (c4567 > 0) {
cost += c45 * vp9_cost_zero(probs[2]) +
c67 * vp9_cost_one(probs[2]);
if (c45 > 0)
cost += segcounts[4] * vp9_cost_zero(probs[5]) +
segcounts[5] * vp9_cost_one(probs[5]);
if (c67 > 0)
cost += segcounts[6] * vp9_cost_zero(probs[6]) +
segcounts[7] * vp9_cost_one(probs[6]);
}
return cost;
}
static void count_segs(const VP9_COMMON *cm, MACROBLOCKD *xd,
const TileInfo *tile, MODE_INFO **mi,
int *no_pred_segcounts,
int (*temporal_predictor_count)[2],
int *t_unpred_seg_counts,
int bw, int bh, int mi_row, int mi_col) {
int segment_id;
if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols)
return;
xd->mi = mi;
segment_id = xd->mi[0]->mbmi.segment_id;
set_mi_row_col(xd, tile, mi_row, bh, mi_col, bw, cm->mi_rows, cm->mi_cols);
// Count the number of hits on each segment with no prediction
no_pred_segcounts[segment_id]++;
// Temporal prediction not allowed on key frames
if (cm->frame_type != KEY_FRAME) {
const BLOCK_SIZE bsize = xd->mi[0]->mbmi.sb_type;
// Test to see if the segment id matches the predicted value.
const int pred_segment_id = vp9_get_segment_id(cm, cm->last_frame_seg_map,
bsize, mi_row, mi_col);
const int pred_flag = pred_segment_id == segment_id;
const int pred_context = vp9_get_pred_context_seg_id(xd);
// Store the prediction status for this mb and update counts
// as appropriate
xd->mi[0]->mbmi.seg_id_predicted = pred_flag;
temporal_predictor_count[pred_context][pred_flag]++;
// Update the "unpredicted" segment count
if (!pred_flag)
t_unpred_seg_counts[segment_id]++;
}
}
static void count_segs_sb(const VP9_COMMON *cm, MACROBLOCKD *xd,
const TileInfo *tile, MODE_INFO **mi,
int *no_pred_segcounts,
int (*temporal_predictor_count)[2],
int *t_unpred_seg_counts,
int mi_row, int mi_col,
BLOCK_SIZE bsize) {
const int mis = cm->mi_stride;
int bw, bh;
const int bs = num_8x8_blocks_wide_lookup[bsize], hbs = bs / 2;
if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols)
return;
bw = num_8x8_blocks_wide_lookup[mi[0]->mbmi.sb_type];
bh = num_8x8_blocks_high_lookup[mi[0]->mbmi.sb_type];
if (bw == bs && bh == bs) {
count_segs(cm, xd, tile, mi, no_pred_segcounts, temporal_predictor_count,
t_unpred_seg_counts, bs, bs, mi_row, mi_col);
} else if (bw == bs && bh < bs) {
count_segs(cm, xd, tile, mi, no_pred_segcounts, temporal_predictor_count,
t_unpred_seg_counts, bs, hbs, mi_row, mi_col);
count_segs(cm, xd, tile, mi + hbs * mis, no_pred_segcounts,
temporal_predictor_count, t_unpred_seg_counts, bs, hbs,
mi_row + hbs, mi_col);
} else if (bw < bs && bh == bs) {
count_segs(cm, xd, tile, mi, no_pred_segcounts, temporal_predictor_count,
t_unpred_seg_counts, hbs, bs, mi_row, mi_col);
count_segs(cm, xd, tile, mi + hbs,
no_pred_segcounts, temporal_predictor_count, t_unpred_seg_counts,
hbs, bs, mi_row, mi_col + hbs);
} else {
const BLOCK_SIZE subsize = subsize_lookup[PARTITION_SPLIT][bsize];
int n;
assert(bw < bs && bh < bs);
for (n = 0; n < 4; n++) {
const int mi_dc = hbs * (n & 1);
const int mi_dr = hbs * (n >> 1);
count_segs_sb(cm, xd, tile, &mi[mi_dr * mis + mi_dc],
no_pred_segcounts, temporal_predictor_count,
t_unpred_seg_counts,
mi_row + mi_dr, mi_col + mi_dc, subsize);
}
}
}
void vp9_choose_segmap_coding_method(VP9_COMMON *cm, MACROBLOCKD *xd) {
struct segmentation *seg = &cm->seg;
int no_pred_cost;
int t_pred_cost = INT_MAX;
int i, tile_col, mi_row, mi_col;
int temporal_predictor_count[PREDICTION_PROBS][2] = { { 0 } };
int no_pred_segcounts[MAX_SEGMENTS] = { 0 };
int t_unpred_seg_counts[MAX_SEGMENTS] = { 0 };
vp9_prob no_pred_tree[SEG_TREE_PROBS];
vp9_prob t_pred_tree[SEG_TREE_PROBS];
vp9_prob t_nopred_prob[PREDICTION_PROBS];
// Set default state for the segment tree probabilities and the
// temporal coding probabilities
memset(seg->tree_probs, 255, sizeof(seg->tree_probs));
memset(seg->pred_probs, 255, sizeof(seg->pred_probs));
// First of all generate stats regarding how well the last segment map
// predicts this one
for (tile_col = 0; tile_col < 1 << cm->log2_tile_cols; tile_col++) {
TileInfo tile;
MODE_INFO **mi_ptr;
vp9_tile_init(&tile, cm, 0, tile_col);
mi_ptr = cm->mi_grid_visible + tile.mi_col_start;
for (mi_row = 0; mi_row < cm->mi_rows;
mi_row += 8, mi_ptr += 8 * cm->mi_stride) {
MODE_INFO **mi = mi_ptr;
for (mi_col = tile.mi_col_start; mi_col < tile.mi_col_end;
mi_col += 8, mi += 8)
count_segs_sb(cm, xd, &tile, mi, no_pred_segcounts,
temporal_predictor_count, t_unpred_seg_counts,
mi_row, mi_col, BLOCK_64X64);
}
}
// Work out probability tree for coding segments without prediction
// and the cost.
calc_segtree_probs(no_pred_segcounts, no_pred_tree);
no_pred_cost = cost_segmap(no_pred_segcounts, no_pred_tree);
// Key frames cannot use temporal prediction
if (!frame_is_intra_only(cm)) {
// Work out probability tree for coding those segments not
// predicted using the temporal method and the cost.
calc_segtree_probs(t_unpred_seg_counts, t_pred_tree);
t_pred_cost = cost_segmap(t_unpred_seg_counts, t_pred_tree);
// Add in the cost of the signaling for each prediction context.
for (i = 0; i < PREDICTION_PROBS; i++) {
const int count0 = temporal_predictor_count[i][0];
const int count1 = temporal_predictor_count[i][1];
t_nopred_prob[i] = get_binary_prob(count0, count1);
// Add in the predictor signaling cost
t_pred_cost += count0 * vp9_cost_zero(t_nopred_prob[i]) +
count1 * vp9_cost_one(t_nopred_prob[i]);
}
}
// Now choose which coding method to use.
if (t_pred_cost < no_pred_cost) {
seg->temporal_update = 1;
memcpy(seg->tree_probs, t_pred_tree, sizeof(t_pred_tree));
memcpy(seg->pred_probs, t_nopred_prob, sizeof(t_nopred_prob));
} else {
seg->temporal_update = 0;
memcpy(seg->tree_probs, no_pred_tree, sizeof(no_pred_tree));
}
}
void vp9_reset_segment_features(struct segmentation *seg) {
// Set up default state for MB feature flags
seg->enabled = 0;
seg->update_map = 0;
seg->update_data = 0;
memset(seg->tree_probs, 255, sizeof(seg->tree_probs));
vp9_clearall_segfeatures(seg);
}

View file

@ -0,0 +1,53 @@
/*
* 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.
*/
#ifndef VP9_ENCODER_VP9_SEGMENTATION_H_
#define VP9_ENCODER_VP9_SEGMENTATION_H_
#include "vp9/common/vp9_blockd.h"
#include "vp9/encoder/vp9_encoder.h"
#ifdef __cplusplus
extern "C" {
#endif
void vp9_enable_segmentation(struct segmentation *seg);
void vp9_disable_segmentation(struct segmentation *seg);
void vp9_disable_segfeature(struct segmentation *seg,
int segment_id,
SEG_LVL_FEATURES feature_id);
void vp9_clear_segdata(struct segmentation *seg,
int segment_id,
SEG_LVL_FEATURES feature_id);
// The values given for each segment can be either deltas (from the default
// value chosen for the frame) or absolute values.
//
// Valid range for abs values is (0-127 for MB_LVL_ALT_Q), (0-63 for
// SEGMENT_ALT_LF)
// Valid range for delta values are (+/-127 for MB_LVL_ALT_Q), (+/-63 for
// SEGMENT_ALT_LF)
//
// abs_delta = SEGMENT_DELTADATA (deltas) abs_delta = SEGMENT_ABSDATA (use
// the absolute values given).
void vp9_set_segment_data(struct segmentation *seg, signed char *feature_data,
unsigned char abs_delta);
void vp9_choose_segmap_coding_method(VP9_COMMON *cm, MACROBLOCKD *xd);
void vp9_reset_segment_features(struct segmentation *seg);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // VP9_ENCODER_VP9_SEGMENTATION_H_

View file

@ -0,0 +1,104 @@
/*
* Copyright (c) 2015 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <limits.h>
#include <math.h>
#include "vp9/common/vp9_blockd.h"
#include "vp9/encoder/vp9_encoder.h"
#include "vp9/encoder/vp9_skin_detection.h"
// Fixed-point skin color model parameters.
static const int skin_mean[2] = {7463, 9614}; // q6
static const int skin_inv_cov[4] = {4107, 1663, 1663, 2157}; // q16
static const int skin_threshold = 1570636; // q18
// Thresholds on luminance.
static const int y_low = 20;
static const int y_high = 220;
// Evaluates the Mahalanobis distance measure for the input CbCr values.
static int evaluate_skin_color_difference(int cb, int cr) {
const int cb_q6 = cb << 6;
const int cr_q6 = cr << 6;
const int cb_diff_q12 = (cb_q6 - skin_mean[0]) * (cb_q6 - skin_mean[0]);
const int cbcr_diff_q12 = (cb_q6 - skin_mean[0]) * (cr_q6 - skin_mean[1]);
const int cr_diff_q12 = (cr_q6 - skin_mean[1]) * (cr_q6 - skin_mean[1]);
const int cb_diff_q2 = (cb_diff_q12 + (1 << 9)) >> 10;
const int cbcr_diff_q2 = (cbcr_diff_q12 + (1 << 9)) >> 10;
const int cr_diff_q2 = (cr_diff_q12 + (1 << 9)) >> 10;
const int skin_diff = skin_inv_cov[0] * cb_diff_q2 +
skin_inv_cov[1] * cbcr_diff_q2 +
skin_inv_cov[2] * cbcr_diff_q2 +
skin_inv_cov[3] * cr_diff_q2;
return skin_diff;
}
int vp9_skin_pixel(const uint8_t y, const uint8_t cb, const uint8_t cr) {
if (y < y_low || y > y_high)
return 0;
else
return (evaluate_skin_color_difference(cb, cr) < skin_threshold);
}
#ifdef OUTPUT_YUV_SKINMAP
// For viewing skin map on input source.
void vp9_compute_skin_map(VP9_COMP *const cpi, FILE *yuv_skinmap_file) {
int i, j, mi_row, mi_col;
VP9_COMMON *const cm = &cpi->common;
uint8_t *y;
const uint8_t *src_y = cpi->Source->y_buffer;
const uint8_t *src_u = cpi->Source->u_buffer;
const uint8_t *src_v = cpi->Source->v_buffer;
const int src_ystride = cpi->Source->y_stride;
const int src_uvstride = cpi->Source->uv_stride;
YV12_BUFFER_CONFIG skinmap;
memset(&skinmap, 0, sizeof(YV12_BUFFER_CONFIG));
if (vp9_alloc_frame_buffer(&skinmap, cm->width, cm->height,
cm->subsampling_x, cm->subsampling_y,
VP9_ENC_BORDER_IN_PIXELS, cm->byte_alignment)) {
vp9_free_frame_buffer(&skinmap);
return;
}
memset(skinmap.buffer_alloc, 128, skinmap.frame_size);
y = skinmap.y_buffer;
// Loop through 8x8 blocks and set skin map based on center pixel of block.
// Set y to white for skin block, otherwise set to source with gray scale.
// Ignore rightmost/bottom boundary blocks.
for (mi_row = 0; mi_row < cm->mi_rows - 1; ++mi_row) {
for (mi_col = 0; mi_col < cm->mi_cols - 1; ++mi_col) {
// Use middle pixel for each 8x8 block for skin detection.
// If middle pixel is skin, assign whole 8x8 block to skin.
const uint8_t ysource = src_y[4 * src_ystride + 4];
const uint8_t usource = src_u[2 * src_uvstride + 2];
const uint8_t vsource = src_v[2 * src_uvstride + 2];
const int is_skin = vp9_skin_pixel(ysource, usource, vsource);
for (i = 0; i < 8; i++) {
for (j = 0; j < 8; j++) {
if (is_skin)
y[i * src_ystride + j] = 255;
else
y[i * src_ystride + j] = src_y[i * src_ystride + j];
}
}
y += 8;
src_y += 8;
src_u += 4;
src_v += 4;
}
y += (src_ystride << 3) - ((cm->mi_cols - 1) << 3);
src_y += (src_ystride << 3) - ((cm->mi_cols - 1) << 3);
src_u += (src_uvstride << 2) - ((cm->mi_cols - 1) << 2);
src_v += (src_uvstride << 2) - ((cm->mi_cols - 1) << 2);
}
vp9_write_yuv_frame_420(&skinmap, yuv_skinmap_file);
vp9_free_frame_buffer(&skinmap);
}
#endif

View file

@ -0,0 +1,35 @@
/*
* Copyright (c) 2015 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.
*/
#ifndef VP9_ENCODER_VP9_SKIN_MAP_H_
#define VP9_ENCODER_VP9_SKIN_MAP_H_
#include "vp9/common/vp9_blockd.h"
#ifdef __cplusplus
extern "C" {
#endif
struct VP9_COMP;
// #define OUTPUT_YUV_SKINMAP
int vp9_skin_pixel(const uint8_t y, const uint8_t cb, const uint8_t cr);
#ifdef OUTPUT_YUV_SKINMAP
// For viewing skin map on input source.
void vp9_compute_skin_map(VP9_COMP *const cpi, FILE *yuv_skinmap_file);
#endif
#ifdef __cplusplus
} // extern "C"
#endif
#endif // VP9_ENCODER_VP9_SKIN_MAP_H_

View file

@ -0,0 +1,531 @@
/*
* Copyright (c) 2010 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <limits.h>
#include "vp9/encoder/vp9_encoder.h"
#include "vp9/encoder/vp9_speed_features.h"
// 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 VP9_COMP *cpi) {
return frame_is_kf_gf_arf(cpi) || vp9_is_upper_layer_key_frame(cpi);
}
static void set_good_speed_feature_framesize_dependent(VP9_COMMON *cm,
SPEED_FEATURES *sf,
int speed) {
if (speed >= 1) {
if (MIN(cm->width, cm->height) >= 720) {
sf->disable_split_mask = cm->show_frame ? DISABLE_ALL_SPLIT
: DISABLE_ALL_INTER_SPLIT;
sf->partition_search_breakout_dist_thr = (1 << 23);
} else {
sf->disable_split_mask = DISABLE_COMPOUND_SPLIT;
sf->partition_search_breakout_dist_thr = (1 << 21);
}
}
if (speed >= 2) {
if (MIN(cm->width, cm->height) >= 720) {
sf->disable_split_mask = cm->show_frame ? DISABLE_ALL_SPLIT
: DISABLE_ALL_INTER_SPLIT;
sf->adaptive_pred_interp_filter = 0;
sf->partition_search_breakout_dist_thr = (1 << 24);
sf->partition_search_breakout_rate_thr = 120;
} else {
sf->disable_split_mask = LAST_AND_INTRA_SPLIT_ONLY;
sf->partition_search_breakout_dist_thr = (1 << 22);
sf->partition_search_breakout_rate_thr = 100;
}
}
if (speed >= 3) {
if (MIN(cm->width, cm->height) >= 720) {
sf->disable_split_mask = DISABLE_ALL_SPLIT;
sf->schedule_mode_search = cm->base_qindex < 220 ? 1 : 0;
sf->partition_search_breakout_dist_thr = (1 << 25);
sf->partition_search_breakout_rate_thr = 200;
} else {
sf->max_intra_bsize = BLOCK_32X32;
sf->disable_split_mask = DISABLE_ALL_INTER_SPLIT;
sf->schedule_mode_search = cm->base_qindex < 175 ? 1 : 0;
sf->partition_search_breakout_dist_thr = (1 << 23);
sf->partition_search_breakout_rate_thr = 120;
}
}
if (speed >= 4) {
if (MIN(cm->width, cm->height) >= 720) {
sf->partition_search_breakout_dist_thr = (1 << 26);
} else {
sf->partition_search_breakout_dist_thr = (1 << 24);
}
sf->disable_split_mask = DISABLE_ALL_SPLIT;
}
}
// Sets a partition size down to which the auto partition code will always
// search (can go lower), based on the image dimensions. The logic here
// is that the extent to which ringing artefacts are offensive, depends
// 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(VP9_COMP *cpi) {
VP9_COMMON *const cm = &cpi->common;
unsigned int screen_area = (cm->width * cm->height);
// Select block size based on image format size.
if (screen_area < 1280 * 720) {
// Formats smaller in area than 720P
return BLOCK_4X4;
} else if (screen_area < 1920 * 1080) {
// Format >= 720P and < 1080P
return BLOCK_8X8;
} else {
// Formats 1080P and up
return BLOCK_16X16;
}
}
static void set_good_speed_feature(VP9_COMP *cpi, VP9_COMMON *cm,
SPEED_FEATURES *sf, int speed) {
const int boosted = frame_is_boosted(cpi);
sf->adaptive_rd_thresh = 1;
sf->allow_skip_recode = 1;
if (speed >= 1) {
sf->use_square_partition_only = !frame_is_intra_only(cm);
sf->less_rectangular_check = 1;
sf->use_rd_breakout = 1;
sf->adaptive_motion_search = 1;
sf->mv.auto_mv_step_size = 1;
sf->adaptive_rd_thresh = 2;
sf->mv.subpel_iters_per_step = 1;
sf->mode_skip_start = 10;
sf->adaptive_pred_interp_filter = 1;
sf->recode_loop = ALLOW_RECODE_KFARFGF;
sf->intra_y_mode_mask[TX_32X32] = INTRA_DC_H_V;
sf->intra_uv_mode_mask[TX_32X32] = INTRA_DC_H_V;
sf->intra_y_mode_mask[TX_16X16] = INTRA_DC_H_V;
sf->intra_uv_mode_mask[TX_16X16] = INTRA_DC_H_V;
sf->tx_size_search_breakout = 1;
sf->partition_search_breakout_rate_thr = 80;
}
if (speed >= 2) {
sf->tx_size_search_method = frame_is_boosted(cpi) ? USE_FULL_RD
: USE_LARGESTALL;
// Reference masking is not supported in dynamic scaling mode.
sf->reference_masking = cpi->oxcf.resize_mode != RESIZE_DYNAMIC ? 1 : 0;
sf->mode_search_skip_flags = (cm->frame_type == KEY_FRAME) ? 0 :
FLAG_SKIP_INTRA_DIRMISMATCH |
FLAG_SKIP_INTRA_BESTINTER |
FLAG_SKIP_COMP_BESTINTRA |
FLAG_SKIP_INTRA_LOWVAR;
sf->disable_filter_search_var_thresh = 100;
sf->comp_inter_joint_search_thresh = BLOCK_SIZES;
sf->auto_min_max_partition_size = RELAXED_NEIGHBORING_MIN_MAX;
sf->rd_auto_partition_min_limit = set_partition_min_limit(cpi);
sf->allow_partition_search_skip = 1;
}
if (speed >= 3) {
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->cb_pred_filter_search = 1;
sf->alt_ref_search_fp = 1;
sf->recode_loop = ALLOW_RECODE_KFMAXBW;
sf->adaptive_rd_thresh = 3;
sf->mode_skip_start = 6;
sf->intra_y_mode_mask[TX_32X32] = INTRA_DC;
sf->intra_uv_mode_mask[TX_32X32] = INTRA_DC;
sf->adaptive_interp_filter_search = 1;
}
if (speed >= 4) {
sf->use_square_partition_only = 1;
sf->tx_size_search_method = USE_LARGESTALL;
sf->mv.search_method = BIGDIA;
sf->mv.subpel_search_method = SUBPEL_TREE_PRUNED_MORE;
sf->adaptive_rd_thresh = 4;
if (cm->frame_type != KEY_FRAME)
sf->mode_search_skip_flags |= FLAG_EARLY_TERMINATE;
sf->disable_filter_search_var_thresh = 200;
sf->use_lp32x32fdct = 1;
sf->use_fast_coef_updates = ONE_LOOP_REDUCED;
sf->use_fast_coef_costing = 1;
sf->motion_field_mode_search = !boosted;
sf->partition_search_breakout_rate_thr = 300;
}
if (speed >= 5) {
int i;
sf->optimize_coefficients = 0;
sf->mv.search_method = HEX;
sf->disable_filter_search_var_thresh = 500;
for (i = 0; i < TX_SIZES; ++i) {
sf->intra_y_mode_mask[i] = INTRA_DC;
sf->intra_uv_mode_mask[i] = INTRA_DC;
}
sf->partition_search_breakout_rate_thr = 500;
sf->mv.reduce_first_step_size = 1;
}
}
static void set_rt_speed_feature_framesize_dependent(VP9_COMP *cpi,
SPEED_FEATURES *sf, int speed) {
VP9_COMMON *const cm = &cpi->common;
if (speed >= 1) {
if (MIN(cm->width, cm->height) >= 720) {
sf->disable_split_mask = cm->show_frame ? DISABLE_ALL_SPLIT
: DISABLE_ALL_INTER_SPLIT;
} else {
sf->disable_split_mask = DISABLE_COMPOUND_SPLIT;
}
}
if (speed >= 2) {
if (MIN(cm->width, cm->height) >= 720) {
sf->disable_split_mask = cm->show_frame ? DISABLE_ALL_SPLIT
: DISABLE_ALL_INTER_SPLIT;
} else {
sf->disable_split_mask = LAST_AND_INTRA_SPLIT_ONLY;
}
}
if (speed >= 5) {
if (MIN(cm->width, cm->height) >= 720) {
sf->partition_search_breakout_dist_thr = (1 << 25);
} else {
sf->partition_search_breakout_dist_thr = (1 << 23);
}
}
if (speed >= 7) {
sf->encode_breakout_thresh = (MIN(cm->width, cm->height) >= 720) ?
800 : 300;
}
}
static void set_rt_speed_feature(VP9_COMP *cpi, SPEED_FEATURES *sf,
int speed, vp9e_tune_content content) {
VP9_COMMON *const cm = &cpi->common;
const int is_keyframe = cm->frame_type == KEY_FRAME;
const int frames_since_key = is_keyframe ? 0 : cpi->rc.frames_since_key;
sf->static_segmentation = 0;
sf->adaptive_rd_thresh = 1;
sf->use_fast_coef_costing = 1;
if (speed >= 1) {
sf->use_square_partition_only = !frame_is_intra_only(cm);
sf->less_rectangular_check = 1;
sf->tx_size_search_method = frame_is_intra_only(cm) ? USE_FULL_RD
: USE_LARGESTALL;
sf->use_rd_breakout = 1;
sf->adaptive_motion_search = 1;
sf->adaptive_pred_interp_filter = 1;
sf->mv.auto_mv_step_size = 1;
sf->adaptive_rd_thresh = 2;
sf->intra_y_mode_mask[TX_32X32] = INTRA_DC_H_V;
sf->intra_uv_mode_mask[TX_32X32] = INTRA_DC_H_V;
sf->intra_uv_mode_mask[TX_16X16] = INTRA_DC_H_V;
}
if (speed >= 2) {
sf->mode_search_skip_flags = (cm->frame_type == KEY_FRAME) ? 0 :
FLAG_SKIP_INTRA_DIRMISMATCH |
FLAG_SKIP_INTRA_BESTINTER |
FLAG_SKIP_COMP_BESTINTRA |
FLAG_SKIP_INTRA_LOWVAR;
sf->adaptive_pred_interp_filter = 2;
// Disable reference masking if using spatial scaling since
// pred_mv_sad will not be set (since vp9_mv_pred will not
// be called).
// TODO(marpan/agrange): Fix this condition.
sf->reference_masking = (cpi->oxcf.resize_mode != RESIZE_DYNAMIC &&
cpi->svc.number_spatial_layers == 1) ? 1 : 0;
sf->disable_filter_search_var_thresh = 50;
sf->comp_inter_joint_search_thresh = BLOCK_SIZES;
sf->auto_min_max_partition_size = RELAXED_NEIGHBORING_MIN_MAX;
sf->lf_motion_threshold = LOW_MOTION_THRESHOLD;
sf->adjust_partitioning_from_last_frame = 1;
sf->last_partitioning_redo_frequency = 3;
sf->use_lp32x32fdct = 1;
sf->mode_skip_start = 11;
sf->intra_y_mode_mask[TX_16X16] = INTRA_DC_H_V;
}
if (speed >= 3) {
sf->use_square_partition_only = 1;
sf->disable_filter_search_var_thresh = 100;
sf->use_uv_intra_rd_estimate = 1;
sf->skip_encode_sb = 1;
sf->mv.subpel_iters_per_step = 1;
sf->adaptive_rd_thresh = 4;
sf->mode_skip_start = 6;
sf->allow_skip_recode = 0;
sf->optimize_coefficients = 0;
sf->disable_split_mask = DISABLE_ALL_SPLIT;
sf->lpf_pick = LPF_PICK_FROM_Q;
}
if (speed >= 4) {
int i;
sf->last_partitioning_redo_frequency = 4;
sf->adaptive_rd_thresh = 5;
sf->use_fast_coef_costing = 0;
sf->auto_min_max_partition_size = STRICT_NEIGHBORING_MIN_MAX;
sf->adjust_partitioning_from_last_frame =
cm->last_frame_type != cm->frame_type || (0 ==
(frames_since_key + 1) % sf->last_partitioning_redo_frequency);
sf->mv.subpel_force_stop = 1;
for (i = 0; i < TX_SIZES; i++) {
sf->intra_y_mode_mask[i] = INTRA_DC_H_V;
sf->intra_uv_mode_mask[i] = INTRA_DC;
}
sf->intra_y_mode_mask[TX_32X32] = INTRA_DC;
sf->frame_parameter_update = 0;
sf->mv.search_method = FAST_HEX;
sf->inter_mode_mask[BLOCK_32X32] = INTER_NEAREST_NEAR_NEW;
sf->inter_mode_mask[BLOCK_32X64] = INTER_NEAREST;
sf->inter_mode_mask[BLOCK_64X32] = INTER_NEAREST;
sf->inter_mode_mask[BLOCK_64X64] = INTER_NEAREST;
sf->max_intra_bsize = BLOCK_32X32;
sf->allow_skip_recode = 1;
}
if (speed >= 5) {
sf->use_quant_fp = !is_keyframe;
sf->auto_min_max_partition_size = is_keyframe ? RELAXED_NEIGHBORING_MIN_MAX
: STRICT_NEIGHBORING_MIN_MAX;
sf->default_max_partition_size = BLOCK_32X32;
sf->default_min_partition_size = BLOCK_8X8;
sf->force_frame_boost = is_keyframe ||
(frames_since_key % (sf->last_partitioning_redo_frequency << 1) == 1);
sf->max_delta_qindex = is_keyframe ? 20 : 15;
sf->partition_search_type = REFERENCE_PARTITION;
sf->use_nonrd_pick_mode = 1;
sf->allow_skip_recode = 0;
sf->inter_mode_mask[BLOCK_32X32] = INTER_NEAREST_NEW_ZERO;
sf->inter_mode_mask[BLOCK_32X64] = INTER_NEAREST_NEW_ZERO;
sf->inter_mode_mask[BLOCK_64X32] = INTER_NEAREST_NEW_ZERO;
sf->inter_mode_mask[BLOCK_64X64] = INTER_NEAREST_NEW_ZERO;
sf->adaptive_rd_thresh = 2;
// This feature is only enabled when partition search is disabled.
sf->reuse_inter_pred_sby = 1;
sf->partition_search_breakout_rate_thr = 200;
sf->coeff_prob_appx_step = 4;
sf->use_fast_coef_updates = is_keyframe ? TWO_LOOP : ONE_LOOP_REDUCED;
sf->mode_search_skip_flags = FLAG_SKIP_INTRA_DIRMISMATCH;
sf->tx_size_search_method = is_keyframe ? USE_LARGESTALL : USE_TX_8X8;
if (!is_keyframe) {
int i;
if (content == VP9E_CONTENT_SCREEN) {
for (i = 0; i < BLOCK_SIZES; ++i)
sf->intra_y_mode_bsize_mask[i] = INTRA_DC_TM_H_V;
} else {
for (i = 0; i < BLOCK_SIZES; ++i)
if (i >= BLOCK_16X16)
sf->intra_y_mode_bsize_mask[i] = INTRA_DC;
else
// Use H and V intra mode for block sizes <= 16X16.
sf->intra_y_mode_bsize_mask[i] = INTRA_DC_H_V;
}
}
}
if (speed >= 6) {
// Adaptively switch between SOURCE_VAR_BASED_PARTITION and FIXED_PARTITION.
sf->partition_search_type = VAR_BASED_PARTITION;
// Turn on this to use non-RD key frame coding mode.
sf->use_nonrd_pick_mode = 1;
sf->mv.search_method = NSTEP;
sf->mv.reduce_first_step_size = 1;
sf->skip_encode_sb = 0;
}
if (speed >= 7) {
sf->adaptive_rd_thresh = 3;
sf->mv.search_method = FAST_DIAMOND;
sf->mv.fullpel_search_step_param = 10;
}
if (speed >= 8) {
sf->adaptive_rd_thresh = 4;
sf->mv.subpel_force_stop = 2;
sf->lpf_pick = LPF_PICK_MINIMAL_LPF;
}
}
void vp9_set_speed_features_framesize_dependent(VP9_COMP *cpi) {
SPEED_FEATURES *const sf = &cpi->sf;
VP9_COMMON *const cm = &cpi->common;
const VP9EncoderConfig *const oxcf = &cpi->oxcf;
RD_OPT *const rd = &cpi->rd;
int i;
if (oxcf->mode == REALTIME) {
set_rt_speed_feature_framesize_dependent(cpi, sf, oxcf->speed);
} else if (oxcf->mode == GOOD) {
set_good_speed_feature_framesize_dependent(cm, sf, oxcf->speed);
}
if (sf->disable_split_mask == DISABLE_ALL_SPLIT) {
sf->adaptive_pred_interp_filter = 0;
}
if (cpi->encode_breakout && oxcf->mode == REALTIME &&
sf->encode_breakout_thresh > cpi->encode_breakout) {
cpi->encode_breakout = sf->encode_breakout_thresh;
}
// 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;
}
}
}
void vp9_set_speed_features_framesize_independent(VP9_COMP *cpi) {
SPEED_FEATURES *const sf = &cpi->sf;
VP9_COMMON *const cm = &cpi->common;
MACROBLOCK *const x = &cpi->td.mb;
const VP9EncoderConfig *const oxcf = &cpi->oxcf;
int i;
// best quality defaults
sf->frame_parameter_update = 1;
sf->mv.search_method = NSTEP;
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->optimize_coefficients = !is_lossless_requested(&cpi->oxcf);
sf->mv.reduce_first_step_size = 0;
sf->coeff_prob_appx_step = 1;
sf->mv.auto_mv_step_size = 0;
sf->mv.fullpel_search_step_param = 6;
sf->comp_inter_joint_search_thresh = BLOCK_4X4;
sf->adaptive_rd_thresh = 0;
sf->tx_size_search_method = USE_FULL_RD;
sf->use_lp32x32fdct = 0;
sf->adaptive_motion_search = 0;
sf->adaptive_pred_interp_filter = 0;
sf->adaptive_mode_search = 0;
sf->cb_pred_filter_search = 0;
sf->cb_partition_search = 0;
sf->motion_field_mode_search = 0;
sf->alt_ref_search_fp = 0;
sf->use_quant_fp = 0;
sf->reference_masking = 0;
sf->partition_search_type = SEARCH_PARTITION;
sf->less_rectangular_check = 0;
sf->use_square_partition_only = 0;
sf->auto_min_max_partition_size = NOT_IN_USE;
sf->rd_auto_partition_min_limit = BLOCK_4X4;
sf->default_max_partition_size = BLOCK_64X64;
sf->default_min_partition_size = BLOCK_4X4;
sf->adjust_partitioning_from_last_frame = 0;
sf->last_partitioning_redo_frequency = 4;
sf->disable_split_mask = 0;
sf->mode_search_skip_flags = 0;
sf->force_frame_boost = 0;
sf->max_delta_qindex = 0;
sf->disable_filter_search_var_thresh = 0;
sf->adaptive_interp_filter_search = 0;
sf->allow_partition_search_skip = 0;
for (i = 0; i < TX_SIZES; i++) {
sf->intra_y_mode_mask[i] = INTRA_ALL;
sf->intra_uv_mode_mask[i] = INTRA_ALL;
}
sf->use_rd_breakout = 0;
sf->skip_encode_sb = 0;
sf->use_uv_intra_rd_estimate = 0;
sf->allow_skip_recode = 0;
sf->lpf_pick = LPF_PICK_FROM_FULL_IMAGE;
sf->use_fast_coef_updates = TWO_LOOP;
sf->use_fast_coef_costing = 0;
sf->mode_skip_start = MAX_MODES; // Mode index at which mode skip mask set
sf->schedule_mode_search = 0;
sf->use_nonrd_pick_mode = 0;
for (i = 0; i < BLOCK_SIZES; ++i)
sf->inter_mode_mask[i] = INTER_ALL;
sf->max_intra_bsize = BLOCK_64X64;
sf->reuse_inter_pred_sby = 0;
// This setting only takes effect when partition_search_type is set
// to FIXED_PARTITION.
sf->always_this_block_size = BLOCK_16X16;
sf->search_type_check_frequency = 50;
sf->encode_breakout_thresh = 0;
// Recode loop tolerance %.
sf->recode_tolerance = 25;
sf->default_interp_filter = SWITCHABLE;
sf->tx_size_search_breakout = 0;
sf->partition_search_breakout_dist_thr = 0;
sf->partition_search_breakout_rate_thr = 0;
if (oxcf->mode == REALTIME)
set_rt_speed_feature(cpi, sf, oxcf->speed, oxcf->content);
else if (oxcf->mode == GOOD)
set_good_speed_feature(cpi, cm, sf, oxcf->speed);
cpi->full_search_sad = vp9_full_search_sad;
cpi->diamond_search_sad = oxcf->mode == BEST ? vp9_full_range_search
: vp9_diamond_search_sad;
// Slow quant, dct and trellis not worthwhile for first pass
// so make sure they are always turned off.
if (oxcf->pass == 1)
sf->optimize_coefficients = 0;
// No recode for 1 pass.
if (oxcf->pass == 0) {
sf->recode_loop = DISALLOW_RECODE;
sf->optimize_coefficients = 0;
}
if (sf->mv.subpel_search_method == SUBPEL_TREE) {
cpi->find_fractional_mv_step = vp9_find_best_sub_pixel_tree;
} else if (sf->mv.subpel_search_method == SUBPEL_TREE_PRUNED) {
cpi->find_fractional_mv_step = vp9_find_best_sub_pixel_tree_pruned;
} else if (sf->mv.subpel_search_method == SUBPEL_TREE_PRUNED_MORE) {
cpi->find_fractional_mv_step = vp9_find_best_sub_pixel_tree_pruned_more;
} else if (sf->mv.subpel_search_method == SUBPEL_TREE_PRUNED_EVENMORE) {
cpi->find_fractional_mv_step = vp9_find_best_sub_pixel_tree_pruned_evenmore;
}
x->optimize = sf->optimize_coefficients == 1 && oxcf->pass != 1;
x->min_partition_size = sf->default_min_partition_size;
x->max_partition_size = sf->default_max_partition_size;
if (!cpi->oxcf.frame_periodic_boost) {
sf->max_delta_qindex = 0;
}
}

View file

@ -0,0 +1,429 @@
/*
* 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.
*/
#ifndef VP9_ENCODER_VP9_SPEED_FEATURES_H_
#define VP9_ENCODER_VP9_SPEED_FEATURES_H_
#include "vp9/common/vp9_enums.h"
#ifdef __cplusplus
extern "C" {
#endif
enum {
INTRA_ALL = (1 << DC_PRED) |
(1 << V_PRED) | (1 << H_PRED) |
(1 << D45_PRED) | (1 << D135_PRED) |
(1 << D117_PRED) | (1 << D153_PRED) |
(1 << D207_PRED) | (1 << D63_PRED) |
(1 << TM_PRED),
INTRA_DC = (1 << DC_PRED),
INTRA_DC_TM = (1 << DC_PRED) | (1 << TM_PRED),
INTRA_DC_H_V = (1 << DC_PRED) | (1 << V_PRED) | (1 << H_PRED),
INTRA_DC_TM_H_V = (1 << DC_PRED) | (1 << TM_PRED) | (1 << V_PRED) |
(1 << H_PRED)
};
enum {
INTER_ALL = (1 << NEARESTMV) | (1 << NEARMV) | (1 << ZEROMV) | (1 << NEWMV),
INTER_NEAREST = (1 << NEARESTMV),
INTER_NEAREST_NEW = (1 << NEARESTMV) | (1 << NEWMV),
INTER_NEAREST_ZERO = (1 << NEARESTMV) | (1 << ZEROMV),
INTER_NEAREST_NEW_ZERO = (1 << NEARESTMV) | (1 << ZEROMV) | (1 << NEWMV),
INTER_NEAREST_NEAR_NEW = (1 << NEARESTMV) | (1 << NEARMV) | (1 << NEWMV),
INTER_NEAREST_NEAR_ZERO = (1 << NEARESTMV) | (1 << NEARMV) | (1 << ZEROMV),
};
enum {
DISABLE_ALL_INTER_SPLIT = (1 << THR_COMP_GA) |
(1 << THR_COMP_LA) |
(1 << THR_ALTR) |
(1 << THR_GOLD) |
(1 << THR_LAST),
DISABLE_ALL_SPLIT = (1 << THR_INTRA) | DISABLE_ALL_INTER_SPLIT,
DISABLE_COMPOUND_SPLIT = (1 << THR_COMP_GA) | (1 << THR_COMP_LA),
LAST_AND_INTRA_SPLIT_ONLY = (1 << THR_COMP_GA) |
(1 << THR_COMP_LA) |
(1 << THR_ALTR) |
(1 << THR_GOLD)
};
typedef enum {
DIAMOND = 0,
NSTEP = 1,
HEX = 2,
BIGDIA = 3,
SQUARE = 4,
FAST_HEX = 5,
FAST_DIAMOND = 6
} SEARCH_METHODS;
typedef enum {
// No recode.
DISALLOW_RECODE = 0,
// Allow recode for KF and exceeding maximum frame bandwidth.
ALLOW_RECODE_KFMAXBW = 1,
// Allow recode only for KF/ARF/GF frames.
ALLOW_RECODE_KFARFGF = 2,
// Allow recode for all frames based on bitrate constraints.
ALLOW_RECODE = 3,
} RECODE_LOOP_TYPE;
typedef 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;
typedef enum {
NO_MOTION_THRESHOLD = 0,
LOW_MOTION_THRESHOLD = 7
} MOTION_THRESHOLD;
typedef enum {
USE_FULL_RD = 0,
USE_LARGESTALL,
USE_TX_8X8
} TX_SIZE_SEARCH_METHOD;
typedef enum {
NOT_IN_USE = 0,
RELAXED_NEIGHBORING_MIN_MAX = 1,
STRICT_NEIGHBORING_MIN_MAX = 2
} AUTO_MIN_MAX_MODE;
typedef enum {
// Try the full image with different values.
LPF_PICK_FROM_FULL_IMAGE,
// Try a small portion of the image with different values.
LPF_PICK_FROM_SUBIMAGE,
// Estimate the level based on quantizer and frame type
LPF_PICK_FROM_Q,
// Pick 0 to disable LPF if LPF was enabled last frame
LPF_PICK_MINIMAL_LPF
} LPF_PICK_METHOD;
typedef 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,
// Skips comp inter modes if the best so far is an intra mode.
FLAG_SKIP_COMP_BESTINTRA = 1 << 1,
// Skips oblique intra modes if the best so far is an inter mode.
FLAG_SKIP_INTRA_BESTINTER = 1 << 3,
// Skips oblique intra modes at angles 27, 63, 117, 153 if the best
// intra so far is not one of the neighboring directions.
FLAG_SKIP_INTRA_DIRMISMATCH = 1 << 4,
// Skips intra modes other than DC_PRED if the source variance is small
FLAG_SKIP_INTRA_LOWVAR = 1 << 5,
} MODE_SEARCH_SKIP_LOGIC;
typedef enum {
FLAG_SKIP_EIGHTTAP = 1 << EIGHTTAP,
FLAG_SKIP_EIGHTTAP_SMOOTH = 1 << EIGHTTAP_SMOOTH,
FLAG_SKIP_EIGHTTAP_SHARP = 1 << EIGHTTAP_SHARP,
} INTERP_FILTER_MASK;
typedef enum {
// Search partitions using RD/NONRD criterion
SEARCH_PARTITION,
// Always use a fixed size partition
FIXED_PARTITION,
REFERENCE_PARTITION,
// Use an arbitrary partitioning scheme based on source variance within
// a 64X64 SB
VAR_BASED_PARTITION,
// Use non-fixed partitions based on source variance
SOURCE_VAR_BASED_PARTITION
} PARTITION_SEARCH_TYPE;
typedef enum {
// Does a dry run to see if any of the contexts need to be updated or not,
// before the final run.
TWO_LOOP = 0,
// No dry run, also only half the coef contexts and bands are updated.
// The rest are not updated at all.
ONE_LOOP_REDUCED = 1
} FAST_COEFF_UPDATE;
typedef struct MV_SPEED_FEATURES {
// Motion search method (Diamond, NSTEP, Hex, Big Diamond, Square, etc).
SEARCH_METHODS search_method;
// This parameter controls which step in the n-step process we start at.
// It's changed adaptively based on circumstances.
int reduce_first_step_size;
// If this is set to 1, we limit the motion search range to 2 times the
// largest motion vector found in the last frame.
int auto_mv_step_size;
// Subpel_search_method can only be subpel_tree which does a subpixel
// logarithmic search that keeps stepping at 1/2 pixel units until
// you stop getting a gain, and then goes on to 1/4 and repeats
// the same process. Along the way it skips many diagonals.
SUBPEL_SEARCH_METHODS subpel_search_method;
// 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;
// This variable sets the step_param used in full pel motion search.
int fullpel_search_step_param;
} MV_SPEED_FEATURES;
typedef struct SPEED_FEATURES {
MV_SPEED_FEATURES mv;
// Frame level coding parameter update
int frame_parameter_update;
RECODE_LOOP_TYPE recode_loop;
// Trellis (dynamic programming) optimization of quantized values (+1, 0).
int optimize_coefficients;
// Always set to 0. If on it enables 0 cost background transmission
// (except for the initial transmission of the segmentation). The feature is
// disabled because the addition of very large block sizes make the
// backgrounds very to cheap to encode, and the segmentation we have
// adds overhead.
int static_segmentation;
// If 1 we iterate finding a best reference for 2 ref frames together - via
// a log search that iterates 4 times (check around mv for last for best
// error of combined predictor then check around mv for alt). If 0 we
// we just use the best motion vector found for each frame by itself.
BLOCK_SIZE comp_inter_joint_search_thresh;
// This variable is used to cap the maximum number of times we skip testing a
// mode to be evaluated. A high value means we will be faster.
int adaptive_rd_thresh;
// Enables skipping the reconstruction step (idct, recon) in the
// intermediate steps assuming the last frame didn't have too many intra
// blocks and the q is less than a threshold.
int skip_encode_sb;
int skip_encode_frame;
// Speed feature to allow or disallow skipping of recode at block
// level within a frame.
int allow_skip_recode;
// Coefficient probability model approximation step size
int coeff_prob_appx_step;
// The threshold is to determine how slow the motino is, it is used when
// use_lastframe_partitioning is set to LAST_FRAME_PARTITION_LOW_MOTION
MOTION_THRESHOLD lf_motion_threshold;
// Determine which method we use to determine transform size. We can choose
// between options like full rd, largest for prediction size, largest
// for intra and model coefs for the rest.
TX_SIZE_SEARCH_METHOD tx_size_search_method;
// Low precision 32x32 fdct keeps everything in 16 bits and thus is less
// precise but significantly faster than the non lp version.
int use_lp32x32fdct;
// After looking at the first set of modes (set by index here), skip
// checking modes for reference frames that don't match the reference frame
// of the best so far.
int mode_skip_start;
// TODO(JBB): Remove this.
int reference_masking;
PARTITION_SEARCH_TYPE partition_search_type;
// Used if partition_search_type = FIXED_SIZE_PARTITION
BLOCK_SIZE always_this_block_size;
// Skip rectangular partition test when partition type none gives better
// rd than partition type split.
int less_rectangular_check;
// Disable testing non square partitions. (eg 16x32)
int use_square_partition_only;
// Sets min and max partition sizes for this 64x64 region based on the
// same 64x64 in last encoded frame, and the left and above neighbor.
AUTO_MIN_MAX_MODE auto_min_max_partition_size;
// Ensures the rd based auto partition search will always
// go down at least to the specified level.
BLOCK_SIZE rd_auto_partition_min_limit;
// Min and max partition size we enable (block_size) as per auto
// min max, but also used by adjust partitioning, and pick_partitioning.
BLOCK_SIZE default_min_partition_size;
BLOCK_SIZE default_max_partition_size;
// Whether or not we allow partitions one smaller or one greater than the last
// frame's partitioning. Only used if use_lastframe_partitioning is set.
int adjust_partitioning_from_last_frame;
// How frequently we re do the partitioning from scratch. Only used if
// use_lastframe_partitioning is set.
int last_partitioning_redo_frequency;
// Disables sub 8x8 blocksizes in different scenarios: Choices are to disable
// it always, to allow it for only Last frame and Intra, disable it for all
// inter modes or to enable it always.
int disable_split_mask;
// TODO(jingning): combine the related motion search speed features
// This allows us to use motion search at other sizes as a starting
// point for this motion search and limits the search range around it.
int adaptive_motion_search;
int schedule_mode_search;
// Allows sub 8x8 modes to use the prediction filter that was determined
// best for 8x8 mode. If set to 0 we always re check all the filters for
// sizes less than 8x8, 1 means we check all filter modes if no 8x8 filter
// was selected, and 2 means we use 8 tap if no 8x8 filter mode was selected.
int adaptive_pred_interp_filter;
// Adaptive prediction mode search
int adaptive_mode_search;
// Chessboard pattern prediction filter type search
int cb_pred_filter_search;
int cb_partition_search;
int motion_field_mode_search;
int alt_ref_search_fp;
// Fast quantization process path
int use_quant_fp;
// Use finer quantizer in every other few frames that run variable block
// partition type search.
int force_frame_boost;
// Maximally allowed base quantization index fluctuation.
int max_delta_qindex;
// Implements various heuristics to skip searching modes
// The heuristics selected are based on flags
// defined in the MODE_SEARCH_SKIP_HEURISTICS enum
unsigned int mode_search_skip_flags;
// A source variance threshold below which filter search is disabled
// Choose a very large value (UINT_MAX) to use 8-tap always
unsigned int disable_filter_search_var_thresh;
// These bit masks allow you to enable or disable intra modes for each
// transform size separately.
int intra_y_mode_mask[TX_SIZES];
int intra_uv_mode_mask[TX_SIZES];
// These bit masks allow you to enable or disable intra modes for each
// prediction block size separately.
int intra_y_mode_bsize_mask[BLOCK_SIZES];
// This variable enables an early break out of mode testing if the model for
// rd built from the prediction signal indicates a value that's much
// higher than the best rd we've seen so far.
int use_rd_breakout;
// This enables us to use an estimate for intra rd based on dc mode rather
// than choosing an actual uv mode in the stage of encoding before the actual
// final encode.
int use_uv_intra_rd_estimate;
// This feature controls how the loop filter level is determined.
LPF_PICK_METHOD lpf_pick;
// This feature limits the number of coefficients updates we actually do
// by only looking at counts from 1/2 the bands.
FAST_COEFF_UPDATE use_fast_coef_updates;
// This flag controls the use of non-RD mode decision.
int use_nonrd_pick_mode;
// A binary mask indicating if NEARESTMV, NEARMV, ZEROMV, NEWMV
// modes are used in order from LSB to MSB for each BLOCK_SIZE.
int inter_mode_mask[BLOCK_SIZES];
// This feature controls whether we do the expensive context update and
// calculation in the rd coefficient costing loop.
int use_fast_coef_costing;
// This feature controls the tolerence vs target used in deciding whether to
// recode a frame. It has no meaning if recode is disabled.
int recode_tolerance;
// This variable controls the maximum block size where intra blocks can be
// used in inter frames.
// TODO(aconverse): Fold this into one of the other many mode skips
BLOCK_SIZE max_intra_bsize;
// The frequency that we check if SOURCE_VAR_BASED_PARTITION or
// FIXED_PARTITION search type should be used.
int search_type_check_frequency;
// When partition is pre-set, the inter prediction result from pick_inter_mode
// can be reused in final block encoding process. It is enabled only for real-
// time mode speed 6.
int reuse_inter_pred_sby;
// This variable sets the encode_breakout threshold. Currently, it is only
// enabled in real time mode.
int encode_breakout_thresh;
// default interp filter choice
INTERP_FILTER default_interp_filter;
// Early termination in transform size search, which only applies while
// tx_size_search_method is USE_FULL_RD.
int tx_size_search_breakout;
// 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;
// Partition search early breakout thresholds.
int64_t partition_search_breakout_dist_thr;
int partition_search_breakout_rate_thr;
// Allow skipping partition search for still image frame
int allow_partition_search_skip;
} SPEED_FEATURES;
struct VP9_COMP;
void vp9_set_speed_features_framesize_independent(struct VP9_COMP *cpi);
void vp9_set_speed_features_framesize_dependent(struct VP9_COMP *cpi);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // VP9_ENCODER_VP9_SPEED_FEATURES_H_

View file

@ -0,0 +1,96 @@
/*
* Copyright (c) 2014 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.
*/
#ifndef VP9_ENCODER_VP9_SSIM_H_
#define VP9_ENCODER_VP9_SSIM_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "vpx_scale/yv12config.h"
// metrics used for calculating ssim, ssim2, dssim, and ssimc
typedef struct {
// source sum ( over 8x8 region )
uint64_t sum_s;
// reference sum (over 8x8 region )
uint64_t sum_r;
// source sum squared ( over 8x8 region )
uint64_t sum_sq_s;
// reference sum squared (over 8x8 region )
uint64_t sum_sq_r;
// sum of source times reference (over 8x8 region)
uint64_t sum_sxr;
// calculated ssim score between source and reference
double ssim;
} Ssimv;
// metrics collected on a frame basis
typedef struct {
// ssim consistency error metric ( see code for explanation )
double ssimc;
// standard ssim
double ssim;
// revised ssim ( see code for explanation)
double ssim2;
// ssim restated as an error metric like sse
double dssim;
// dssim converted to decibels
double dssimd;
// ssimc converted to decibels
double ssimcd;
} Metrics;
double vp9_get_ssim_metrics(uint8_t *img1, int img1_pitch, uint8_t *img2,
int img2_pitch, int width, int height, Ssimv *sv2,
Metrics *m, int do_inconsistency);
double vp9_calc_ssim(YV12_BUFFER_CONFIG *source, YV12_BUFFER_CONFIG *dest,
double *weight);
double vp9_calc_ssimg(YV12_BUFFER_CONFIG *source, YV12_BUFFER_CONFIG *dest,
double *ssim_y, double *ssim_u, double *ssim_v);
double vp9_calc_fastssim(YV12_BUFFER_CONFIG *source, YV12_BUFFER_CONFIG *dest,
double *ssim_y, double *ssim_u, double *ssim_v);
double vp9_psnrhvs(YV12_BUFFER_CONFIG *source, YV12_BUFFER_CONFIG *dest,
double *ssim_y, double *ssim_u, double *ssim_v);
#if CONFIG_VP9_HIGHBITDEPTH
double vp9_highbd_calc_ssim(YV12_BUFFER_CONFIG *source,
YV12_BUFFER_CONFIG *dest,
double *weight,
unsigned int bd);
double vp9_highbd_calc_ssimg(YV12_BUFFER_CONFIG *source,
YV12_BUFFER_CONFIG *dest,
double *ssim_y,
double *ssim_u,
double *ssim_v,
unsigned int bd);
#endif // CONFIG_VP9_HIGHBITDEPTH
#ifdef __cplusplus
} // extern "C"
#endif
#endif // VP9_ENCODER_VP9_SSIM_H_

View file

@ -0,0 +1,214 @@
/*
* Copyright (c) 2013 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 "vp9/common/vp9_common.h"
#include "vp9/common/vp9_entropy.h"
#include "vp9/encoder/vp9_cost.h"
#include "vp9/encoder/vp9_subexp.h"
#include "vp9/encoder/vp9_writer.h"
#define vp9_cost_upd256 ((int)(vp9_cost_one(upd) - vp9_cost_zero(upd)))
static const int update_bits[255] = {
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 0,
};
static int recenter_nonneg(int v, int m) {
if (v > (m << 1))
return v;
else if (v >= m)
return ((v - m) << 1);
else
return ((m - v) << 1) - 1;
}
static int remap_prob(int v, int m) {
int i;
static const int map_table[MAX_PROB - 1] = {
// generated by:
// map_table[j] = split_index(j, MAX_PROB - 1, MODULUS_PARAM);
20, 21, 22, 23, 24, 25, 0, 26, 27, 28, 29, 30, 31, 32, 33,
34, 35, 36, 37, 1, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 2, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
3, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 4, 74,
75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 5, 86, 87, 88,
89, 90, 91, 92, 93, 94, 95, 96, 97, 6, 98, 99, 100, 101, 102,
103, 104, 105, 106, 107, 108, 109, 7, 110, 111, 112, 113, 114, 115, 116,
117, 118, 119, 120, 121, 8, 122, 123, 124, 125, 126, 127, 128, 129, 130,
131, 132, 133, 9, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144,
145, 10, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 11,
158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 12, 170, 171,
172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 13, 182, 183, 184, 185,
186, 187, 188, 189, 190, 191, 192, 193, 14, 194, 195, 196, 197, 198, 199,
200, 201, 202, 203, 204, 205, 15, 206, 207, 208, 209, 210, 211, 212, 213,
214, 215, 216, 217, 16, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227,
228, 229, 17, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241,
18, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 19,
};
v--;
m--;
if ((m << 1) <= MAX_PROB)
i = recenter_nonneg(v, m) - 1;
else
i = recenter_nonneg(MAX_PROB - 1 - v, MAX_PROB - 1 - m) - 1;
i = map_table[i];
return i;
}
static int prob_diff_update_cost(vp9_prob newp, vp9_prob oldp) {
int delp = remap_prob(newp, oldp);
return update_bits[delp] * 256;
}
static void encode_uniform(vp9_writer *w, int v) {
const int l = 8;
const int m = (1 << l) - 191;
if (v < m) {
vp9_write_literal(w, v, l - 1);
} else {
vp9_write_literal(w, m + ((v - m) >> 1), l - 1);
vp9_write_literal(w, (v - m) & 1, 1);
}
}
static INLINE int write_bit_gte(vp9_writer *w, int word, int test) {
vp9_write_literal(w, word >= test, 1);
return word >= test;
}
static void encode_term_subexp(vp9_writer *w, int word) {
if (!write_bit_gte(w, word, 16)) {
vp9_write_literal(w, word, 4);
} else if (!write_bit_gte(w, word, 32)) {
vp9_write_literal(w, word - 16, 4);
} else if (!write_bit_gte(w, word, 64)) {
vp9_write_literal(w, word - 32, 5);
} else {
encode_uniform(w, word - 64);
}
}
void vp9_write_prob_diff_update(vp9_writer *w, vp9_prob newp, vp9_prob oldp) {
const int delp = remap_prob(newp, oldp);
encode_term_subexp(w, delp);
}
int vp9_prob_diff_update_savings_search(const unsigned int *ct,
vp9_prob oldp, vp9_prob *bestp,
vp9_prob upd) {
const int old_b = cost_branch256(ct, oldp);
int bestsavings = 0;
vp9_prob newp, bestnewp = oldp;
const int step = *bestp > oldp ? -1 : 1;
for (newp = *bestp; newp != oldp; newp += step) {
const int new_b = cost_branch256(ct, newp);
const int update_b = prob_diff_update_cost(newp, oldp) + vp9_cost_upd256;
const int savings = old_b - new_b - update_b;
if (savings > bestsavings) {
bestsavings = savings;
bestnewp = newp;
}
}
*bestp = bestnewp;
return bestsavings;
}
int vp9_prob_diff_update_savings_search_model(const unsigned int *ct,
const vp9_prob *oldp,
vp9_prob *bestp,
vp9_prob upd,
int stepsize) {
int i, old_b, new_b, update_b, savings, bestsavings, step;
int newp;
vp9_prob bestnewp, newplist[ENTROPY_NODES], oldplist[ENTROPY_NODES];
vp9_model_to_full_probs(oldp, oldplist);
memcpy(newplist, oldp, sizeof(vp9_prob) * UNCONSTRAINED_NODES);
for (i = UNCONSTRAINED_NODES, old_b = 0; i < ENTROPY_NODES; ++i)
old_b += cost_branch256(ct + 2 * i, oldplist[i]);
old_b += cost_branch256(ct + 2 * PIVOT_NODE, oldplist[PIVOT_NODE]);
bestsavings = 0;
bestnewp = oldp[PIVOT_NODE];
if (*bestp > oldp[PIVOT_NODE]) {
step = -stepsize;
for (newp = *bestp; newp > oldp[PIVOT_NODE]; newp += step) {
if (newp < 1 || newp > 255)
continue;
newplist[PIVOT_NODE] = newp;
vp9_model_to_full_probs(newplist, newplist);
for (i = UNCONSTRAINED_NODES, new_b = 0; i < ENTROPY_NODES; ++i)
new_b += cost_branch256(ct + 2 * i, newplist[i]);
new_b += cost_branch256(ct + 2 * PIVOT_NODE, newplist[PIVOT_NODE]);
update_b = prob_diff_update_cost(newp, oldp[PIVOT_NODE]) +
vp9_cost_upd256;
savings = old_b - new_b - update_b;
if (savings > bestsavings) {
bestsavings = savings;
bestnewp = newp;
}
}
} else {
step = stepsize;
for (newp = *bestp; newp < oldp[PIVOT_NODE]; newp += step) {
if (newp < 1 || newp > 255)
continue;
newplist[PIVOT_NODE] = newp;
vp9_model_to_full_probs(newplist, newplist);
for (i = UNCONSTRAINED_NODES, new_b = 0; i < ENTROPY_NODES; ++i)
new_b += cost_branch256(ct + 2 * i, newplist[i]);
new_b += cost_branch256(ct + 2 * PIVOT_NODE, newplist[PIVOT_NODE]);
update_b = prob_diff_update_cost(newp, oldp[PIVOT_NODE]) +
vp9_cost_upd256;
savings = old_b - new_b - update_b;
if (savings > bestsavings) {
bestsavings = savings;
bestnewp = newp;
}
}
}
*bestp = bestnewp;
return bestsavings;
}
void vp9_cond_prob_diff_update(vp9_writer *w, vp9_prob *oldp,
const unsigned int ct[2]) {
const vp9_prob upd = DIFF_UPDATE_PROB;
vp9_prob newp = get_binary_prob(ct[0], ct[1]);
const int savings = vp9_prob_diff_update_savings_search(ct, *oldp, &newp,
upd);
assert(newp >= 1);
if (savings > 0) {
vp9_write(w, 1, upd);
vp9_write_prob_diff_update(w, newp, *oldp);
*oldp = newp;
} else {
vp9_write(w, 0, upd);
}
}

View file

@ -0,0 +1,44 @@
/*
* Copyright (c) 2013 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.
*/
#ifndef VP9_ENCODER_VP9_SUBEXP_H_
#define VP9_ENCODER_VP9_SUBEXP_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "vp9/common/vp9_prob.h"
struct vp9_writer;
void vp9_write_prob_diff_update(struct vp9_writer *w,
vp9_prob newp, vp9_prob oldp);
void vp9_cond_prob_diff_update(struct vp9_writer *w, vp9_prob *oldp,
const unsigned int ct[2]);
int vp9_prob_diff_update_savings_search(const unsigned int *ct,
vp9_prob oldp, vp9_prob *bestp,
vp9_prob upd);
int vp9_prob_diff_update_savings_search_model(const unsigned int *ct,
const vp9_prob *oldp,
vp9_prob *bestp,
vp9_prob upd,
int stepsize);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // VP9_ENCODER_VP9_SUBEXP_H_

View file

@ -0,0 +1,646 @@
/*
* Copyright (c) 2014 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 <math.h>
#include "vp9/encoder/vp9_encoder.h"
#include "vp9/encoder/vp9_svc_layercontext.h"
#include "vp9/encoder/vp9_extend.h"
#define SMALL_FRAME_FB_IDX 7
#define SMALL_FRAME_WIDTH 16
#define SMALL_FRAME_HEIGHT 16
void vp9_init_layer_context(VP9_COMP *const cpi) {
SVC *const svc = &cpi->svc;
const VP9EncoderConfig *const oxcf = &cpi->oxcf;
int sl, tl;
int alt_ref_idx = svc->number_spatial_layers;
svc->spatial_layer_id = 0;
svc->temporal_layer_id = 0;
if (cpi->oxcf.error_resilient_mode == 0 && cpi->oxcf.pass == 2) {
if (vp9_realloc_frame_buffer(&cpi->svc.empty_frame.img,
SMALL_FRAME_WIDTH, SMALL_FRAME_HEIGHT,
cpi->common.subsampling_x,
cpi->common.subsampling_y,
#if CONFIG_VP9_HIGHBITDEPTH
cpi->common.use_highbitdepth,
#endif
VP9_ENC_BORDER_IN_PIXELS,
cpi->common.byte_alignment,
NULL, NULL, NULL))
vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR,
"Failed to allocate empty frame for multiple frame "
"contexts");
memset(cpi->svc.empty_frame.img.buffer_alloc, 0x80,
cpi->svc.empty_frame.img.buffer_alloc_sz);
}
for (sl = 0; sl < oxcf->ss_number_layers; ++sl) {
for (tl = 0; tl < oxcf->ts_number_layers; ++tl) {
int layer = LAYER_IDS_TO_IDX(sl, tl, oxcf->ts_number_layers);
LAYER_CONTEXT *const lc = &svc->layer_context[layer];
RATE_CONTROL *const lrc = &lc->rc;
int i;
lc->current_video_frame_in_layer = 0;
lc->layer_size = 0;
lc->frames_from_key_frame = 0;
lc->last_frame_type = FRAME_TYPES;
lrc->ni_av_qi = oxcf->worst_allowed_q;
lrc->total_actual_bits = 0;
lrc->total_target_vs_actual = 0;
lrc->ni_tot_qi = 0;
lrc->tot_q = 0.0;
lrc->avg_q = 0.0;
lrc->ni_frames = 0;
lrc->decimation_count = 0;
lrc->decimation_factor = 0;
for (i = 0; i < RATE_FACTOR_LEVELS; ++i) {
lrc->rate_correction_factors[i] = 1.0;
}
if (cpi->oxcf.rc_mode == VPX_CBR) {
lc->target_bandwidth = oxcf->layer_target_bitrate[layer];
lrc->last_q[INTER_FRAME] = oxcf->worst_allowed_q;
lrc->avg_frame_qindex[INTER_FRAME] = oxcf->worst_allowed_q;
lrc->avg_frame_qindex[KEY_FRAME] = oxcf->worst_allowed_q;
} else {
lc->target_bandwidth = oxcf->layer_target_bitrate[layer];
lrc->last_q[KEY_FRAME] = oxcf->best_allowed_q;
lrc->last_q[INTER_FRAME] = oxcf->best_allowed_q;
lrc->avg_frame_qindex[KEY_FRAME] = (oxcf->worst_allowed_q +
oxcf->best_allowed_q) / 2;
lrc->avg_frame_qindex[INTER_FRAME] = (oxcf->worst_allowed_q +
oxcf->best_allowed_q) / 2;
if (oxcf->ss_enable_auto_arf[sl])
lc->alt_ref_idx = alt_ref_idx++;
else
lc->alt_ref_idx = INVALID_IDX;
lc->gold_ref_idx = INVALID_IDX;
}
lrc->buffer_level = oxcf->starting_buffer_level_ms *
lc->target_bandwidth / 1000;
lrc->bits_off_target = lrc->buffer_level;
}
}
// Still have extra buffer for base layer golden frame
if (!(svc->number_temporal_layers > 1 && cpi->oxcf.rc_mode == VPX_CBR)
&& alt_ref_idx < REF_FRAMES)
svc->layer_context[0].gold_ref_idx = alt_ref_idx;
}
// Update the layer context from a change_config() call.
void vp9_update_layer_context_change_config(VP9_COMP *const cpi,
const int target_bandwidth) {
SVC *const svc = &cpi->svc;
const VP9EncoderConfig *const oxcf = &cpi->oxcf;
const RATE_CONTROL *const rc = &cpi->rc;
int sl, tl, layer = 0, spatial_layer_target;
float bitrate_alloc = 1.0;
if (svc->temporal_layering_mode != VP9E_TEMPORAL_LAYERING_MODE_NOLAYERING) {
for (sl = 0; sl < oxcf->ss_number_layers; ++sl) {
spatial_layer_target = 0;
for (tl = 0; tl < oxcf->ts_number_layers; ++tl) {
layer = LAYER_IDS_TO_IDX(sl, tl, oxcf->ts_number_layers);
svc->layer_context[layer].target_bandwidth =
oxcf->layer_target_bitrate[layer];
}
layer = LAYER_IDS_TO_IDX(sl, ((oxcf->ts_number_layers - 1) < 0 ?
0 : (oxcf->ts_number_layers - 1)), oxcf->ts_number_layers);
spatial_layer_target =
svc->layer_context[layer].target_bandwidth =
oxcf->layer_target_bitrate[layer];
for (tl = 0; tl < oxcf->ts_number_layers; ++tl) {
LAYER_CONTEXT *const lc =
&svc->layer_context[sl * oxcf->ts_number_layers + tl];
RATE_CONTROL *const lrc = &lc->rc;
lc->spatial_layer_target_bandwidth = spatial_layer_target;
bitrate_alloc = (float)lc->target_bandwidth / spatial_layer_target;
lrc->starting_buffer_level =
(int64_t)(rc->starting_buffer_level * bitrate_alloc);
lrc->optimal_buffer_level =
(int64_t)(rc->optimal_buffer_level * bitrate_alloc);
lrc->maximum_buffer_size =
(int64_t)(rc->maximum_buffer_size * bitrate_alloc);
lrc->bits_off_target =
MIN(lrc->bits_off_target, lrc->maximum_buffer_size);
lrc->buffer_level = MIN(lrc->buffer_level, lrc->maximum_buffer_size);
lc->framerate = cpi->framerate / oxcf->ts_rate_decimator[tl];
lrc->avg_frame_bandwidth = (int)(lc->target_bandwidth / lc->framerate);
lrc->max_frame_bandwidth = rc->max_frame_bandwidth;
lrc->worst_quality = rc->worst_quality;
lrc->best_quality = rc->best_quality;
}
}
} else {
int layer_end;
float bitrate_alloc = 1.0;
if (svc->number_temporal_layers > 1 && cpi->oxcf.rc_mode == VPX_CBR) {
layer_end = svc->number_temporal_layers;
} else {
layer_end = svc->number_spatial_layers;
}
for (layer = 0; layer < layer_end; ++layer) {
LAYER_CONTEXT *const lc = &svc->layer_context[layer];
RATE_CONTROL *const lrc = &lc->rc;
lc->target_bandwidth = oxcf->layer_target_bitrate[layer];
bitrate_alloc = (float)lc->target_bandwidth / target_bandwidth;
// Update buffer-related quantities.
lrc->starting_buffer_level =
(int64_t)(rc->starting_buffer_level * bitrate_alloc);
lrc->optimal_buffer_level =
(int64_t)(rc->optimal_buffer_level * bitrate_alloc);
lrc->maximum_buffer_size =
(int64_t)(rc->maximum_buffer_size * bitrate_alloc);
lrc->bits_off_target = MIN(lrc->bits_off_target,
lrc->maximum_buffer_size);
lrc->buffer_level = MIN(lrc->buffer_level, lrc->maximum_buffer_size);
// Update framerate-related quantities.
if (svc->number_temporal_layers > 1 && cpi->oxcf.rc_mode == VPX_CBR) {
lc->framerate = cpi->framerate / oxcf->ts_rate_decimator[layer];
} else {
lc->framerate = cpi->framerate;
}
lrc->avg_frame_bandwidth = (int)(lc->target_bandwidth / lc->framerate);
lrc->max_frame_bandwidth = rc->max_frame_bandwidth;
// Update qp-related quantities.
lrc->worst_quality = rc->worst_quality;
lrc->best_quality = rc->best_quality;
}
}
}
static LAYER_CONTEXT *get_layer_context(VP9_COMP *const cpi) {
if (is_one_pass_cbr_svc(cpi))
return &cpi->svc.layer_context[cpi->svc.spatial_layer_id *
cpi->svc.number_temporal_layers + cpi->svc.temporal_layer_id];
else
return (cpi->svc.number_temporal_layers > 1 &&
cpi->oxcf.rc_mode == VPX_CBR) ?
&cpi->svc.layer_context[cpi->svc.temporal_layer_id] :
&cpi->svc.layer_context[cpi->svc.spatial_layer_id];
}
void vp9_update_temporal_layer_framerate(VP9_COMP *const cpi) {
SVC *const svc = &cpi->svc;
const VP9EncoderConfig *const oxcf = &cpi->oxcf;
LAYER_CONTEXT *const lc = get_layer_context(cpi);
RATE_CONTROL *const lrc = &lc->rc;
// Index into spatial+temporal arrays.
const int st_idx = svc->spatial_layer_id * svc->number_temporal_layers +
svc->temporal_layer_id;
const int tl = svc->temporal_layer_id;
lc->framerate = cpi->framerate / oxcf->ts_rate_decimator[tl];
lrc->avg_frame_bandwidth = (int)(lc->target_bandwidth / lc->framerate);
lrc->max_frame_bandwidth = cpi->rc.max_frame_bandwidth;
// Update the average layer frame size (non-cumulative per-frame-bw).
if (tl == 0) {
lc->avg_frame_size = lrc->avg_frame_bandwidth;
} else {
const double prev_layer_framerate =
cpi->framerate / oxcf->ts_rate_decimator[tl - 1];
const int prev_layer_target_bandwidth =
oxcf->layer_target_bitrate[st_idx - 1];
lc->avg_frame_size =
(int)((lc->target_bandwidth - prev_layer_target_bandwidth) /
(lc->framerate - prev_layer_framerate));
}
}
void vp9_update_spatial_layer_framerate(VP9_COMP *const cpi, double framerate) {
const VP9EncoderConfig *const oxcf = &cpi->oxcf;
LAYER_CONTEXT *const lc = get_layer_context(cpi);
RATE_CONTROL *const lrc = &lc->rc;
lc->framerate = framerate;
lrc->avg_frame_bandwidth = (int)(lc->target_bandwidth / lc->framerate);
lrc->min_frame_bandwidth = (int)(lrc->avg_frame_bandwidth *
oxcf->two_pass_vbrmin_section / 100);
lrc->max_frame_bandwidth = (int)(((int64_t)lrc->avg_frame_bandwidth *
oxcf->two_pass_vbrmax_section) / 100);
vp9_rc_set_gf_interval_range(cpi, lrc);
}
void vp9_restore_layer_context(VP9_COMP *const cpi) {
LAYER_CONTEXT *const lc = get_layer_context(cpi);
const int old_frame_since_key = cpi->rc.frames_since_key;
const int old_frame_to_key = cpi->rc.frames_to_key;
cpi->rc = lc->rc;
cpi->twopass = lc->twopass;
cpi->oxcf.target_bandwidth = lc->target_bandwidth;
cpi->alt_ref_source = lc->alt_ref_source;
// Reset the frames_since_key and frames_to_key counters to their values
// before the layer restore. Keep these defined for the stream (not layer).
if (cpi->svc.number_temporal_layers > 1) {
cpi->rc.frames_since_key = old_frame_since_key;
cpi->rc.frames_to_key = old_frame_to_key;
}
}
void vp9_save_layer_context(VP9_COMP *const cpi) {
const VP9EncoderConfig *const oxcf = &cpi->oxcf;
LAYER_CONTEXT *const lc = get_layer_context(cpi);
lc->rc = cpi->rc;
lc->twopass = cpi->twopass;
lc->target_bandwidth = (int)oxcf->target_bandwidth;
lc->alt_ref_source = cpi->alt_ref_source;
}
void vp9_init_second_pass_spatial_svc(VP9_COMP *cpi) {
SVC *const svc = &cpi->svc;
int i;
for (i = 0; i < svc->number_spatial_layers; ++i) {
TWO_PASS *const twopass = &svc->layer_context[i].twopass;
svc->spatial_layer_id = i;
vp9_init_second_pass(cpi);
twopass->total_stats.spatial_layer_id = i;
twopass->total_left_stats.spatial_layer_id = i;
}
svc->spatial_layer_id = 0;
}
void vp9_inc_frame_in_layer(VP9_COMP *const cpi) {
LAYER_CONTEXT *const lc =
&cpi->svc.layer_context[cpi->svc.spatial_layer_id *
cpi->svc.number_temporal_layers];
++lc->current_video_frame_in_layer;
++lc->frames_from_key_frame;
}
int vp9_is_upper_layer_key_frame(const VP9_COMP *const cpi) {
return is_two_pass_svc(cpi) &&
cpi->svc.spatial_layer_id > 0 &&
cpi->svc.layer_context[cpi->svc.spatial_layer_id *
cpi->svc.number_temporal_layers +
cpi->svc.temporal_layer_id].is_key_frame;
}
static void get_layer_resolution(const int width_org, const int height_org,
const int num, const int den,
int *width_out, int *height_out) {
int w, h;
if (width_out == NULL || height_out == NULL || den == 0)
return;
w = width_org * num / den;
h = height_org * num / den;
// make height and width even to make chrome player happy
w += w % 2;
h += h % 2;
*width_out = w;
*height_out = h;
}
// The function sets proper ref_frame_flags, buffer indices, and buffer update
// variables for temporal layering mode 3 - that does 0-2-1-2 temporal layering
// scheme.
static void set_flags_and_fb_idx_for_temporal_mode3(VP9_COMP *const cpi) {
int frame_num_within_temporal_struct = 0;
int spatial_id, temporal_id;
spatial_id = cpi->svc.spatial_layer_id = cpi->svc.spatial_layer_to_encode;
frame_num_within_temporal_struct =
cpi->svc.layer_context[cpi->svc.spatial_layer_id *
cpi->svc.number_temporal_layers].current_video_frame_in_layer % 4;
temporal_id = cpi->svc.temporal_layer_id =
(frame_num_within_temporal_struct & 1) ? 2 :
(frame_num_within_temporal_struct >> 1);
cpi->ext_refresh_last_frame = cpi->ext_refresh_golden_frame =
cpi->ext_refresh_alt_ref_frame = 0;
if (!temporal_id) {
cpi->ext_refresh_frame_flags_pending = 1;
cpi->ext_refresh_last_frame = 1;
if (!spatial_id) {
cpi->ref_frame_flags = VP9_LAST_FLAG;
} else if (cpi->svc.layer_context[temporal_id].is_key_frame) {
// base layer is a key frame.
cpi->ref_frame_flags = VP9_GOLD_FLAG;
} else {
cpi->ref_frame_flags = VP9_LAST_FLAG | VP9_GOLD_FLAG;
}
} else if (temporal_id == 1) {
cpi->ext_refresh_frame_flags_pending = 1;
cpi->ext_refresh_alt_ref_frame = 1;
if (!spatial_id) {
cpi->ref_frame_flags = VP9_LAST_FLAG;
} else {
cpi->ref_frame_flags = VP9_LAST_FLAG | VP9_GOLD_FLAG;
}
} else {
if (frame_num_within_temporal_struct == 1) {
// the first tl2 picture
if (!spatial_id) {
cpi->ext_refresh_frame_flags_pending = 1;
cpi->ext_refresh_alt_ref_frame = 1;
cpi->ref_frame_flags = VP9_LAST_FLAG;
} else if (spatial_id < cpi->svc.number_spatial_layers - 1) {
cpi->ext_refresh_frame_flags_pending = 1;
cpi->ext_refresh_alt_ref_frame = 1;
cpi->ref_frame_flags = VP9_LAST_FLAG | VP9_GOLD_FLAG;
} else { // Top layer
cpi->ext_refresh_frame_flags_pending = 0;
cpi->ref_frame_flags = VP9_LAST_FLAG | VP9_GOLD_FLAG;
}
} else {
// The second tl2 picture
if (!spatial_id) {
cpi->ext_refresh_frame_flags_pending = 1;
cpi->ref_frame_flags = VP9_LAST_FLAG;
cpi->ext_refresh_last_frame = 1;
} else if (spatial_id < cpi->svc.number_spatial_layers - 1) {
cpi->ext_refresh_frame_flags_pending = 1;
cpi->ref_frame_flags = VP9_LAST_FLAG | VP9_GOLD_FLAG;
cpi->ext_refresh_last_frame = 1;
} else { // top layer
cpi->ext_refresh_frame_flags_pending = 0;
cpi->ref_frame_flags = VP9_LAST_FLAG | VP9_GOLD_FLAG;
}
}
}
if (temporal_id == 0) {
cpi->lst_fb_idx = spatial_id;
if (spatial_id)
cpi->gld_fb_idx = spatial_id - 1;
else
cpi->gld_fb_idx = 0;
cpi->alt_fb_idx = 0;
} else if (temporal_id == 1) {
cpi->lst_fb_idx = spatial_id;
cpi->gld_fb_idx = cpi->svc.number_spatial_layers + spatial_id - 1;
cpi->alt_fb_idx = cpi->svc.number_spatial_layers + spatial_id;
} else if (frame_num_within_temporal_struct == 1) {
cpi->lst_fb_idx = spatial_id;
cpi->gld_fb_idx = cpi->svc.number_spatial_layers + spatial_id - 1;
cpi->alt_fb_idx = cpi->svc.number_spatial_layers + spatial_id;
} else {
cpi->lst_fb_idx = cpi->svc.number_spatial_layers + spatial_id;
cpi->gld_fb_idx = cpi->svc.number_spatial_layers + spatial_id - 1;
cpi->alt_fb_idx = 0;
}
}
// The function sets proper ref_frame_flags, buffer indices, and buffer update
// variables for temporal layering mode 2 - that does 0-1-0-1 temporal layering
// scheme.
static void set_flags_and_fb_idx_for_temporal_mode2(VP9_COMP *const cpi) {
int spatial_id, temporal_id;
spatial_id = cpi->svc.spatial_layer_id = cpi->svc.spatial_layer_to_encode;
temporal_id = cpi->svc.temporal_layer_id =
cpi->svc.layer_context[cpi->svc.spatial_layer_id *
cpi->svc.number_temporal_layers].current_video_frame_in_layer & 1;
cpi->ext_refresh_last_frame = cpi->ext_refresh_golden_frame =
cpi->ext_refresh_alt_ref_frame = 0;
if (!temporal_id) {
cpi->ext_refresh_frame_flags_pending = 1;
cpi->ext_refresh_last_frame = 1;
if (!spatial_id) {
cpi->ref_frame_flags = VP9_LAST_FLAG;
} else if (cpi->svc.layer_context[temporal_id].is_key_frame) {
// base layer is a key frame.
cpi->ref_frame_flags = VP9_GOLD_FLAG;
} else {
cpi->ref_frame_flags = VP9_LAST_FLAG | VP9_GOLD_FLAG;
}
} else if (temporal_id == 1) {
cpi->ext_refresh_frame_flags_pending = 1;
cpi->ext_refresh_alt_ref_frame = 1;
if (!spatial_id) {
cpi->ref_frame_flags = VP9_LAST_FLAG;
} else {
cpi->ref_frame_flags = VP9_LAST_FLAG | VP9_GOLD_FLAG;
}
}
if (temporal_id == 0) {
cpi->lst_fb_idx = spatial_id;
if (spatial_id)
cpi->gld_fb_idx = spatial_id - 1;
else
cpi->gld_fb_idx = 0;
cpi->alt_fb_idx = 0;
} else if (temporal_id == 1) {
cpi->lst_fb_idx = spatial_id;
cpi->gld_fb_idx = cpi->svc.number_spatial_layers + spatial_id - 1;
cpi->alt_fb_idx = cpi->svc.number_spatial_layers + spatial_id;
}
}
// The function sets proper ref_frame_flags, buffer indices, and buffer update
// variables for temporal layering mode 0 - that has no temporal layering.
static void set_flags_and_fb_idx_for_temporal_mode_noLayering(
VP9_COMP *const cpi) {
int spatial_id;
spatial_id = cpi->svc.spatial_layer_id = cpi->svc.spatial_layer_to_encode;
cpi->ext_refresh_last_frame =
cpi->ext_refresh_golden_frame = cpi->ext_refresh_alt_ref_frame = 0;
cpi->ext_refresh_frame_flags_pending = 1;
cpi->ext_refresh_last_frame = 1;
if (!spatial_id) {
cpi->ref_frame_flags = VP9_LAST_FLAG;
} else if (cpi->svc.layer_context[0].is_key_frame) {
cpi->ref_frame_flags = VP9_GOLD_FLAG;
} else {
cpi->ref_frame_flags = VP9_LAST_FLAG | VP9_GOLD_FLAG;
}
cpi->lst_fb_idx = spatial_id;
if (spatial_id)
cpi->gld_fb_idx = spatial_id - 1;
else
cpi->gld_fb_idx = 0;
}
int vp9_one_pass_cbr_svc_start_layer(VP9_COMP *const cpi) {
int width = 0, height = 0;
LAYER_CONTEXT *lc = NULL;
if (cpi->svc.temporal_layering_mode == VP9E_TEMPORAL_LAYERING_MODE_0212) {
set_flags_and_fb_idx_for_temporal_mode3(cpi);
} else if (cpi->svc.temporal_layering_mode ==
VP9E_TEMPORAL_LAYERING_MODE_NOLAYERING) {
set_flags_and_fb_idx_for_temporal_mode_noLayering(cpi);
} else if (cpi->svc.temporal_layering_mode ==
VP9E_TEMPORAL_LAYERING_MODE_0101) {
set_flags_and_fb_idx_for_temporal_mode2(cpi);
} else if (cpi->svc.temporal_layering_mode ==
VP9E_TEMPORAL_LAYERING_MODE_BYPASS) {
// VP9E_TEMPORAL_LAYERING_MODE_BYPASS :
// if the code goes here, it means the encoder will be relying on the
// flags from outside for layering.
// However, since when spatial+temporal layering is used, the buffer indices
// cannot be derived automatically, the bypass mode will only work when the
// number of spatial layers equals 1.
assert(cpi->svc.number_spatial_layers == 1);
}
lc = &cpi->svc.layer_context[cpi->svc.spatial_layer_id *
cpi->svc.number_temporal_layers +
cpi->svc.temporal_layer_id];
get_layer_resolution(cpi->oxcf.width, cpi->oxcf.height,
lc->scaling_factor_num, lc->scaling_factor_den,
&width, &height);
if (vp9_set_size_literal(cpi, width, height) != 0)
return VPX_CODEC_INVALID_PARAM;
return 0;
}
#if CONFIG_SPATIAL_SVC
int vp9_svc_start_frame(VP9_COMP *const cpi) {
int width = 0, height = 0;
LAYER_CONTEXT *lc;
struct lookahead_entry *buf;
int count = 1 << (cpi->svc.number_temporal_layers - 1);
cpi->svc.spatial_layer_id = cpi->svc.spatial_layer_to_encode;
lc = &cpi->svc.layer_context[cpi->svc.spatial_layer_id];
cpi->svc.temporal_layer_id = 0;
while ((lc->current_video_frame_in_layer % count) != 0) {
++cpi->svc.temporal_layer_id;
count >>= 1;
}
cpi->ref_frame_flags = VP9_ALT_FLAG | VP9_GOLD_FLAG | VP9_LAST_FLAG;
cpi->lst_fb_idx = cpi->svc.spatial_layer_id;
if (cpi->svc.spatial_layer_id == 0)
cpi->gld_fb_idx = (lc->gold_ref_idx >= 0) ?
lc->gold_ref_idx : cpi->lst_fb_idx;
else
cpi->gld_fb_idx = cpi->svc.spatial_layer_id - 1;
if (lc->current_video_frame_in_layer == 0) {
if (cpi->svc.spatial_layer_id >= 2) {
cpi->alt_fb_idx = cpi->svc.spatial_layer_id - 2;
} else {
cpi->alt_fb_idx = cpi->lst_fb_idx;
cpi->ref_frame_flags &= (~VP9_LAST_FLAG & ~VP9_ALT_FLAG);
}
} else {
if (cpi->oxcf.ss_enable_auto_arf[cpi->svc.spatial_layer_id]) {
cpi->alt_fb_idx = lc->alt_ref_idx;
if (!lc->has_alt_frame)
cpi->ref_frame_flags &= (~VP9_ALT_FLAG);
} else {
// Find a proper alt_fb_idx for layers that don't have alt ref frame
if (cpi->svc.spatial_layer_id == 0) {
cpi->alt_fb_idx = cpi->lst_fb_idx;
} else {
LAYER_CONTEXT *lc_lower =
&cpi->svc.layer_context[cpi->svc.spatial_layer_id - 1];
if (cpi->oxcf.ss_enable_auto_arf[cpi->svc.spatial_layer_id - 1] &&
lc_lower->alt_ref_source != NULL)
cpi->alt_fb_idx = lc_lower->alt_ref_idx;
else if (cpi->svc.spatial_layer_id >= 2)
cpi->alt_fb_idx = cpi->svc.spatial_layer_id - 2;
else
cpi->alt_fb_idx = cpi->lst_fb_idx;
}
}
}
get_layer_resolution(cpi->oxcf.width, cpi->oxcf.height,
lc->scaling_factor_num, lc->scaling_factor_den,
&width, &height);
// Workaround for multiple frame contexts. In some frames we can't use prev_mi
// since its previous frame could be changed during decoding time. The idea is
// we put a empty invisible frame in front of them, then we will not use
// prev_mi when encoding these frames.
buf = vp9_lookahead_peek(cpi->lookahead, 0);
if (cpi->oxcf.error_resilient_mode == 0 && cpi->oxcf.pass == 2 &&
cpi->svc.encode_empty_frame_state == NEED_TO_ENCODE &&
lc->rc.frames_to_key != 0 &&
!(buf != NULL && (buf->flags & VPX_EFLAG_FORCE_KF))) {
if ((cpi->svc.number_temporal_layers > 1 &&
cpi->svc.temporal_layer_id < cpi->svc.number_temporal_layers - 1) ||
(cpi->svc.number_spatial_layers > 1 &&
cpi->svc.spatial_layer_id == 0)) {
struct lookahead_entry *buf = vp9_lookahead_peek(cpi->lookahead, 0);
if (buf != NULL) {
cpi->svc.empty_frame.ts_start = buf->ts_start;
cpi->svc.empty_frame.ts_end = buf->ts_end;
cpi->svc.encode_empty_frame_state = ENCODING;
cpi->common.show_frame = 0;
cpi->ref_frame_flags = 0;
cpi->common.frame_type = INTER_FRAME;
cpi->lst_fb_idx =
cpi->gld_fb_idx = cpi->alt_fb_idx = SMALL_FRAME_FB_IDX;
if (cpi->svc.encode_intra_empty_frame != 0)
cpi->common.intra_only = 1;
width = SMALL_FRAME_WIDTH;
height = SMALL_FRAME_HEIGHT;
}
}
}
cpi->oxcf.worst_allowed_q = vp9_quantizer_to_qindex(lc->max_q);
cpi->oxcf.best_allowed_q = vp9_quantizer_to_qindex(lc->min_q);
vp9_change_config(cpi, &cpi->oxcf);
if (vp9_set_size_literal(cpi, width, height) != 0)
return VPX_CODEC_INVALID_PARAM;
vp9_set_high_precision_mv(cpi, 1);
cpi->alt_ref_source = get_layer_context(cpi)->alt_ref_source;
return 0;
}
#endif
struct lookahead_entry *vp9_svc_lookahead_pop(VP9_COMP *const cpi,
struct lookahead_ctx *ctx,
int drain) {
struct lookahead_entry *buf = NULL;
if (ctx->sz && (drain || ctx->sz == ctx->max_sz - MAX_PRE_FRAMES)) {
buf = vp9_lookahead_peek(ctx, 0);
if (buf != NULL) {
// Only remove the buffer when pop the highest layer.
if (cpi->svc.spatial_layer_id == cpi->svc.number_spatial_layers - 1) {
vp9_lookahead_pop(ctx, drain);
}
}
}
return buf;
}

View file

@ -0,0 +1,122 @@
/*
* Copyright (c) 2014 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.
*/
#ifndef VP9_ENCODER_VP9_SVC_LAYERCONTEXT_H_
#define VP9_ENCODER_VP9_SVC_LAYERCONTEXT_H_
#include "vpx/vpx_encoder.h"
#include "vp9/encoder/vp9_ratectrl.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
RATE_CONTROL rc;
int target_bandwidth;
int spatial_layer_target_bandwidth; // Target for the spatial layer.
double framerate;
int avg_frame_size;
int max_q;
int min_q;
int scaling_factor_num;
int scaling_factor_den;
TWO_PASS twopass;
vpx_fixed_buf_t rc_twopass_stats_in;
unsigned int current_video_frame_in_layer;
int is_key_frame;
int frames_from_key_frame;
FRAME_TYPE last_frame_type;
struct lookahead_entry *alt_ref_source;
int alt_ref_idx;
int gold_ref_idx;
int has_alt_frame;
size_t layer_size;
struct vpx_psnr_pkt psnr_pkt;
} LAYER_CONTEXT;
typedef struct {
int spatial_layer_id;
int temporal_layer_id;
int number_spatial_layers;
int number_temporal_layers;
int spatial_layer_to_encode;
// Workaround for multiple frame contexts
enum {
ENCODED = 0,
ENCODING,
NEED_TO_ENCODE
}encode_empty_frame_state;
struct lookahead_entry empty_frame;
int encode_intra_empty_frame;
// Store scaled source frames to be used for temporal filter to generate
// a alt ref frame.
YV12_BUFFER_CONFIG scaled_frames[MAX_LAG_BUFFERS];
// Layer context used for rate control in one pass temporal CBR mode or
// two pass spatial mode.
LAYER_CONTEXT layer_context[VPX_MAX_LAYERS];
// Indicates what sort of temporal layering is used.
// Currently, this only works for CBR mode.
VP9E_TEMPORAL_LAYERING_MODE temporal_layering_mode;
} SVC;
struct VP9_COMP;
// Initialize layer context data from init_config().
void vp9_init_layer_context(struct VP9_COMP *const cpi);
// Update the layer context from a change_config() call.
void vp9_update_layer_context_change_config(struct VP9_COMP *const cpi,
const int target_bandwidth);
// Prior to encoding the frame, update framerate-related quantities
// for the current temporal layer.
void vp9_update_temporal_layer_framerate(struct VP9_COMP *const cpi);
// Update framerate-related quantities for the current spatial layer.
void vp9_update_spatial_layer_framerate(struct VP9_COMP *const cpi,
double framerate);
// Prior to encoding the frame, set the layer context, for the current layer
// to be encoded, to the cpi struct.
void vp9_restore_layer_context(struct VP9_COMP *const cpi);
// Save the layer context after encoding the frame.
void vp9_save_layer_context(struct VP9_COMP *const cpi);
// Initialize second pass rc for spatial svc.
void vp9_init_second_pass_spatial_svc(struct VP9_COMP *cpi);
// Increment number of video frames in layer
void vp9_inc_frame_in_layer(struct VP9_COMP *const cpi);
// Check if current layer is key frame in spatial upper layer
int vp9_is_upper_layer_key_frame(const struct VP9_COMP *const cpi);
// Get the next source buffer to encode
struct lookahead_entry *vp9_svc_lookahead_pop(struct VP9_COMP *const cpi,
struct lookahead_ctx *ctx,
int drain);
// Start a frame and initialize svc parameters
int vp9_svc_start_frame(struct VP9_COMP *const cpi);
int vp9_one_pass_cbr_svc_start_layer(struct VP9_COMP *const cpi);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // VP9_ENCODER_VP9_SVC_LAYERCONTEXT_

View file

@ -0,0 +1,750 @@
/*
* 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 <math.h>
#include <limits.h>
#include "vp9/common/vp9_alloccommon.h"
#include "vp9/common/vp9_onyxc_int.h"
#include "vp9/common/vp9_quant_common.h"
#include "vp9/common/vp9_reconinter.h"
#include "vp9/common/vp9_systemdependent.h"
#include "vp9/encoder/vp9_extend.h"
#include "vp9/encoder/vp9_firstpass.h"
#include "vp9/encoder/vp9_mcomp.h"
#include "vp9/encoder/vp9_encoder.h"
#include "vp9/encoder/vp9_quantize.h"
#include "vp9/encoder/vp9_ratectrl.h"
#include "vp9/encoder/vp9_segmentation.h"
#include "vp9/encoder/vp9_temporal_filter.h"
#include "vpx_mem/vpx_mem.h"
#include "vpx_ports/mem.h"
#include "vpx_ports/vpx_timer.h"
#include "vpx_scale/vpx_scale.h"
static int fixed_divide[512];
static void temporal_filter_predictors_mb_c(MACROBLOCKD *xd,
uint8_t *y_mb_ptr,
uint8_t *u_mb_ptr,
uint8_t *v_mb_ptr,
int stride,
int uv_block_width,
int uv_block_height,
int mv_row,
int mv_col,
uint8_t *pred,
struct scale_factors *scale,
int x, int y) {
const int which_mv = 0;
const MV mv = { mv_row, mv_col };
const InterpKernel *const kernel =
vp9_get_interp_kernel(xd->mi[0]->mbmi.interp_filter);
enum mv_precision mv_precision_uv;
int uv_stride;
if (uv_block_width == 8) {
uv_stride = (stride + 1) >> 1;
mv_precision_uv = MV_PRECISION_Q4;
} else {
uv_stride = stride;
mv_precision_uv = MV_PRECISION_Q3;
}
#if CONFIG_VP9_HIGHBITDEPTH
if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) {
vp9_highbd_build_inter_predictor(y_mb_ptr, stride,
&pred[0], 16,
&mv,
scale,
16, 16,
which_mv,
kernel, MV_PRECISION_Q3, x, y, xd->bd);
vp9_highbd_build_inter_predictor(u_mb_ptr, uv_stride,
&pred[256], uv_block_width,
&mv,
scale,
uv_block_width, uv_block_height,
which_mv,
kernel, mv_precision_uv, x, y, xd->bd);
vp9_highbd_build_inter_predictor(v_mb_ptr, uv_stride,
&pred[512], uv_block_width,
&mv,
scale,
uv_block_width, uv_block_height,
which_mv,
kernel, mv_precision_uv, x, y, xd->bd);
return;
}
#endif // CONFIG_VP9_HIGHBITDEPTH
vp9_build_inter_predictor(y_mb_ptr, stride,
&pred[0], 16,
&mv,
scale,
16, 16,
which_mv,
kernel, MV_PRECISION_Q3, x, y);
vp9_build_inter_predictor(u_mb_ptr, uv_stride,
&pred[256], uv_block_width,
&mv,
scale,
uv_block_width, uv_block_height,
which_mv,
kernel, mv_precision_uv, x, y);
vp9_build_inter_predictor(v_mb_ptr, uv_stride,
&pred[512], uv_block_width,
&mv,
scale,
uv_block_width, uv_block_height,
which_mv,
kernel, mv_precision_uv, x, y);
}
void vp9_temporal_filter_init(void) {
int i;
fixed_divide[0] = 0;
for (i = 1; i < 512; ++i)
fixed_divide[i] = 0x80000 / i;
}
void vp9_temporal_filter_apply_c(uint8_t *frame1,
unsigned int stride,
uint8_t *frame2,
unsigned int block_width,
unsigned int block_height,
int strength,
int filter_weight,
unsigned int *accumulator,
uint16_t *count) {
unsigned int i, j, k;
int modifier;
int byte = 0;
const int rounding = strength > 0 ? 1 << (strength - 1) : 0;
for (i = 0, k = 0; i < block_height; i++) {
for (j = 0; j < block_width; j++, k++) {
int src_byte = frame1[byte];
int pixel_value = *frame2++;
modifier = src_byte - pixel_value;
// This is an integer approximation of:
// float coeff = (3.0 * modifer * modifier) / pow(2, strength);
// modifier = (int)roundf(coeff > 16 ? 0 : 16-coeff);
modifier *= modifier;
modifier *= 3;
modifier += rounding;
modifier >>= strength;
if (modifier > 16)
modifier = 16;
modifier = 16 - modifier;
modifier *= filter_weight;
count[k] += modifier;
accumulator[k] += modifier * pixel_value;
byte++;
}
byte += stride - block_width;
}
}
#if CONFIG_VP9_HIGHBITDEPTH
void vp9_highbd_temporal_filter_apply_c(uint8_t *frame1_8,
unsigned int stride,
uint8_t *frame2_8,
unsigned int block_width,
unsigned int block_height,
int strength,
int filter_weight,
unsigned int *accumulator,
uint16_t *count) {
uint16_t *frame1 = CONVERT_TO_SHORTPTR(frame1_8);
uint16_t *frame2 = CONVERT_TO_SHORTPTR(frame2_8);
unsigned int i, j, k;
int modifier;
int byte = 0;
const int rounding = strength > 0 ? 1 << (strength - 1) : 0;
for (i = 0, k = 0; i < block_height; i++) {
for (j = 0; j < block_width; j++, k++) {
int src_byte = frame1[byte];
int pixel_value = *frame2++;
modifier = src_byte - pixel_value;
// This is an integer approximation of:
// float coeff = (3.0 * modifer * modifier) / pow(2, strength);
// modifier = (int)roundf(coeff > 16 ? 0 : 16-coeff);
modifier *= modifier;
modifier *= 3;
modifier += rounding;
modifier >>= strength;
if (modifier > 16)
modifier = 16;
modifier = 16 - modifier;
modifier *= filter_weight;
count[k] += modifier;
accumulator[k] += modifier * pixel_value;
byte++;
}
byte += stride - block_width;
}
}
#endif // CONFIG_VP9_HIGHBITDEPTH
static int temporal_filter_find_matching_mb_c(VP9_COMP *cpi,
uint8_t *arf_frame_buf,
uint8_t *frame_ptr_buf,
int stride) {
MACROBLOCK *const x = &cpi->td.mb;
MACROBLOCKD *const xd = &x->e_mbd;
const MV_SPEED_FEATURES *const mv_sf = &cpi->sf.mv;
int step_param;
int sadpb = x->sadperbit16;
int bestsme = INT_MAX;
int distortion;
unsigned int sse;
int cost_list[5];
MV best_ref_mv1 = {0, 0};
MV best_ref_mv1_full; /* full-pixel value of best_ref_mv1 */
MV *ref_mv = &x->e_mbd.mi[0]->bmi[0].as_mv[0].as_mv;
// Save input state
struct buf_2d src = x->plane[0].src;
struct buf_2d pre = xd->plane[0].pre[0];
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 = arf_frame_buf;
x->plane[0].src.stride = stride;
xd->plane[0].pre[0].buf = frame_ptr_buf;
xd->plane[0].pre[0].stride = stride;
step_param = mv_sf->reduce_first_step_size;
step_param = MIN(step_param, MAX_MVSEARCH_STEPS - 2);
// Ignore mv costing by sending NULL pointer instead of cost arrays
vp9_hex_search(x, &best_ref_mv1_full, step_param, sadpb, 1,
cond_cost_list(cpi, cost_list),
&cpi->fn_ptr[BLOCK_16X16], 0, &best_ref_mv1, ref_mv);
// Ignore mv costing by sending NULL pointer instead of cost array
bestsme = cpi->find_fractional_mv_step(x, ref_mv,
&best_ref_mv1,
cpi->common.allow_high_precision_mv,
x->errorperbit,
&cpi->fn_ptr[BLOCK_16X16],
0, mv_sf->subpel_iters_per_step,
cond_cost_list(cpi, cost_list),
NULL, NULL,
&distortion, &sse, NULL, 0, 0);
// Restore input state
x->plane[0].src = src;
xd->plane[0].pre[0] = pre;
return bestsme;
}
static void temporal_filter_iterate_c(VP9_COMP *cpi,
YV12_BUFFER_CONFIG **frames,
int frame_count,
int alt_ref_index,
int strength,
struct scale_factors *scale) {
int byte;
int frame;
int mb_col, mb_row;
unsigned int filter_weight;
int mb_cols = (frames[alt_ref_index]->y_crop_width + 15) >> 4;
int mb_rows = (frames[alt_ref_index]->y_crop_height + 15) >> 4;
int mb_y_offset = 0;
int mb_uv_offset = 0;
DECLARE_ALIGNED(16, unsigned int, accumulator[16 * 16 * 3]);
DECLARE_ALIGNED(16, uint16_t, count[16 * 16 * 3]);
MACROBLOCKD *mbd = &cpi->td.mb.e_mbd;
YV12_BUFFER_CONFIG *f = frames[alt_ref_index];
uint8_t *dst1, *dst2;
#if CONFIG_VP9_HIGHBITDEPTH
DECLARE_ALIGNED(16, uint16_t, predictor16[16 * 16 * 3]);
DECLARE_ALIGNED(16, uint8_t, predictor8[16 * 16 * 3]);
uint8_t *predictor;
#else
DECLARE_ALIGNED(16, uint8_t, predictor[16 * 16 * 3]);
#endif
const int mb_uv_height = 16 >> mbd->plane[1].subsampling_y;
const int mb_uv_width = 16 >> mbd->plane[1].subsampling_x;
// Save input state
uint8_t* input_buffer[MAX_MB_PLANE];
int i;
#if CONFIG_VP9_HIGHBITDEPTH
if (mbd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) {
predictor = CONVERT_TO_BYTEPTR(predictor16);
} else {
predictor = predictor8;
}
#endif
for (i = 0; i < MAX_MB_PLANE; i++)
input_buffer[i] = mbd->plane[i].pre[0].buf;
for (mb_row = 0; mb_row < mb_rows; mb_row++) {
// Source frames are extended to 16 pixels. This is different than
// L/A/G reference frames that have a border of 32 (VP9ENCBORDERINPIXELS)
// A 6/8 tap filter is used for motion search. This requires 2 pixels
// before and 3 pixels after. So the largest Y mv on a border would
// then be 16 - VP9_INTERP_EXTEND. The UV blocks are half the size of the
// Y and therefore only extended by 8. The largest mv that a UV block
// can support is 8 - VP9_INTERP_EXTEND. A UV mv is half of a Y mv.
// (16 - VP9_INTERP_EXTEND) >> 1 which is greater than
// 8 - VP9_INTERP_EXTEND.
// To keep the mv in play for both Y and UV planes the max that it
// can be on a border is therefore 16 - (2*VP9_INTERP_EXTEND+1).
cpi->td.mb.mv_row_min = -((mb_row * 16) + (17 - 2 * VP9_INTERP_EXTEND));
cpi->td.mb.mv_row_max = ((mb_rows - 1 - mb_row) * 16)
+ (17 - 2 * VP9_INTERP_EXTEND);
for (mb_col = 0; mb_col < mb_cols; mb_col++) {
int i, j, k;
int stride;
memset(accumulator, 0, 16 * 16 * 3 * sizeof(accumulator[0]));
memset(count, 0, 16 * 16 * 3 * sizeof(count[0]));
cpi->td.mb.mv_col_min = -((mb_col * 16) + (17 - 2 * VP9_INTERP_EXTEND));
cpi->td.mb.mv_col_max = ((mb_cols - 1 - mb_col) * 16)
+ (17 - 2 * VP9_INTERP_EXTEND);
for (frame = 0; frame < frame_count; frame++) {
const int thresh_low = 10000;
const int thresh_high = 20000;
if (frames[frame] == NULL)
continue;
mbd->mi[0]->bmi[0].as_mv[0].as_mv.row = 0;
mbd->mi[0]->bmi[0].as_mv[0].as_mv.col = 0;
if (frame == alt_ref_index) {
filter_weight = 2;
} else {
// Find best match in this frame by MC
int err = temporal_filter_find_matching_mb_c(cpi,
frames[alt_ref_index]->y_buffer + mb_y_offset,
frames[frame]->y_buffer + mb_y_offset,
frames[frame]->y_stride);
// Assign higher weight to matching MB if it's error
// score is lower. If not applying MC default behavior
// is to weight all MBs equal.
filter_weight = err < thresh_low
? 2 : err < thresh_high ? 1 : 0;
}
if (filter_weight != 0) {
// Construct the predictors
temporal_filter_predictors_mb_c(mbd,
frames[frame]->y_buffer + mb_y_offset,
frames[frame]->u_buffer + mb_uv_offset,
frames[frame]->v_buffer + mb_uv_offset,
frames[frame]->y_stride,
mb_uv_width, mb_uv_height,
mbd->mi[0]->bmi[0].as_mv[0].as_mv.row,
mbd->mi[0]->bmi[0].as_mv[0].as_mv.col,
predictor, scale,
mb_col * 16, mb_row * 16);
#if CONFIG_VP9_HIGHBITDEPTH
if (mbd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) {
int adj_strength = strength + 2 * (mbd->bd - 8);
// Apply the filter (YUV)
vp9_highbd_temporal_filter_apply(f->y_buffer + mb_y_offset,
f->y_stride,
predictor, 16, 16, adj_strength,
filter_weight,
accumulator, count);
vp9_highbd_temporal_filter_apply(f->u_buffer + mb_uv_offset,
f->uv_stride, predictor + 256,
mb_uv_width, mb_uv_height,
adj_strength,
filter_weight, accumulator + 256,
count + 256);
vp9_highbd_temporal_filter_apply(f->v_buffer + mb_uv_offset,
f->uv_stride, predictor + 512,
mb_uv_width, mb_uv_height,
adj_strength, filter_weight,
accumulator + 512, count + 512);
} else {
// Apply the filter (YUV)
vp9_temporal_filter_apply(f->y_buffer + mb_y_offset, f->y_stride,
predictor, 16, 16,
strength, filter_weight,
accumulator, count);
vp9_temporal_filter_apply(f->u_buffer + mb_uv_offset, f->uv_stride,
predictor + 256,
mb_uv_width, mb_uv_height, strength,
filter_weight, accumulator + 256,
count + 256);
vp9_temporal_filter_apply(f->v_buffer + mb_uv_offset, f->uv_stride,
predictor + 512,
mb_uv_width, mb_uv_height, strength,
filter_weight, accumulator + 512,
count + 512);
}
#else
// Apply the filter (YUV)
vp9_temporal_filter_apply(f->y_buffer + mb_y_offset, f->y_stride,
predictor, 16, 16,
strength, filter_weight,
accumulator, count);
vp9_temporal_filter_apply(f->u_buffer + mb_uv_offset, f->uv_stride,
predictor + 256,
mb_uv_width, mb_uv_height, strength,
filter_weight, accumulator + 256,
count + 256);
vp9_temporal_filter_apply(f->v_buffer + mb_uv_offset, f->uv_stride,
predictor + 512,
mb_uv_width, mb_uv_height, strength,
filter_weight, accumulator + 512,
count + 512);
#endif // CONFIG_VP9_HIGHBITDEPTH
}
}
#if CONFIG_VP9_HIGHBITDEPTH
if (mbd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) {
uint16_t *dst1_16;
uint16_t *dst2_16;
// Normalize filter output to produce AltRef frame
dst1 = cpi->alt_ref_buffer.y_buffer;
dst1_16 = CONVERT_TO_SHORTPTR(dst1);
stride = cpi->alt_ref_buffer.y_stride;
byte = mb_y_offset;
for (i = 0, k = 0; i < 16; i++) {
for (j = 0; j < 16; j++, k++) {
unsigned int pval = accumulator[k] + (count[k] >> 1);
pval *= fixed_divide[count[k]];
pval >>= 19;
dst1_16[byte] = (uint16_t)pval;
// move to next pixel
byte++;
}
byte += stride - 16;
}
dst1 = cpi->alt_ref_buffer.u_buffer;
dst2 = cpi->alt_ref_buffer.v_buffer;
dst1_16 = CONVERT_TO_SHORTPTR(dst1);
dst2_16 = CONVERT_TO_SHORTPTR(dst2);
stride = cpi->alt_ref_buffer.uv_stride;
byte = mb_uv_offset;
for (i = 0, k = 256; i < mb_uv_height; i++) {
for (j = 0; j < mb_uv_width; j++, k++) {
int m = k + 256;
// U
unsigned int pval = accumulator[k] + (count[k] >> 1);
pval *= fixed_divide[count[k]];
pval >>= 19;
dst1_16[byte] = (uint16_t)pval;
// V
pval = accumulator[m] + (count[m] >> 1);
pval *= fixed_divide[count[m]];
pval >>= 19;
dst2_16[byte] = (uint16_t)pval;
// move to next pixel
byte++;
}
byte += stride - mb_uv_width;
}
} else {
// Normalize filter output to produce AltRef frame
dst1 = cpi->alt_ref_buffer.y_buffer;
stride = cpi->alt_ref_buffer.y_stride;
byte = mb_y_offset;
for (i = 0, k = 0; i < 16; i++) {
for (j = 0; j < 16; j++, k++) {
unsigned int pval = accumulator[k] + (count[k] >> 1);
pval *= fixed_divide[count[k]];
pval >>= 19;
dst1[byte] = (uint8_t)pval;
// move to next pixel
byte++;
}
byte += stride - 16;
}
dst1 = cpi->alt_ref_buffer.u_buffer;
dst2 = cpi->alt_ref_buffer.v_buffer;
stride = cpi->alt_ref_buffer.uv_stride;
byte = mb_uv_offset;
for (i = 0, k = 256; i < mb_uv_height; i++) {
for (j = 0; j < mb_uv_width; j++, k++) {
int m = k + 256;
// U
unsigned int pval = accumulator[k] + (count[k] >> 1);
pval *= fixed_divide[count[k]];
pval >>= 19;
dst1[byte] = (uint8_t)pval;
// V
pval = accumulator[m] + (count[m] >> 1);
pval *= fixed_divide[count[m]];
pval >>= 19;
dst2[byte] = (uint8_t)pval;
// move to next pixel
byte++;
}
byte += stride - mb_uv_width;
}
}
#else
// Normalize filter output to produce AltRef frame
dst1 = cpi->alt_ref_buffer.y_buffer;
stride = cpi->alt_ref_buffer.y_stride;
byte = mb_y_offset;
for (i = 0, k = 0; i < 16; i++) {
for (j = 0; j < 16; j++, k++) {
unsigned int pval = accumulator[k] + (count[k] >> 1);
pval *= fixed_divide[count[k]];
pval >>= 19;
dst1[byte] = (uint8_t)pval;
// move to next pixel
byte++;
}
byte += stride - 16;
}
dst1 = cpi->alt_ref_buffer.u_buffer;
dst2 = cpi->alt_ref_buffer.v_buffer;
stride = cpi->alt_ref_buffer.uv_stride;
byte = mb_uv_offset;
for (i = 0, k = 256; i < mb_uv_height; i++) {
for (j = 0; j < mb_uv_width; j++, k++) {
int m = k + 256;
// U
unsigned int pval = accumulator[k] + (count[k] >> 1);
pval *= fixed_divide[count[k]];
pval >>= 19;
dst1[byte] = (uint8_t)pval;
// V
pval = accumulator[m] + (count[m] >> 1);
pval *= fixed_divide[count[m]];
pval >>= 19;
dst2[byte] = (uint8_t)pval;
// move to next pixel
byte++;
}
byte += stride - mb_uv_width;
}
#endif // CONFIG_VP9_HIGHBITDEPTH
mb_y_offset += 16;
mb_uv_offset += mb_uv_width;
}
mb_y_offset += 16 * (f->y_stride - mb_cols);
mb_uv_offset += mb_uv_height * f->uv_stride - mb_uv_width * mb_cols;
}
// Restore input state
for (i = 0; i < MAX_MB_PLANE; i++)
mbd->plane[i].pre[0].buf = input_buffer[i];
}
// Apply buffer limits and context specific adjustments to arnr filter.
static void adjust_arnr_filter(VP9_COMP *cpi,
int distance, int group_boost,
int *arnr_frames, int *arnr_strength) {
const VP9EncoderConfig *const oxcf = &cpi->oxcf;
const int frames_after_arf =
vp9_lookahead_depth(cpi->lookahead) - distance - 1;
int frames_fwd = (cpi->oxcf.arnr_max_frames - 1) >> 1;
int frames_bwd;
int q, frames, strength;
// Define the forward and backwards filter limits for this arnr group.
if (frames_fwd > frames_after_arf)
frames_fwd = frames_after_arf;
if (frames_fwd > distance)
frames_fwd = distance;
frames_bwd = frames_fwd;
// For even length filter there is one more frame backward
// than forward: e.g. len=6 ==> bbbAff, len=7 ==> bbbAfff.
if (frames_bwd < distance)
frames_bwd += (oxcf->arnr_max_frames + 1) & 0x1;
// Set the baseline active filter size.
frames = frames_bwd + 1 + frames_fwd;
// Adjust the strength based on active max q.
if (cpi->common.current_video_frame > 1)
q = ((int)vp9_convert_qindex_to_q(
cpi->rc.avg_frame_qindex[INTER_FRAME], cpi->common.bit_depth));
else
q = ((int)vp9_convert_qindex_to_q(
cpi->rc.avg_frame_qindex[KEY_FRAME], cpi->common.bit_depth));
if (q > 16) {
strength = oxcf->arnr_strength;
} else {
strength = oxcf->arnr_strength - ((16 - q) / 2);
if (strength < 0)
strength = 0;
}
// Adjust number of frames in filter and strength based on gf boost level.
if (frames > group_boost / 150) {
frames = group_boost / 150;
frames += !(frames & 1);
}
if (strength > group_boost / 300) {
strength = group_boost / 300;
}
// Adjustments for second level arf in multi arf case.
if (cpi->oxcf.pass == 2 && cpi->multi_arf_allowed) {
const GF_GROUP *const gf_group = &cpi->twopass.gf_group;
if (gf_group->rf_level[gf_group->index] != GF_ARF_STD) {
strength >>= 1;
}
}
*arnr_frames = frames;
*arnr_strength = strength;
}
void vp9_temporal_filter(VP9_COMP *cpi, int distance) {
VP9_COMMON *const cm = &cpi->common;
RATE_CONTROL *const rc = &cpi->rc;
MACROBLOCKD *const xd = &cpi->td.mb.e_mbd;
int frame;
int frames_to_blur;
int start_frame;
int strength;
int frames_to_blur_backward;
int frames_to_blur_forward;
struct scale_factors sf;
YV12_BUFFER_CONFIG *frames[MAX_LAG_BUFFERS] = {NULL};
// Apply context specific adjustments to the arnr filter parameters.
adjust_arnr_filter(cpi, distance, rc->gfu_boost, &frames_to_blur, &strength);
frames_to_blur_backward = (frames_to_blur / 2);
frames_to_blur_forward = ((frames_to_blur - 1) / 2);
start_frame = distance + frames_to_blur_forward;
// Setup frame pointers, NULL indicates frame not included in filter.
for (frame = 0; frame < frames_to_blur; ++frame) {
const int which_buffer = start_frame - frame;
struct lookahead_entry *buf = vp9_lookahead_peek(cpi->lookahead,
which_buffer);
frames[frames_to_blur - 1 - frame] = &buf->img;
}
if (frames_to_blur > 0) {
// Setup scaling factors. Scaling on each of the arnr frames is not
// supported.
if (cpi->use_svc) {
// In spatial svc the scaling factors might be less then 1/2.
// So we will use non-normative scaling.
int frame_used = 0;
#if CONFIG_VP9_HIGHBITDEPTH
vp9_setup_scale_factors_for_frame(
&sf,
get_frame_new_buffer(cm)->y_crop_width,
get_frame_new_buffer(cm)->y_crop_height,
get_frame_new_buffer(cm)->y_crop_width,
get_frame_new_buffer(cm)->y_crop_height,
cm->use_highbitdepth);
#else
vp9_setup_scale_factors_for_frame(
&sf,
get_frame_new_buffer(cm)->y_crop_width,
get_frame_new_buffer(cm)->y_crop_height,
get_frame_new_buffer(cm)->y_crop_width,
get_frame_new_buffer(cm)->y_crop_height);
#endif // CONFIG_VP9_HIGHBITDEPTH
for (frame = 0; frame < frames_to_blur; ++frame) {
if (cm->mi_cols * MI_SIZE != frames[frame]->y_width ||
cm->mi_rows * MI_SIZE != frames[frame]->y_height) {
if (vp9_realloc_frame_buffer(&cpi->svc.scaled_frames[frame_used],
cm->width, cm->height,
cm->subsampling_x, cm->subsampling_y,
#if CONFIG_VP9_HIGHBITDEPTH
cm->use_highbitdepth,
#endif
VP9_ENC_BORDER_IN_PIXELS,
cm->byte_alignment,
NULL, NULL, NULL)) {
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
"Failed to reallocate alt_ref_buffer");
}
frames[frame] = vp9_scale_if_required(
cm, frames[frame], &cpi->svc.scaled_frames[frame_used]);
++frame_used;
}
}
cm->mi = cm->mip + cm->mi_stride + 1;
xd->mi = cm->mi_grid_visible;
xd->mi[0] = cm->mi;
} else {
// ARF is produced at the native frame size and resized when coded.
#if CONFIG_VP9_HIGHBITDEPTH
vp9_setup_scale_factors_for_frame(&sf,
frames[0]->y_crop_width,
frames[0]->y_crop_height,
frames[0]->y_crop_width,
frames[0]->y_crop_height,
cm->use_highbitdepth);
#else
vp9_setup_scale_factors_for_frame(&sf,
frames[0]->y_crop_width,
frames[0]->y_crop_height,
frames[0]->y_crop_width,
frames[0]->y_crop_height);
#endif // CONFIG_VP9_HIGHBITDEPTH
}
}
temporal_filter_iterate_c(cpi, frames, frames_to_blur,
frames_to_blur_backward, strength, &sf);
}

View file

@ -0,0 +1,25 @@
/*
* 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.
*/
#ifndef VP9_ENCODER_VP9_TEMPORAL_FILTER_H_
#define VP9_ENCODER_VP9_TEMPORAL_FILTER_H_
#ifdef __cplusplus
extern "C" {
#endif
void vp9_temporal_filter_init(void);
void vp9_temporal_filter(VP9_COMP *cpi, int distance);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // VP9_ENCODER_VP9_TEMPORAL_FILTER_H_

View file

@ -0,0 +1,634 @@
/*
* 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 <assert.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include "vpx_mem/vpx_mem.h"
#include "vp9/common/vp9_entropy.h"
#include "vp9/common/vp9_pred_common.h"
#include "vp9/common/vp9_scan.h"
#include "vp9/common/vp9_seg_common.h"
#include "vp9/encoder/vp9_cost.h"
#include "vp9/encoder/vp9_encoder.h"
#include "vp9/encoder/vp9_tokenize.h"
static const TOKENVALUE dct_cat_lt_10_value_tokens[] = {
{9, 63}, {9, 61}, {9, 59}, {9, 57}, {9, 55}, {9, 53}, {9, 51}, {9, 49},
{9, 47}, {9, 45}, {9, 43}, {9, 41}, {9, 39}, {9, 37}, {9, 35}, {9, 33},
{9, 31}, {9, 29}, {9, 27}, {9, 25}, {9, 23}, {9, 21}, {9, 19}, {9, 17},
{9, 15}, {9, 13}, {9, 11}, {9, 9}, {9, 7}, {9, 5}, {9, 3}, {9, 1},
{8, 31}, {8, 29}, {8, 27}, {8, 25}, {8, 23}, {8, 21},
{8, 19}, {8, 17}, {8, 15}, {8, 13}, {8, 11}, {8, 9},
{8, 7}, {8, 5}, {8, 3}, {8, 1},
{7, 15}, {7, 13}, {7, 11}, {7, 9}, {7, 7}, {7, 5}, {7, 3}, {7, 1},
{6, 7}, {6, 5}, {6, 3}, {6, 1}, {5, 3}, {5, 1},
{4, 1}, {3, 1}, {2, 1}, {1, 1}, {0, 0},
{1, 0}, {2, 0}, {3, 0}, {4, 0},
{5, 0}, {5, 2}, {6, 0}, {6, 2}, {6, 4}, {6, 6},
{7, 0}, {7, 2}, {7, 4}, {7, 6}, {7, 8}, {7, 10}, {7, 12}, {7, 14},
{8, 0}, {8, 2}, {8, 4}, {8, 6}, {8, 8}, {8, 10}, {8, 12},
{8, 14}, {8, 16}, {8, 18}, {8, 20}, {8, 22}, {8, 24},
{8, 26}, {8, 28}, {8, 30}, {9, 0}, {9, 2},
{9, 4}, {9, 6}, {9, 8}, {9, 10}, {9, 12}, {9, 14}, {9, 16},
{9, 18}, {9, 20}, {9, 22}, {9, 24}, {9, 26}, {9, 28},
{9, 30}, {9, 32}, {9, 34}, {9, 36}, {9, 38}, {9, 40},
{9, 42}, {9, 44}, {9, 46}, {9, 48}, {9, 50}, {9, 52},
{9, 54}, {9, 56}, {9, 58}, {9, 60}, {9, 62}
};
const TOKENVALUE *vp9_dct_cat_lt_10_value_tokens = dct_cat_lt_10_value_tokens +
(sizeof(dct_cat_lt_10_value_tokens) / sizeof(*dct_cat_lt_10_value_tokens))
/ 2;
// Array indices are identical to previously-existing CONTEXT_NODE indices
const vp9_tree_index vp9_coef_tree[TREE_SIZE(ENTROPY_TOKENS)] = {
-EOB_TOKEN, 2, // 0 = EOB
-ZERO_TOKEN, 4, // 1 = ZERO
-ONE_TOKEN, 6, // 2 = ONE
8, 12, // 3 = LOW_VAL
-TWO_TOKEN, 10, // 4 = TWO
-THREE_TOKEN, -FOUR_TOKEN, // 5 = THREE
14, 16, // 6 = HIGH_LOW
-CATEGORY1_TOKEN, -CATEGORY2_TOKEN, // 7 = CAT_ONE
18, 20, // 8 = CAT_THREEFOUR
-CATEGORY3_TOKEN, -CATEGORY4_TOKEN, // 9 = CAT_THREE
-CATEGORY5_TOKEN, -CATEGORY6_TOKEN // 10 = CAT_FIVE
};
static const vp9_tree_index cat1[2] = {0, 0};
static const vp9_tree_index cat2[4] = {2, 2, 0, 0};
static const vp9_tree_index cat3[6] = {2, 2, 4, 4, 0, 0};
static const vp9_tree_index cat4[8] = {2, 2, 4, 4, 6, 6, 0, 0};
static const vp9_tree_index cat5[10] = {2, 2, 4, 4, 6, 6, 8, 8, 0, 0};
static const vp9_tree_index cat6[28] = {2, 2, 4, 4, 6, 6, 8, 8, 10, 10, 12, 12,
14, 14, 16, 16, 18, 18, 20, 20, 22, 22, 24, 24, 26, 26, 0, 0};
static const int16_t zero_cost[] = {0};
static const int16_t one_cost[] = {255, 257};
static const int16_t two_cost[] = {255, 257};
static const int16_t three_cost[] = {255, 257};
static const int16_t four_cost[] = {255, 257};
static const int16_t cat1_cost[] = {429, 431, 616, 618};
static const int16_t cat2_cost[] = {624, 626, 727, 729, 848, 850, 951, 953};
static const int16_t cat3_cost[] = {
820, 822, 893, 895, 940, 942, 1013, 1015, 1096, 1098, 1169, 1171, 1216, 1218,
1289, 1291
};
static const int16_t cat4_cost[] = {
1032, 1034, 1075, 1077, 1105, 1107, 1148, 1150, 1194, 1196, 1237, 1239,
1267, 1269, 1310, 1312, 1328, 1330, 1371, 1373, 1401, 1403, 1444, 1446,
1490, 1492, 1533, 1535, 1563, 1565, 1606, 1608
};
static const int16_t cat5_cost[] = {
1269, 1271, 1283, 1285, 1306, 1308, 1320,
1322, 1347, 1349, 1361, 1363, 1384, 1386, 1398, 1400, 1443, 1445, 1457,
1459, 1480, 1482, 1494, 1496, 1521, 1523, 1535, 1537, 1558, 1560, 1572,
1574, 1592, 1594, 1606, 1608, 1629, 1631, 1643, 1645, 1670, 1672, 1684,
1686, 1707, 1709, 1721, 1723, 1766, 1768, 1780, 1782, 1803, 1805, 1817,
1819, 1844, 1846, 1858, 1860, 1881, 1883, 1895, 1897
};
const int16_t vp9_cat6_low_cost[256] = {
1638, 1640, 1646, 1648, 1652, 1654, 1660, 1662,
1670, 1672, 1678, 1680, 1684, 1686, 1692, 1694, 1711, 1713, 1719, 1721,
1725, 1727, 1733, 1735, 1743, 1745, 1751, 1753, 1757, 1759, 1765, 1767,
1787, 1789, 1795, 1797, 1801, 1803, 1809, 1811, 1819, 1821, 1827, 1829,
1833, 1835, 1841, 1843, 1860, 1862, 1868, 1870, 1874, 1876, 1882, 1884,
1892, 1894, 1900, 1902, 1906, 1908, 1914, 1916, 1940, 1942, 1948, 1950,
1954, 1956, 1962, 1964, 1972, 1974, 1980, 1982, 1986, 1988, 1994, 1996,
2013, 2015, 2021, 2023, 2027, 2029, 2035, 2037, 2045, 2047, 2053, 2055,
2059, 2061, 2067, 2069, 2089, 2091, 2097, 2099, 2103, 2105, 2111, 2113,
2121, 2123, 2129, 2131, 2135, 2137, 2143, 2145, 2162, 2164, 2170, 2172,
2176, 2178, 2184, 2186, 2194, 2196, 2202, 2204, 2208, 2210, 2216, 2218,
2082, 2084, 2090, 2092, 2096, 2098, 2104, 2106, 2114, 2116, 2122, 2124,
2128, 2130, 2136, 2138, 2155, 2157, 2163, 2165, 2169, 2171, 2177, 2179,
2187, 2189, 2195, 2197, 2201, 2203, 2209, 2211, 2231, 2233, 2239, 2241,
2245, 2247, 2253, 2255, 2263, 2265, 2271, 2273, 2277, 2279, 2285, 2287,
2304, 2306, 2312, 2314, 2318, 2320, 2326, 2328, 2336, 2338, 2344, 2346,
2350, 2352, 2358, 2360, 2384, 2386, 2392, 2394, 2398, 2400, 2406, 2408,
2416, 2418, 2424, 2426, 2430, 2432, 2438, 2440, 2457, 2459, 2465, 2467,
2471, 2473, 2479, 2481, 2489, 2491, 2497, 2499, 2503, 2505, 2511, 2513,
2533, 2535, 2541, 2543, 2547, 2549, 2555, 2557, 2565, 2567, 2573, 2575,
2579, 2581, 2587, 2589, 2606, 2608, 2614, 2616, 2620, 2622, 2628, 2630,
2638, 2640, 2646, 2648, 2652, 2654, 2660, 2662
};
const int16_t vp9_cat6_high_cost[128] = {
72, 892, 1183, 2003, 1448, 2268, 2559, 3379,
1709, 2529, 2820, 3640, 3085, 3905, 4196, 5016, 2118, 2938, 3229, 4049,
3494, 4314, 4605, 5425, 3755, 4575, 4866, 5686, 5131, 5951, 6242, 7062,
2118, 2938, 3229, 4049, 3494, 4314, 4605, 5425, 3755, 4575, 4866, 5686,
5131, 5951, 6242, 7062, 4164, 4984, 5275, 6095, 5540, 6360, 6651, 7471,
5801, 6621, 6912, 7732, 7177, 7997, 8288, 9108, 2118, 2938, 3229, 4049,
3494, 4314, 4605, 5425, 3755, 4575, 4866, 5686, 5131, 5951, 6242, 7062,
4164, 4984, 5275, 6095, 5540, 6360, 6651, 7471, 5801, 6621, 6912, 7732,
7177, 7997, 8288, 9108, 4164, 4984, 5275, 6095, 5540, 6360, 6651, 7471,
5801, 6621, 6912, 7732, 7177, 7997, 8288, 9108, 6210, 7030, 7321, 8141,
7586, 8406, 8697, 9517, 7847, 8667, 8958, 9778, 9223, 10043, 10334, 11154
};
#if CONFIG_VP9_HIGHBITDEPTH
const int16_t vp9_cat6_high10_high_cost[512] = {
74, 894, 1185, 2005, 1450, 2270, 2561,
3381, 1711, 2531, 2822, 3642, 3087, 3907, 4198, 5018, 2120, 2940, 3231,
4051, 3496, 4316, 4607, 5427, 3757, 4577, 4868, 5688, 5133, 5953, 6244,
7064, 2120, 2940, 3231, 4051, 3496, 4316, 4607, 5427, 3757, 4577, 4868,
5688, 5133, 5953, 6244, 7064, 4166, 4986, 5277, 6097, 5542, 6362, 6653,
7473, 5803, 6623, 6914, 7734, 7179, 7999, 8290, 9110, 2120, 2940, 3231,
4051, 3496, 4316, 4607, 5427, 3757, 4577, 4868, 5688, 5133, 5953, 6244,
7064, 4166, 4986, 5277, 6097, 5542, 6362, 6653, 7473, 5803, 6623, 6914,
7734, 7179, 7999, 8290, 9110, 4166, 4986, 5277, 6097, 5542, 6362, 6653,
7473, 5803, 6623, 6914, 7734, 7179, 7999, 8290, 9110, 6212, 7032, 7323,
8143, 7588, 8408, 8699, 9519, 7849, 8669, 8960, 9780, 9225, 10045, 10336,
11156, 2120, 2940, 3231, 4051, 3496, 4316, 4607, 5427, 3757, 4577, 4868,
5688, 5133, 5953, 6244, 7064, 4166, 4986, 5277, 6097, 5542, 6362, 6653,
7473, 5803, 6623, 6914, 7734, 7179, 7999, 8290, 9110, 4166, 4986, 5277,
6097, 5542, 6362, 6653, 7473, 5803, 6623, 6914, 7734, 7179, 7999, 8290,
9110, 6212, 7032, 7323, 8143, 7588, 8408, 8699, 9519, 7849, 8669, 8960,
9780, 9225, 10045, 10336, 11156, 4166, 4986, 5277, 6097, 5542, 6362, 6653,
7473, 5803, 6623, 6914, 7734, 7179, 7999, 8290, 9110, 6212, 7032, 7323,
8143, 7588, 8408, 8699, 9519, 7849, 8669, 8960, 9780, 9225, 10045, 10336,
11156, 6212, 7032, 7323, 8143, 7588, 8408, 8699, 9519, 7849, 8669, 8960,
9780, 9225, 10045, 10336, 11156, 8258, 9078, 9369, 10189, 9634, 10454,
10745, 11565, 9895, 10715, 11006, 11826, 11271, 12091, 12382, 13202, 2120,
2940, 3231, 4051, 3496, 4316, 4607, 5427, 3757, 4577, 4868, 5688, 5133,
5953, 6244, 7064, 4166, 4986, 5277, 6097, 5542, 6362, 6653, 7473, 5803,
6623, 6914, 7734, 7179, 7999, 8290, 9110, 4166, 4986, 5277, 6097, 5542,
6362, 6653, 7473, 5803, 6623, 6914, 7734, 7179, 7999, 8290, 9110, 6212,
7032, 7323, 8143, 7588, 8408, 8699, 9519, 7849, 8669, 8960, 9780, 9225,
10045, 10336, 11156, 4166, 4986, 5277, 6097, 5542, 6362, 6653, 7473, 5803,
6623, 6914, 7734, 7179, 7999, 8290, 9110, 6212, 7032, 7323, 8143, 7588,
8408, 8699, 9519, 7849, 8669, 8960, 9780, 9225, 10045, 10336, 11156, 6212,
7032, 7323, 8143, 7588, 8408, 8699, 9519, 7849, 8669, 8960, 9780, 9225,
10045, 10336, 11156, 8258, 9078, 9369, 10189, 9634, 10454, 10745, 11565,
9895, 10715, 11006, 11826, 11271, 12091, 12382, 13202, 4166, 4986, 5277,
6097, 5542, 6362, 6653, 7473, 5803, 6623, 6914, 7734, 7179, 7999, 8290,
9110, 6212, 7032, 7323, 8143, 7588, 8408, 8699, 9519, 7849, 8669, 8960,
9780, 9225, 10045, 10336, 11156, 6212, 7032, 7323, 8143, 7588, 8408, 8699,
9519, 7849, 8669, 8960, 9780, 9225, 10045, 10336, 11156, 8258, 9078, 9369,
10189, 9634, 10454, 10745, 11565, 9895, 10715, 11006, 11826, 11271, 12091,
12382, 13202, 6212, 7032, 7323, 8143, 7588, 8408, 8699, 9519, 7849, 8669,
8960, 9780, 9225, 10045, 10336, 11156, 8258, 9078, 9369, 10189, 9634, 10454,
10745, 11565, 9895, 10715, 11006, 11826, 11271, 12091, 12382, 13202, 8258,
9078, 9369, 10189, 9634, 10454, 10745, 11565, 9895, 10715, 11006, 11826,
11271, 12091, 12382, 13202, 10304, 11124, 11415, 12235, 11680, 12500, 12791,
13611, 11941, 12761, 13052, 13872, 13317, 14137, 14428, 15248,
};
const int16_t vp9_cat6_high12_high_cost[2048] = {
76, 896, 1187, 2007, 1452, 2272, 2563,
3383, 1713, 2533, 2824, 3644, 3089, 3909, 4200, 5020, 2122, 2942, 3233,
4053, 3498, 4318, 4609, 5429, 3759, 4579, 4870, 5690, 5135, 5955, 6246,
7066, 2122, 2942, 3233, 4053, 3498, 4318, 4609, 5429, 3759, 4579, 4870,
5690, 5135, 5955, 6246, 7066, 4168, 4988, 5279, 6099, 5544, 6364, 6655,
7475, 5805, 6625, 6916, 7736, 7181, 8001, 8292, 9112, 2122, 2942, 3233,
4053, 3498, 4318, 4609, 5429, 3759, 4579, 4870, 5690, 5135, 5955, 6246,
7066, 4168, 4988, 5279, 6099, 5544, 6364, 6655, 7475, 5805, 6625, 6916,
7736, 7181, 8001, 8292, 9112, 4168, 4988, 5279, 6099, 5544, 6364, 6655,
7475, 5805, 6625, 6916, 7736, 7181, 8001, 8292, 9112, 6214, 7034, 7325,
8145, 7590, 8410, 8701, 9521, 7851, 8671, 8962, 9782, 9227, 10047, 10338,
11158, 2122, 2942, 3233, 4053, 3498, 4318, 4609, 5429, 3759, 4579, 4870,
5690, 5135, 5955, 6246, 7066, 4168, 4988, 5279, 6099, 5544, 6364, 6655,
7475, 5805, 6625, 6916, 7736, 7181, 8001, 8292, 9112, 4168, 4988, 5279,
6099, 5544, 6364, 6655, 7475, 5805, 6625, 6916, 7736, 7181, 8001, 8292,
9112, 6214, 7034, 7325, 8145, 7590, 8410, 8701, 9521, 7851, 8671, 8962,
9782, 9227, 10047, 10338, 11158, 4168, 4988, 5279, 6099, 5544, 6364, 6655,
7475, 5805, 6625, 6916, 7736, 7181, 8001, 8292, 9112, 6214, 7034, 7325,
8145, 7590, 8410, 8701, 9521, 7851, 8671, 8962, 9782, 9227, 10047, 10338,
11158, 6214, 7034, 7325, 8145, 7590, 8410, 8701, 9521, 7851, 8671, 8962,
9782, 9227, 10047, 10338, 11158, 8260, 9080, 9371, 10191, 9636, 10456,
10747, 11567, 9897, 10717, 11008, 11828, 11273, 12093, 12384, 13204, 2122,
2942, 3233, 4053, 3498, 4318, 4609, 5429, 3759, 4579, 4870, 5690, 5135,
5955, 6246, 7066, 4168, 4988, 5279, 6099, 5544, 6364, 6655, 7475, 5805,
6625, 6916, 7736, 7181, 8001, 8292, 9112, 4168, 4988, 5279, 6099, 5544,
6364, 6655, 7475, 5805, 6625, 6916, 7736, 7181, 8001, 8292, 9112, 6214,
7034, 7325, 8145, 7590, 8410, 8701, 9521, 7851, 8671, 8962, 9782, 9227,
10047, 10338, 11158, 4168, 4988, 5279, 6099, 5544, 6364, 6655, 7475, 5805,
6625, 6916, 7736, 7181, 8001, 8292, 9112, 6214, 7034, 7325, 8145, 7590,
8410, 8701, 9521, 7851, 8671, 8962, 9782, 9227, 10047, 10338, 11158, 6214,
7034, 7325, 8145, 7590, 8410, 8701, 9521, 7851, 8671, 8962, 9782, 9227,
10047, 10338, 11158, 8260, 9080, 9371, 10191, 9636, 10456, 10747, 11567,
9897, 10717, 11008, 11828, 11273, 12093, 12384, 13204, 4168, 4988, 5279,
6099, 5544, 6364, 6655, 7475, 5805, 6625, 6916, 7736, 7181, 8001, 8292,
9112, 6214, 7034, 7325, 8145, 7590, 8410, 8701, 9521, 7851, 8671, 8962,
9782, 9227, 10047, 10338, 11158, 6214, 7034, 7325, 8145, 7590, 8410, 8701,
9521, 7851, 8671, 8962, 9782, 9227, 10047, 10338, 11158, 8260, 9080, 9371,
10191, 9636, 10456, 10747, 11567, 9897, 10717, 11008, 11828, 11273, 12093,
12384, 13204, 6214, 7034, 7325, 8145, 7590, 8410, 8701, 9521, 7851, 8671,
8962, 9782, 9227, 10047, 10338, 11158, 8260, 9080, 9371, 10191, 9636, 10456,
10747, 11567, 9897, 10717, 11008, 11828, 11273, 12093, 12384, 13204, 8260,
9080, 9371, 10191, 9636, 10456, 10747, 11567, 9897, 10717, 11008, 11828,
11273, 12093, 12384, 13204, 10306, 11126, 11417, 12237, 11682, 12502, 12793,
13613, 11943, 12763, 13054, 13874, 13319, 14139, 14430, 15250, 2122, 2942,
3233, 4053, 3498, 4318, 4609, 5429, 3759, 4579, 4870, 5690, 5135, 5955,
6246, 7066, 4168, 4988, 5279, 6099, 5544, 6364, 6655, 7475, 5805, 6625,
6916, 7736, 7181, 8001, 8292, 9112, 4168, 4988, 5279, 6099, 5544, 6364,
6655, 7475, 5805, 6625, 6916, 7736, 7181, 8001, 8292, 9112, 6214, 7034,
7325, 8145, 7590, 8410, 8701, 9521, 7851, 8671, 8962, 9782, 9227, 10047,
10338, 11158, 4168, 4988, 5279, 6099, 5544, 6364, 6655, 7475, 5805, 6625,
6916, 7736, 7181, 8001, 8292, 9112, 6214, 7034, 7325, 8145, 7590, 8410,
8701, 9521, 7851, 8671, 8962, 9782, 9227, 10047, 10338, 11158, 6214, 7034,
7325, 8145, 7590, 8410, 8701, 9521, 7851, 8671, 8962, 9782, 9227, 10047,
10338, 11158, 8260, 9080, 9371, 10191, 9636, 10456, 10747, 11567, 9897,
10717, 11008, 11828, 11273, 12093, 12384, 13204, 4168, 4988, 5279, 6099,
5544, 6364, 6655, 7475, 5805, 6625, 6916, 7736, 7181, 8001, 8292, 9112,
6214, 7034, 7325, 8145, 7590, 8410, 8701, 9521, 7851, 8671, 8962, 9782,
9227, 10047, 10338, 11158, 6214, 7034, 7325, 8145, 7590, 8410, 8701, 9521,
7851, 8671, 8962, 9782, 9227, 10047, 10338, 11158, 8260, 9080, 9371, 10191,
9636, 10456, 10747, 11567, 9897, 10717, 11008, 11828, 11273, 12093, 12384,
13204, 6214, 7034, 7325, 8145, 7590, 8410, 8701, 9521, 7851, 8671, 8962,
9782, 9227, 10047, 10338, 11158, 8260, 9080, 9371, 10191, 9636, 10456,
10747, 11567, 9897, 10717, 11008, 11828, 11273, 12093, 12384, 13204, 8260,
9080, 9371, 10191, 9636, 10456, 10747, 11567, 9897, 10717, 11008, 11828,
11273, 12093, 12384, 13204, 10306, 11126, 11417, 12237, 11682, 12502, 12793,
13613, 11943, 12763, 13054, 13874, 13319, 14139, 14430, 15250, 4168, 4988,
5279, 6099, 5544, 6364, 6655, 7475, 5805, 6625, 6916, 7736, 7181, 8001,
8292, 9112, 6214, 7034, 7325, 8145, 7590, 8410, 8701, 9521, 7851, 8671,
8962, 9782, 9227, 10047, 10338, 11158, 6214, 7034, 7325, 8145, 7590, 8410,
8701, 9521, 7851, 8671, 8962, 9782, 9227, 10047, 10338, 11158, 8260, 9080,
9371, 10191, 9636, 10456, 10747, 11567, 9897, 10717, 11008, 11828, 11273,
12093, 12384, 13204, 6214, 7034, 7325, 8145, 7590, 8410, 8701, 9521, 7851,
8671, 8962, 9782, 9227, 10047, 10338, 11158, 8260, 9080, 9371, 10191, 9636,
10456, 10747, 11567, 9897, 10717, 11008, 11828, 11273, 12093, 12384, 13204,
8260, 9080, 9371, 10191, 9636, 10456, 10747, 11567, 9897, 10717, 11008,
11828, 11273, 12093, 12384, 13204, 10306, 11126, 11417, 12237, 11682, 12502,
12793, 13613, 11943, 12763, 13054, 13874, 13319, 14139, 14430, 15250, 6214,
7034, 7325, 8145, 7590, 8410, 8701, 9521, 7851, 8671, 8962, 9782, 9227,
10047, 10338, 11158, 8260, 9080, 9371, 10191, 9636, 10456, 10747, 11567,
9897, 10717, 11008, 11828, 11273, 12093, 12384, 13204, 8260, 9080, 9371,
10191, 9636, 10456, 10747, 11567, 9897, 10717, 11008, 11828, 11273, 12093,
12384, 13204, 10306, 11126, 11417, 12237, 11682, 12502, 12793, 13613, 11943,
12763, 13054, 13874, 13319, 14139, 14430, 15250, 8260, 9080, 9371, 10191,
9636, 10456, 10747, 11567, 9897, 10717, 11008, 11828, 11273, 12093, 12384,
13204, 10306, 11126, 11417, 12237, 11682, 12502, 12793, 13613, 11943, 12763,
13054, 13874, 13319, 14139, 14430, 15250, 10306, 11126, 11417, 12237, 11682,
12502, 12793, 13613, 11943, 12763, 13054, 13874, 13319, 14139, 14430, 15250,
12352, 13172, 13463, 14283, 13728, 14548, 14839, 15659, 13989, 14809, 15100,
15920, 15365, 16185, 16476, 17296, 2122, 2942, 3233, 4053, 3498, 4318, 4609,
5429, 3759, 4579, 4870, 5690, 5135, 5955, 6246, 7066, 4168, 4988, 5279,
6099, 5544, 6364, 6655, 7475, 5805, 6625, 6916, 7736, 7181, 8001, 8292,
9112, 4168, 4988, 5279, 6099, 5544, 6364, 6655, 7475, 5805, 6625, 6916,
7736, 7181, 8001, 8292, 9112, 6214, 7034, 7325, 8145, 7590, 8410, 8701,
9521, 7851, 8671, 8962, 9782, 9227, 10047, 10338, 11158, 4168, 4988, 5279,
6099, 5544, 6364, 6655, 7475, 5805, 6625, 6916, 7736, 7181, 8001, 8292,
9112, 6214, 7034, 7325, 8145, 7590, 8410, 8701, 9521, 7851, 8671, 8962,
9782, 9227, 10047, 10338, 11158, 6214, 7034, 7325, 8145, 7590, 8410, 8701,
9521, 7851, 8671, 8962, 9782, 9227, 10047, 10338, 11158, 8260, 9080, 9371,
10191, 9636, 10456, 10747, 11567, 9897, 10717, 11008, 11828, 11273, 12093,
12384, 13204, 4168, 4988, 5279, 6099, 5544, 6364, 6655, 7475, 5805, 6625,
6916, 7736, 7181, 8001, 8292, 9112, 6214, 7034, 7325, 8145, 7590, 8410,
8701, 9521, 7851, 8671, 8962, 9782, 9227, 10047, 10338, 11158, 6214, 7034,
7325, 8145, 7590, 8410, 8701, 9521, 7851, 8671, 8962, 9782, 9227, 10047,
10338, 11158, 8260, 9080, 9371, 10191, 9636, 10456, 10747, 11567, 9897,
10717, 11008, 11828, 11273, 12093, 12384, 13204, 6214, 7034, 7325, 8145,
7590, 8410, 8701, 9521, 7851, 8671, 8962, 9782, 9227, 10047, 10338, 11158,
8260, 9080, 9371, 10191, 9636, 10456, 10747, 11567, 9897, 10717, 11008,
11828, 11273, 12093, 12384, 13204, 8260, 9080, 9371, 10191, 9636, 10456,
10747, 11567, 9897, 10717, 11008, 11828, 11273, 12093, 12384, 13204, 10306,
11126, 11417, 12237, 11682, 12502, 12793, 13613, 11943, 12763, 13054, 13874,
13319, 14139, 14430, 15250, 4168, 4988, 5279, 6099, 5544, 6364, 6655, 7475,
5805, 6625, 6916, 7736, 7181, 8001, 8292, 9112, 6214, 7034, 7325, 8145,
7590, 8410, 8701, 9521, 7851, 8671, 8962, 9782, 9227, 10047, 10338, 11158,
6214, 7034, 7325, 8145, 7590, 8410, 8701, 9521, 7851, 8671, 8962, 9782,
9227, 10047, 10338, 11158, 8260, 9080, 9371, 10191, 9636, 10456, 10747,
11567, 9897, 10717, 11008, 11828, 11273, 12093, 12384, 13204, 6214, 7034,
7325, 8145, 7590, 8410, 8701, 9521, 7851, 8671, 8962, 9782, 9227, 10047,
10338, 11158, 8260, 9080, 9371, 10191, 9636, 10456, 10747, 11567, 9897,
10717, 11008, 11828, 11273, 12093, 12384, 13204, 8260, 9080, 9371, 10191,
9636, 10456, 10747, 11567, 9897, 10717, 11008, 11828, 11273, 12093, 12384,
13204, 10306, 11126, 11417, 12237, 11682, 12502, 12793, 13613, 11943, 12763,
13054, 13874, 13319, 14139, 14430, 15250, 6214, 7034, 7325, 8145, 7590,
8410, 8701, 9521, 7851, 8671, 8962, 9782, 9227, 10047, 10338, 11158, 8260,
9080, 9371, 10191, 9636, 10456, 10747, 11567, 9897, 10717, 11008, 11828,
11273, 12093, 12384, 13204, 8260, 9080, 9371, 10191, 9636, 10456, 10747,
11567, 9897, 10717, 11008, 11828, 11273, 12093, 12384, 13204, 10306, 11126,
11417, 12237, 11682, 12502, 12793, 13613, 11943, 12763, 13054, 13874, 13319,
14139, 14430, 15250, 8260, 9080, 9371, 10191, 9636, 10456, 10747, 11567,
9897, 10717, 11008, 11828, 11273, 12093, 12384, 13204, 10306, 11126, 11417,
12237, 11682, 12502, 12793, 13613, 11943, 12763, 13054, 13874, 13319, 14139,
14430, 15250, 10306, 11126, 11417, 12237, 11682, 12502, 12793, 13613, 11943,
12763, 13054, 13874, 13319, 14139, 14430, 15250, 12352, 13172, 13463, 14283,
13728, 14548, 14839, 15659, 13989, 14809, 15100, 15920, 15365, 16185, 16476,
17296, 4168, 4988, 5279, 6099, 5544, 6364, 6655, 7475, 5805, 6625, 6916,
7736, 7181, 8001, 8292, 9112, 6214, 7034, 7325, 8145, 7590, 8410, 8701,
9521, 7851, 8671, 8962, 9782, 9227, 10047, 10338, 11158, 6214, 7034, 7325,
8145, 7590, 8410, 8701, 9521, 7851, 8671, 8962, 9782, 9227, 10047, 10338,
11158, 8260, 9080, 9371, 10191, 9636, 10456, 10747, 11567, 9897, 10717,
11008, 11828, 11273, 12093, 12384, 13204, 6214, 7034, 7325, 8145, 7590,
8410, 8701, 9521, 7851, 8671, 8962, 9782, 9227, 10047, 10338, 11158, 8260,
9080, 9371, 10191, 9636, 10456, 10747, 11567, 9897, 10717, 11008, 11828,
11273, 12093, 12384, 13204, 8260, 9080, 9371, 10191, 9636, 10456, 10747,
11567, 9897, 10717, 11008, 11828, 11273, 12093, 12384, 13204, 10306, 11126,
11417, 12237, 11682, 12502, 12793, 13613, 11943, 12763, 13054, 13874, 13319,
14139, 14430, 15250, 6214, 7034, 7325, 8145, 7590, 8410, 8701, 9521, 7851,
8671, 8962, 9782, 9227, 10047, 10338, 11158, 8260, 9080, 9371, 10191, 9636,
10456, 10747, 11567, 9897, 10717, 11008, 11828, 11273, 12093, 12384, 13204,
8260, 9080, 9371, 10191, 9636, 10456, 10747, 11567, 9897, 10717, 11008,
11828, 11273, 12093, 12384, 13204, 10306, 11126, 11417, 12237, 11682, 12502,
12793, 13613, 11943, 12763, 13054, 13874, 13319, 14139, 14430, 15250, 8260,
9080, 9371, 10191, 9636, 10456, 10747, 11567, 9897, 10717, 11008, 11828,
11273, 12093, 12384, 13204, 10306, 11126, 11417, 12237, 11682, 12502, 12793,
13613, 11943, 12763, 13054, 13874, 13319, 14139, 14430, 15250, 10306, 11126,
11417, 12237, 11682, 12502, 12793, 13613, 11943, 12763, 13054, 13874, 13319,
14139, 14430, 15250, 12352, 13172, 13463, 14283, 13728, 14548, 14839, 15659,
13989, 14809, 15100, 15920, 15365, 16185, 16476, 17296, 6214, 7034, 7325,
8145, 7590, 8410, 8701, 9521, 7851, 8671, 8962, 9782, 9227, 10047, 10338,
11158, 8260, 9080, 9371, 10191, 9636, 10456, 10747, 11567, 9897, 10717,
11008, 11828, 11273, 12093, 12384, 13204, 8260, 9080, 9371, 10191, 9636,
10456, 10747, 11567, 9897, 10717, 11008, 11828, 11273, 12093, 12384, 13204,
10306, 11126, 11417, 12237, 11682, 12502, 12793, 13613, 11943, 12763, 13054,
13874, 13319, 14139, 14430, 15250, 8260, 9080, 9371, 10191, 9636, 10456,
10747, 11567, 9897, 10717, 11008, 11828, 11273, 12093, 12384, 13204, 10306,
11126, 11417, 12237, 11682, 12502, 12793, 13613, 11943, 12763, 13054, 13874,
13319, 14139, 14430, 15250, 10306, 11126, 11417, 12237, 11682, 12502, 12793,
13613, 11943, 12763, 13054, 13874, 13319, 14139, 14430, 15250, 12352, 13172,
13463, 14283, 13728, 14548, 14839, 15659, 13989, 14809, 15100, 15920, 15365,
16185, 16476, 17296, 8260, 9080, 9371, 10191, 9636, 10456, 10747, 11567,
9897, 10717, 11008, 11828, 11273, 12093, 12384, 13204, 10306, 11126, 11417,
12237, 11682, 12502, 12793, 13613, 11943, 12763, 13054, 13874, 13319, 14139,
14430, 15250, 10306, 11126, 11417, 12237, 11682, 12502, 12793, 13613, 11943,
12763, 13054, 13874, 13319, 14139, 14430, 15250, 12352, 13172, 13463, 14283,
13728, 14548, 14839, 15659, 13989, 14809, 15100, 15920, 15365, 16185, 16476,
17296, 10306, 11126, 11417, 12237, 11682, 12502, 12793, 13613, 11943, 12763,
13054, 13874, 13319, 14139, 14430, 15250, 12352, 13172, 13463, 14283, 13728,
14548, 14839, 15659, 13989, 14809, 15100, 15920, 15365, 16185, 16476, 17296,
12352, 13172, 13463, 14283, 13728, 14548, 14839, 15659, 13989, 14809, 15100,
15920, 15365, 16185, 16476, 17296, 14398, 15218, 15509, 16329, 15774, 16594,
16885, 17705, 16035, 16855, 17146, 17966, 17411, 18231, 18522, 19342
};
#endif
#if CONFIG_VP9_HIGHBITDEPTH
static const vp9_tree_index cat1_high10[2] = {0, 0};
static const vp9_tree_index cat2_high10[4] = {2, 2, 0, 0};
static const vp9_tree_index cat3_high10[6] = {2, 2, 4, 4, 0, 0};
static const vp9_tree_index cat4_high10[8] = {2, 2, 4, 4, 6, 6, 0, 0};
static const vp9_tree_index cat5_high10[10] = {2, 2, 4, 4, 6, 6, 8, 8, 0, 0};
static const vp9_tree_index cat6_high10[32] = {2, 2, 4, 4, 6, 6, 8, 8, 10, 10,
12, 12, 14, 14, 16, 16, 18, 18, 20, 20, 22, 22, 24, 24, 26, 26, 28, 28,
30, 30, 0, 0};
static const vp9_tree_index cat1_high12[2] = {0, 0};
static const vp9_tree_index cat2_high12[4] = {2, 2, 0, 0};
static const vp9_tree_index cat3_high12[6] = {2, 2, 4, 4, 0, 0};
static const vp9_tree_index cat4_high12[8] = {2, 2, 4, 4, 6, 6, 0, 0};
static const vp9_tree_index cat5_high12[10] = {2, 2, 4, 4, 6, 6, 8, 8, 0, 0};
static const vp9_tree_index cat6_high12[36] = {2, 2, 4, 4, 6, 6, 8, 8, 10, 10,
12, 12, 14, 14, 16, 16, 18, 18, 20, 20, 22, 22, 24, 24, 26, 26, 28, 28,
30, 30, 32, 32, 34, 34, 0, 0};
#endif
const vp9_extra_bit vp9_extra_bits[ENTROPY_TOKENS] = {
{0, 0, 0, 0, zero_cost}, // ZERO_TOKEN
{0, 0, 0, 1, one_cost}, // ONE_TOKEN
{0, 0, 0, 2, two_cost}, // TWO_TOKEN
{0, 0, 0, 3, three_cost}, // THREE_TOKEN
{0, 0, 0, 4, four_cost}, // FOUR_TOKEN
{cat1, vp9_cat1_prob, 1, CAT1_MIN_VAL, cat1_cost}, // CATEGORY1_TOKEN
{cat2, vp9_cat2_prob, 2, CAT2_MIN_VAL, cat2_cost}, // CATEGORY2_TOKEN
{cat3, vp9_cat3_prob, 3, CAT3_MIN_VAL, cat3_cost}, // CATEGORY3_TOKEN
{cat4, vp9_cat4_prob, 4, CAT4_MIN_VAL, cat4_cost}, // CATEGORY4_TOKEN
{cat5, vp9_cat5_prob, 5, CAT5_MIN_VAL, cat5_cost}, // CATEGORY5_TOKEN
{cat6, vp9_cat6_prob, 14, CAT6_MIN_VAL, 0}, // CATEGORY6_TOKEN
{0, 0, 0, 0, zero_cost} // EOB_TOKEN
};
#if CONFIG_VP9_HIGHBITDEPTH
const vp9_extra_bit vp9_extra_bits_high10[ENTROPY_TOKENS] = {
{0, 0, 0, 0, zero_cost}, // ZERO
{0, 0, 0, 1, one_cost}, // ONE
{0, 0, 0, 2, two_cost}, // TWO
{0, 0, 0, 3, three_cost}, // THREE
{0, 0, 0, 4, four_cost}, // FOUR
{cat1_high10, vp9_cat1_prob_high10, 1, CAT1_MIN_VAL, cat1_cost}, // CAT1
{cat2_high10, vp9_cat2_prob_high10, 2, CAT2_MIN_VAL, cat2_cost}, // CAT2
{cat3_high10, vp9_cat3_prob_high10, 3, CAT3_MIN_VAL, cat3_cost}, // CAT3
{cat4_high10, vp9_cat4_prob_high10, 4, CAT4_MIN_VAL, cat4_cost}, // CAT4
{cat5_high10, vp9_cat5_prob_high10, 5, CAT5_MIN_VAL, cat5_cost}, // CAT5
{cat6_high10, vp9_cat6_prob_high10, 16, CAT6_MIN_VAL, 0}, // CAT6
{0, 0, 0, 0, zero_cost} // EOB
};
const vp9_extra_bit vp9_extra_bits_high12[ENTROPY_TOKENS] = {
{0, 0, 0, 0, zero_cost}, // ZERO
{0, 0, 0, 1, one_cost}, // ONE
{0, 0, 0, 2, two_cost}, // TWO
{0, 0, 0, 3, three_cost}, // THREE
{0, 0, 0, 4, four_cost}, // FOUR
{cat1_high12, vp9_cat1_prob_high12, 1, CAT1_MIN_VAL, cat1_cost}, // CAT1
{cat2_high12, vp9_cat2_prob_high12, 2, CAT2_MIN_VAL, cat2_cost}, // CAT2
{cat3_high12, vp9_cat3_prob_high12, 3, CAT3_MIN_VAL, cat3_cost}, // CAT3
{cat4_high12, vp9_cat4_prob_high12, 4, CAT4_MIN_VAL, cat4_cost}, // CAT4
{cat5_high12, vp9_cat5_prob_high12, 5, CAT5_MIN_VAL, cat5_cost}, // CAT5
{cat6_high12, vp9_cat6_prob_high12, 18, CAT6_MIN_VAL, 0}, // CAT6
{0, 0, 0, 0, zero_cost} // EOB
};
#endif
const struct vp9_token vp9_coef_encodings[ENTROPY_TOKENS] = {
{2, 2}, {6, 3}, {28, 5}, {58, 6}, {59, 6}, {60, 6}, {61, 6}, {124, 7},
{125, 7}, {126, 7}, {127, 7}, {0, 1}
};
struct tokenize_b_args {
VP9_COMP *cpi;
ThreadData *td;
TOKENEXTRA **tp;
};
static void set_entropy_context_b(int plane, int block, BLOCK_SIZE plane_bsize,
TX_SIZE tx_size, void *arg) {
struct tokenize_b_args* const args = arg;
ThreadData *const td = args->td;
MACROBLOCK *const x = &td->mb;
MACROBLOCKD *const xd = &x->e_mbd;
struct macroblock_plane *p = &x->plane[plane];
struct macroblockd_plane *pd = &xd->plane[plane];
int aoff, loff;
txfrm_block_to_raster_xy(plane_bsize, tx_size, block, &aoff, &loff);
vp9_set_contexts(xd, pd, plane_bsize, tx_size, p->eobs[block] > 0,
aoff, loff);
}
static INLINE void add_token(TOKENEXTRA **t, const vp9_prob *context_tree,
int32_t extra, uint8_t token,
uint8_t skip_eob_node,
unsigned int *counts) {
(*t)->token = token;
(*t)->extra = extra;
(*t)->context_tree = context_tree;
(*t)->skip_eob_node = skip_eob_node;
(*t)++;
++counts[token];
}
static INLINE void add_token_no_extra(TOKENEXTRA **t,
const vp9_prob *context_tree,
uint8_t token,
uint8_t skip_eob_node,
unsigned int *counts) {
(*t)->token = token;
(*t)->context_tree = context_tree;
(*t)->skip_eob_node = skip_eob_node;
(*t)++;
++counts[token];
}
static INLINE int get_tx_eob(const struct segmentation *seg, int segment_id,
TX_SIZE tx_size) {
const int eob_max = 16 << (tx_size << 1);
return vp9_segfeature_active(seg, segment_id, SEG_LVL_SKIP) ? 0 : eob_max;
}
static void tokenize_b(int plane, int block, BLOCK_SIZE plane_bsize,
TX_SIZE tx_size, void *arg) {
struct tokenize_b_args* const args = arg;
VP9_COMP *cpi = args->cpi;
ThreadData *const td = args->td;
MACROBLOCK *const x = &td->mb;
MACROBLOCKD *const xd = &x->e_mbd;
TOKENEXTRA **tp = args->tp;
uint8_t token_cache[32 * 32];
struct macroblock_plane *p = &x->plane[plane];
struct macroblockd_plane *pd = &xd->plane[plane];
MB_MODE_INFO *mbmi = &xd->mi[0]->mbmi;
int pt; /* near block/prev token context index */
int c;
TOKENEXTRA *t = *tp; /* store tokens starting here */
int eob = p->eobs[block];
const PLANE_TYPE type = pd->plane_type;
const tran_low_t *qcoeff = BLOCK_OFFSET(p->qcoeff, block);
const int segment_id = mbmi->segment_id;
const int16_t *scan, *nb;
const scan_order *so;
const int ref = is_inter_block(mbmi);
unsigned int (*const counts)[COEFF_CONTEXTS][ENTROPY_TOKENS] =
td->rd_counts.coef_counts[tx_size][type][ref];
vp9_prob (*const coef_probs)[COEFF_CONTEXTS][UNCONSTRAINED_NODES] =
cpi->common.fc->coef_probs[tx_size][type][ref];
unsigned int (*const eob_branch)[COEFF_CONTEXTS] =
td->counts->eob_branch[tx_size][type][ref];
const uint8_t *const band = get_band_translate(tx_size);
const int seg_eob = get_tx_eob(&cpi->common.seg, segment_id, tx_size);
int16_t token;
EXTRABIT extra;
int aoff, loff;
txfrm_block_to_raster_xy(plane_bsize, tx_size, block, &aoff, &loff);
pt = get_entropy_context(tx_size, pd->above_context + aoff,
pd->left_context + loff);
so = get_scan(xd, tx_size, type, block);
scan = so->scan;
nb = so->neighbors;
c = 0;
while (c < eob) {
int v = 0;
int skip_eob = 0;
v = qcoeff[scan[c]];
while (!v) {
add_token_no_extra(&t, coef_probs[band[c]][pt], ZERO_TOKEN, skip_eob,
counts[band[c]][pt]);
eob_branch[band[c]][pt] += !skip_eob;
skip_eob = 1;
token_cache[scan[c]] = 0;
++c;
pt = get_coef_context(nb, token_cache, c);
v = qcoeff[scan[c]];
}
vp9_get_token_extra(v, &token, &extra);
add_token(&t, coef_probs[band[c]][pt], extra, (uint8_t)token,
(uint8_t)skip_eob, counts[band[c]][pt]);
eob_branch[band[c]][pt] += !skip_eob;
token_cache[scan[c]] = vp9_pt_energy_class[token];
++c;
pt = get_coef_context(nb, token_cache, c);
}
if (c < seg_eob) {
add_token_no_extra(&t, coef_probs[band[c]][pt], EOB_TOKEN, 0,
counts[band[c]][pt]);
++eob_branch[band[c]][pt];
}
*tp = t;
vp9_set_contexts(xd, pd, plane_bsize, tx_size, c > 0, aoff, loff);
}
struct is_skippable_args {
MACROBLOCK *x;
int *skippable;
};
static void is_skippable(int plane, int block,
BLOCK_SIZE plane_bsize, TX_SIZE tx_size,
void *argv) {
struct is_skippable_args *args = argv;
(void)plane_bsize;
(void)tx_size;
args->skippable[0] &= (!args->x->plane[plane].eobs[block]);
}
// TODO(yaowu): rewrite and optimize this function to remove the usage of
// vp9_foreach_transform_block() and simplify is_skippable().
int vp9_is_skippable_in_plane(MACROBLOCK *x, BLOCK_SIZE bsize, int plane) {
int result = 1;
struct is_skippable_args args = {x, &result};
vp9_foreach_transformed_block_in_plane(&x->e_mbd, bsize, plane, is_skippable,
&args);
return result;
}
static void has_high_freq_coeff(int plane, int block,
BLOCK_SIZE plane_bsize, TX_SIZE tx_size,
void *argv) {
struct is_skippable_args *args = argv;
int eobs = (tx_size == TX_4X4) ? 3 : 10;
(void) plane_bsize;
*(args->skippable) |= (args->x->plane[plane].eobs[block] > eobs);
}
int vp9_has_high_freq_in_plane(MACROBLOCK *x, BLOCK_SIZE bsize, int plane) {
int result = 0;
struct is_skippable_args args = {x, &result};
vp9_foreach_transformed_block_in_plane(&x->e_mbd, bsize, plane,
has_high_freq_coeff, &args);
return result;
}
void vp9_tokenize_sb(VP9_COMP *cpi, ThreadData *td, TOKENEXTRA **t,
int dry_run, BLOCK_SIZE bsize) {
VP9_COMMON *const cm = &cpi->common;
MACROBLOCK *const x = &td->mb;
MACROBLOCKD *const xd = &x->e_mbd;
MB_MODE_INFO *const mbmi = &xd->mi[0]->mbmi;
const int ctx = vp9_get_skip_context(xd);
const int skip_inc = !vp9_segfeature_active(&cm->seg, mbmi->segment_id,
SEG_LVL_SKIP);
struct tokenize_b_args arg = {cpi, td, t};
if (mbmi->skip) {
if (!dry_run)
td->counts->skip[ctx][1] += skip_inc;
reset_skip_context(xd, bsize);
return;
}
if (!dry_run) {
td->counts->skip[ctx][0] += skip_inc;
vp9_foreach_transformed_block(xd, bsize, tokenize_b, &arg);
} else {
vp9_foreach_transformed_block(xd, bsize, set_entropy_context_b, &arg);
}
}

View file

@ -0,0 +1,112 @@
/*
* 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.
*/
#ifndef VP9_ENCODER_VP9_TOKENIZE_H_
#define VP9_ENCODER_VP9_TOKENIZE_H_
#include "vp9/common/vp9_entropy.h"
#include "vp9/encoder/vp9_block.h"
#include "vp9/encoder/vp9_treewriter.h"
#ifdef __cplusplus
extern "C" {
#endif
#define EOSB_TOKEN 127 // Not signalled, encoder only
#if CONFIG_VP9_HIGHBITDEPTH
typedef int32_t EXTRABIT;
#else
typedef int16_t EXTRABIT;
#endif
typedef struct {
int16_t token;
EXTRABIT extra;
} TOKENVALUE;
typedef struct {
const vp9_prob *context_tree;
EXTRABIT extra;
uint8_t token;
uint8_t skip_eob_node;
} TOKENEXTRA;
extern const vp9_tree_index vp9_coef_tree[];
extern const vp9_tree_index vp9_coef_con_tree[];
extern const struct vp9_token vp9_coef_encodings[];
int vp9_is_skippable_in_plane(MACROBLOCK *x, BLOCK_SIZE bsize, int plane);
int vp9_has_high_freq_in_plane(MACROBLOCK *x, BLOCK_SIZE bsize, int plane);
struct VP9_COMP;
struct ThreadData;
void vp9_tokenize_sb(struct VP9_COMP *cpi, struct ThreadData *td,
TOKENEXTRA **t, int dry_run, BLOCK_SIZE bsize);
extern const int16_t *vp9_dct_value_cost_ptr;
/* TODO: The Token field should be broken out into a separate char array to
* improve cache locality, since it's needed for costing when the rest of the
* fields are not.
*/
extern const TOKENVALUE *vp9_dct_value_tokens_ptr;
extern const TOKENVALUE *vp9_dct_cat_lt_10_value_tokens;
extern const int16_t vp9_cat6_low_cost[256];
extern const int16_t vp9_cat6_high_cost[128];
extern const int16_t vp9_cat6_high10_high_cost[512];
extern const int16_t vp9_cat6_high12_high_cost[2048];
static INLINE int16_t vp9_get_cost(int16_t token, EXTRABIT extrabits,
const int16_t *cat6_high_table) {
if (token != CATEGORY6_TOKEN)
return vp9_extra_bits[token].cost[extrabits];
return vp9_cat6_low_cost[extrabits & 0xff]
+ cat6_high_table[extrabits >> 8];
}
#if CONFIG_VP9_HIGHBITDEPTH
static INLINE const int16_t* vp9_get_high_cost_table(int bit_depth) {
return bit_depth == 8 ? vp9_cat6_high_cost
: (bit_depth == 10 ? vp9_cat6_high10_high_cost :
vp9_cat6_high12_high_cost);
}
#else
static INLINE const int16_t* vp9_get_high_cost_table(int bit_depth) {
(void) bit_depth;
return vp9_cat6_high_cost;
}
#endif // CONFIG_VP9_HIGHBITDEPTH
static INLINE void vp9_get_token_extra(int v, int16_t *token, EXTRABIT *extra) {
if (v >= CAT6_MIN_VAL || v <= -CAT6_MIN_VAL) {
*token = CATEGORY6_TOKEN;
if (v >= CAT6_MIN_VAL)
*extra = 2 * v - 2 * CAT6_MIN_VAL;
else
*extra = -2 * v - 2 * CAT6_MIN_VAL + 1;
return;
}
*token = vp9_dct_cat_lt_10_value_tokens[v].token;
*extra = vp9_dct_cat_lt_10_value_tokens[v].extra;
}
static INLINE int16_t vp9_get_token(int v) {
if (v >= CAT6_MIN_VAL || v <= -CAT6_MIN_VAL)
return 10;
return vp9_dct_cat_lt_10_value_tokens[v].token;
}
#ifdef __cplusplus
} // extern "C"
#endif
#endif // VP9_ENCODER_VP9_TOKENIZE_H_

View file

@ -0,0 +1,58 @@
/*
* 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 "vp9/encoder/vp9_treewriter.h"
static void tree2tok(struct vp9_token *tokens, const vp9_tree_index *tree,
int i, int v, int l) {
v += v;
++l;
do {
const vp9_tree_index j = tree[i++];
if (j <= 0) {
tokens[-j].value = v;
tokens[-j].len = l;
} else {
tree2tok(tokens, tree, j, v, l);
}
} while (++v & 1);
}
void vp9_tokens_from_tree(struct vp9_token *tokens,
const vp9_tree_index *tree) {
tree2tok(tokens, tree, 0, 0, 0);
}
static unsigned int convert_distribution(unsigned int i, vp9_tree tree,
unsigned int branch_ct[][2],
const unsigned int num_events[]) {
unsigned int left, right;
if (tree[i] <= 0)
left = num_events[-tree[i]];
else
left = convert_distribution(tree[i], tree, branch_ct, num_events);
if (tree[i + 1] <= 0)
right = num_events[-tree[i + 1]];
else
right = convert_distribution(tree[i + 1], tree, branch_ct, num_events);
branch_ct[i >> 1][0] = left;
branch_ct[i >> 1][1] = right;
return left + right;
}
void vp9_tree_probs_from_distribution(vp9_tree tree,
unsigned int branch_ct[/* n-1 */][2],
const unsigned int num_events[/* n */]) {
convert_distribution(0, tree, branch_ct, num_events);
}

View file

@ -0,0 +1,51 @@
/*
* 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.
*/
#ifndef VP9_ENCODER_VP9_TREEWRITER_H_
#define VP9_ENCODER_VP9_TREEWRITER_H_
#include "vp9/encoder/vp9_writer.h"
#ifdef __cplusplus
extern "C" {
#endif
void vp9_tree_probs_from_distribution(vp9_tree tree,
unsigned int branch_ct[ /* n - 1 */ ][2],
const unsigned int num_events[ /* n */ ]);
struct vp9_token {
int value;
int len;
};
void vp9_tokens_from_tree(struct vp9_token*, const vp9_tree_index *);
static INLINE void vp9_write_tree(vp9_writer *w, const vp9_tree_index *tree,
const vp9_prob *probs, int bits, int len,
vp9_tree_index i) {
do {
const int bit = (bits >> --len) & 1;
vp9_write(w, bit, probs[i >> 1]);
i = tree[i + bit];
} while (len);
}
static INLINE void vp9_write_token(vp9_writer *w, const vp9_tree_index *tree,
const vp9_prob *probs,
const struct vp9_token *token) {
vp9_write_tree(w, tree, probs, token->value, token->len, 0);
}
#ifdef __cplusplus
} // extern "C"
#endif
#endif // VP9_ENCODER_VP9_TREEWRITER_H_

View file

@ -0,0 +1,380 @@
/*
* 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 "./vp9_rtcd.h"
#include "./vpx_dsp_rtcd.h"
#include "vpx_ports/mem.h"
#include "vpx/vpx_integer.h"
#include "vp9/common/vp9_common.h"
#include "vp9/common/vp9_filter.h"
#include "vp9/encoder/vp9_variance.h"
static uint8_t bilinear_filters[8][2] = {
{ 128, 0, },
{ 112, 16, },
{ 96, 32, },
{ 80, 48, },
{ 64, 64, },
{ 48, 80, },
{ 32, 96, },
{ 16, 112, },
};
// Applies a 1-D 2-tap bi-linear filter to the source block in either horizontal
// or vertical direction to produce the filtered output block. Used to implement
// first-pass of 2-D separable filter.
//
// Produces int32_t output to retain precision for next pass. Two filter taps
// should sum to VP9_FILTER_WEIGHT. pixel_step defines whether the filter is
// applied horizontally (pixel_step=1) or vertically (pixel_step=stride). It
// defines the offset required to move from one input to the next.
static void var_filter_block2d_bil_first_pass(const uint8_t *src_ptr,
uint16_t *output_ptr,
unsigned int src_pixels_per_line,
int pixel_step,
unsigned int output_height,
unsigned int output_width,
const uint8_t *vp9_filter) {
unsigned int i, j;
for (i = 0; i < output_height; i++) {
for (j = 0; j < output_width; j++) {
output_ptr[j] = ROUND_POWER_OF_TWO((int)src_ptr[0] * vp9_filter[0] +
(int)src_ptr[pixel_step] * vp9_filter[1],
FILTER_BITS);
src_ptr++;
}
// Next row...
src_ptr += src_pixels_per_line - output_width;
output_ptr += output_width;
}
}
// Applies a 1-D 2-tap bi-linear filter to the source block in either horizontal
// or vertical direction to produce the filtered output block. Used to implement
// second-pass of 2-D separable filter.
//
// Requires 32-bit input as produced by filter_block2d_bil_first_pass. Two
// filter taps should sum to VP9_FILTER_WEIGHT. pixel_step defines whether the
// filter is applied horizontally (pixel_step=1) or vertically (pixel_step=
// stride). It defines the offset required to move from one input to the next.
static void var_filter_block2d_bil_second_pass(const uint16_t *src_ptr,
uint8_t *output_ptr,
unsigned int src_pixels_per_line,
unsigned int pixel_step,
unsigned int output_height,
unsigned int output_width,
const uint8_t *vp9_filter) {
unsigned int i, j;
for (i = 0; i < output_height; i++) {
for (j = 0; j < output_width; j++) {
output_ptr[j] = ROUND_POWER_OF_TWO((int)src_ptr[0] * vp9_filter[0] +
(int)src_ptr[pixel_step] * vp9_filter[1],
FILTER_BITS);
src_ptr++;
}
src_ptr += src_pixels_per_line - output_width;
output_ptr += output_width;
}
}
#define SUBPIX_VAR(W, H) \
unsigned int vp9_sub_pixel_variance##W##x##H##_c( \
const uint8_t *src, int src_stride, \
int xoffset, int yoffset, \
const uint8_t *dst, int dst_stride, \
unsigned int *sse) { \
uint16_t fdata3[(H + 1) * W]; \
uint8_t temp2[H * W]; \
\
var_filter_block2d_bil_first_pass(src, fdata3, src_stride, 1, H + 1, W, \
bilinear_filters[xoffset]); \
var_filter_block2d_bil_second_pass(fdata3, temp2, W, W, H, W, \
bilinear_filters[yoffset]); \
\
return vpx_variance##W##x##H##_c(temp2, W, dst, dst_stride, sse); \
}
#define SUBPIX_AVG_VAR(W, H) \
unsigned int vp9_sub_pixel_avg_variance##W##x##H##_c( \
const uint8_t *src, int src_stride, \
int xoffset, int yoffset, \
const uint8_t *dst, int dst_stride, \
unsigned int *sse, \
const uint8_t *second_pred) { \
uint16_t fdata3[(H + 1) * W]; \
uint8_t temp2[H * W]; \
DECLARE_ALIGNED(16, uint8_t, temp3[H * W]); \
\
var_filter_block2d_bil_first_pass(src, fdata3, src_stride, 1, H + 1, W, \
bilinear_filters[xoffset]); \
var_filter_block2d_bil_second_pass(fdata3, temp2, W, W, H, W, \
bilinear_filters[yoffset]); \
\
vpx_comp_avg_pred(temp3, second_pred, W, H, temp2, W); \
\
return vpx_variance##W##x##H##_c(temp3, W, dst, dst_stride, sse); \
}
SUBPIX_VAR(4, 4)
SUBPIX_AVG_VAR(4, 4)
SUBPIX_VAR(4, 8)
SUBPIX_AVG_VAR(4, 8)
SUBPIX_VAR(8, 4)
SUBPIX_AVG_VAR(8, 4)
SUBPIX_VAR(8, 8)
SUBPIX_AVG_VAR(8, 8)
SUBPIX_VAR(8, 16)
SUBPIX_AVG_VAR(8, 16)
SUBPIX_VAR(16, 8)
SUBPIX_AVG_VAR(16, 8)
SUBPIX_VAR(16, 16)
SUBPIX_AVG_VAR(16, 16)
SUBPIX_VAR(16, 32)
SUBPIX_AVG_VAR(16, 32)
SUBPIX_VAR(32, 16)
SUBPIX_AVG_VAR(32, 16)
SUBPIX_VAR(32, 32)
SUBPIX_AVG_VAR(32, 32)
SUBPIX_VAR(32, 64)
SUBPIX_AVG_VAR(32, 64)
SUBPIX_VAR(64, 32)
SUBPIX_AVG_VAR(64, 32)
SUBPIX_VAR(64, 64)
SUBPIX_AVG_VAR(64, 64)
#if CONFIG_VP9_HIGHBITDEPTH
static void highbd_var_filter_block2d_bil_first_pass(
const uint8_t *src_ptr8,
uint16_t *output_ptr,
unsigned int src_pixels_per_line,
int pixel_step,
unsigned int output_height,
unsigned int output_width,
const uint8_t *vp9_filter) {
unsigned int i, j;
uint16_t *src_ptr = CONVERT_TO_SHORTPTR(src_ptr8);
for (i = 0; i < output_height; i++) {
for (j = 0; j < output_width; j++) {
output_ptr[j] =
ROUND_POWER_OF_TWO((int)src_ptr[0] * vp9_filter[0] +
(int)src_ptr[pixel_step] * vp9_filter[1],
FILTER_BITS);
src_ptr++;
}
// Next row...
src_ptr += src_pixels_per_line - output_width;
output_ptr += output_width;
}
}
static void highbd_var_filter_block2d_bil_second_pass(
const uint16_t *src_ptr,
uint16_t *output_ptr,
unsigned int src_pixels_per_line,
unsigned int pixel_step,
unsigned int output_height,
unsigned int output_width,
const uint8_t *vp9_filter) {
unsigned int i, j;
for (i = 0; i < output_height; i++) {
for (j = 0; j < output_width; j++) {
output_ptr[j] =
ROUND_POWER_OF_TWO((int)src_ptr[0] * vp9_filter[0] +
(int)src_ptr[pixel_step] * vp9_filter[1],
FILTER_BITS);
src_ptr++;
}
src_ptr += src_pixels_per_line - output_width;
output_ptr += output_width;
}
}
#define HIGHBD_SUBPIX_VAR(W, H) \
unsigned int vp9_highbd_sub_pixel_variance##W##x##H##_c( \
const uint8_t *src, int src_stride, \
int xoffset, int yoffset, \
const uint8_t *dst, int dst_stride, \
unsigned int *sse) { \
uint16_t fdata3[(H + 1) * W]; \
uint16_t temp2[H * W]; \
\
highbd_var_filter_block2d_bil_first_pass(src, fdata3, src_stride, 1, H + 1, \
W, bilinear_filters[xoffset]); \
highbd_var_filter_block2d_bil_second_pass(fdata3, temp2, W, W, H, W, \
bilinear_filters[yoffset]); \
\
return vpx_highbd_8_variance##W##x##H##_c(CONVERT_TO_BYTEPTR(temp2), W, dst, \
dst_stride, sse); \
} \
\
unsigned int vp9_highbd_10_sub_pixel_variance##W##x##H##_c( \
const uint8_t *src, int src_stride, \
int xoffset, int yoffset, \
const uint8_t *dst, int dst_stride, \
unsigned int *sse) { \
uint16_t fdata3[(H + 1) * W]; \
uint16_t temp2[H * W]; \
\
highbd_var_filter_block2d_bil_first_pass(src, fdata3, src_stride, 1, H + 1, \
W, bilinear_filters[xoffset]); \
highbd_var_filter_block2d_bil_second_pass(fdata3, temp2, W, W, H, W, \
bilinear_filters[yoffset]); \
\
return vpx_highbd_10_variance##W##x##H##_c(CONVERT_TO_BYTEPTR(temp2), \
W, dst, dst_stride, sse); \
} \
\
unsigned int vp9_highbd_12_sub_pixel_variance##W##x##H##_c( \
const uint8_t *src, int src_stride, \
int xoffset, int yoffset, \
const uint8_t *dst, int dst_stride, \
unsigned int *sse) { \
uint16_t fdata3[(H + 1) * W]; \
uint16_t temp2[H * W]; \
\
highbd_var_filter_block2d_bil_first_pass(src, fdata3, src_stride, 1, H + 1, \
W, bilinear_filters[xoffset]); \
highbd_var_filter_block2d_bil_second_pass(fdata3, temp2, W, W, H, W, \
bilinear_filters[yoffset]); \
\
return vpx_highbd_12_variance##W##x##H##_c(CONVERT_TO_BYTEPTR(temp2), \
W, dst, dst_stride, sse); \
}
#define HIGHBD_SUBPIX_AVG_VAR(W, H) \
unsigned int vp9_highbd_sub_pixel_avg_variance##W##x##H##_c( \
const uint8_t *src, int src_stride, \
int xoffset, int yoffset, \
const uint8_t *dst, int dst_stride, \
unsigned int *sse, \
const uint8_t *second_pred) { \
uint16_t fdata3[(H + 1) * W]; \
uint16_t temp2[H * W]; \
DECLARE_ALIGNED(16, uint16_t, temp3[H * W]); \
\
highbd_var_filter_block2d_bil_first_pass(src, fdata3, src_stride, 1, H + 1, \
W, bilinear_filters[xoffset]); \
highbd_var_filter_block2d_bil_second_pass(fdata3, temp2, W, W, H, W, \
bilinear_filters[yoffset]); \
\
vpx_highbd_comp_avg_pred(temp3, second_pred, W, H, \
CONVERT_TO_BYTEPTR(temp2), W); \
\
return vpx_highbd_8_variance##W##x##H##_c(CONVERT_TO_BYTEPTR(temp3), W, dst, \
dst_stride, sse); \
} \
\
unsigned int vp9_highbd_10_sub_pixel_avg_variance##W##x##H##_c( \
const uint8_t *src, int src_stride, \
int xoffset, int yoffset, \
const uint8_t *dst, int dst_stride, \
unsigned int *sse, \
const uint8_t *second_pred) { \
uint16_t fdata3[(H + 1) * W]; \
uint16_t temp2[H * W]; \
DECLARE_ALIGNED(16, uint16_t, temp3[H * W]); \
\
highbd_var_filter_block2d_bil_first_pass(src, fdata3, src_stride, 1, H + 1, \
W, bilinear_filters[xoffset]); \
highbd_var_filter_block2d_bil_second_pass(fdata3, temp2, W, W, H, W, \
bilinear_filters[yoffset]); \
\
vpx_highbd_comp_avg_pred(temp3, second_pred, W, H, \
CONVERT_TO_BYTEPTR(temp2), W); \
\
return vpx_highbd_10_variance##W##x##H##_c(CONVERT_TO_BYTEPTR(temp3), \
W, dst, dst_stride, sse); \
} \
\
unsigned int vp9_highbd_12_sub_pixel_avg_variance##W##x##H##_c( \
const uint8_t *src, int src_stride, \
int xoffset, int yoffset, \
const uint8_t *dst, int dst_stride, \
unsigned int *sse, \
const uint8_t *second_pred) { \
uint16_t fdata3[(H + 1) * W]; \
uint16_t temp2[H * W]; \
DECLARE_ALIGNED(16, uint16_t, temp3[H * W]); \
\
highbd_var_filter_block2d_bil_first_pass(src, fdata3, src_stride, 1, H + 1, \
W, bilinear_filters[xoffset]); \
highbd_var_filter_block2d_bil_second_pass(fdata3, temp2, W, W, H, W, \
bilinear_filters[yoffset]); \
\
vpx_highbd_comp_avg_pred(temp3, second_pred, W, H, \
CONVERT_TO_BYTEPTR(temp2), W); \
\
return vpx_highbd_12_variance##W##x##H##_c(CONVERT_TO_BYTEPTR(temp3), \
W, dst, dst_stride, sse); \
}
HIGHBD_SUBPIX_VAR(4, 4)
HIGHBD_SUBPIX_AVG_VAR(4, 4)
HIGHBD_SUBPIX_VAR(4, 8)
HIGHBD_SUBPIX_AVG_VAR(4, 8)
HIGHBD_SUBPIX_VAR(8, 4)
HIGHBD_SUBPIX_AVG_VAR(8, 4)
HIGHBD_SUBPIX_VAR(8, 8)
HIGHBD_SUBPIX_AVG_VAR(8, 8)
HIGHBD_SUBPIX_VAR(8, 16)
HIGHBD_SUBPIX_AVG_VAR(8, 16)
HIGHBD_SUBPIX_VAR(16, 8)
HIGHBD_SUBPIX_AVG_VAR(16, 8)
HIGHBD_SUBPIX_VAR(16, 16)
HIGHBD_SUBPIX_AVG_VAR(16, 16)
HIGHBD_SUBPIX_VAR(16, 32)
HIGHBD_SUBPIX_AVG_VAR(16, 32)
HIGHBD_SUBPIX_VAR(32, 16)
HIGHBD_SUBPIX_AVG_VAR(32, 16)
HIGHBD_SUBPIX_VAR(32, 32)
HIGHBD_SUBPIX_AVG_VAR(32, 32)
HIGHBD_SUBPIX_VAR(32, 64)
HIGHBD_SUBPIX_AVG_VAR(32, 64)
HIGHBD_SUBPIX_VAR(64, 32)
HIGHBD_SUBPIX_AVG_VAR(64, 32)
HIGHBD_SUBPIX_VAR(64, 64)
HIGHBD_SUBPIX_AVG_VAR(64, 64)
#endif // CONFIG_VP9_HIGHBITDEPTH

View file

@ -0,0 +1,81 @@
/*
* 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.
*/
#ifndef VP9_ENCODER_VP9_VARIANCE_H_
#define VP9_ENCODER_VP9_VARIANCE_H_
#include "vpx/vpx_integer.h"
#include "vpx_ports/mem.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef unsigned int(*vp9_sad_fn_t)(const uint8_t *src_ptr,
int source_stride,
const uint8_t *ref_ptr,
int ref_stride);
typedef unsigned int(*vp9_sad_avg_fn_t)(const uint8_t *src_ptr,
int source_stride,
const uint8_t *ref_ptr,
int ref_stride,
const uint8_t *second_pred);
typedef void (*vp9_sad_multi_fn_t)(const uint8_t *src_ptr,
int source_stride,
const uint8_t *ref_ptr,
int ref_stride,
unsigned int *sad_array);
typedef void (*vp9_sad_multi_d_fn_t)(const uint8_t *src_ptr,
int source_stride,
const uint8_t* const ref_ptr[],
int ref_stride, unsigned int *sad_array);
typedef unsigned int (*vp9_variance_fn_t)(const uint8_t *src_ptr,
int source_stride,
const uint8_t *ref_ptr,
int ref_stride,
unsigned int *sse);
typedef unsigned int (*vp9_subpixvariance_fn_t)(const uint8_t *src_ptr,
int source_stride,
int xoffset,
int yoffset,
const uint8_t *ref_ptr,
int Refstride,
unsigned int *sse);
typedef unsigned int (*vp9_subp_avg_variance_fn_t)(const uint8_t *src_ptr,
int source_stride,
int xoffset,
int yoffset,
const uint8_t *ref_ptr,
int Refstride,
unsigned int *sse,
const uint8_t *second_pred);
typedef struct vp9_variance_vtable {
vp9_sad_fn_t sdf;
vp9_sad_avg_fn_t sdaf;
vp9_variance_fn_t vf;
vp9_subpixvariance_fn_t svf;
vp9_subp_avg_variance_fn_t svaf;
vp9_sad_multi_fn_t sdx3f;
vp9_sad_multi_fn_t sdx8f;
vp9_sad_multi_d_fn_t sdx4df;
} vp9_variance_fn_ptr_t;
#ifdef __cplusplus
} // extern "C"
#endif
#endif // VP9_ENCODER_VP9_VARIANCE_H_

View file

@ -0,0 +1,35 @@
/*
* Copyright (c) 2013 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <limits.h>
#include "vp9/encoder/vp9_write_bit_buffer.h"
size_t vp9_wb_bytes_written(const struct vp9_write_bit_buffer *wb) {
return wb->bit_offset / CHAR_BIT + (wb->bit_offset % CHAR_BIT > 0);
}
void vp9_wb_write_bit(struct vp9_write_bit_buffer *wb, int bit) {
const int off = (int)wb->bit_offset;
const int p = off / CHAR_BIT;
const int q = CHAR_BIT - 1 - off % CHAR_BIT;
if (q == CHAR_BIT -1) {
wb->bit_buffer[p] = bit << q;
} else {
wb->bit_buffer[p] &= ~(1 << q);
wb->bit_buffer[p] |= bit << q;
}
wb->bit_offset = off + 1;
}
void vp9_wb_write_literal(struct vp9_write_bit_buffer *wb, int data, int bits) {
int bit;
for (bit = bits - 1; bit >= 0; bit--)
vp9_wb_write_bit(wb, (data >> bit) & 1);
}

View file

@ -0,0 +1,36 @@
/*
* Copyright (c) 2013 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.
*/
#ifndef VP9_ENCODER_VP9_WRITE_BIT_BUFFER_H_
#define VP9_ENCODER_VP9_WRITE_BIT_BUFFER_H_
#include "vpx/vpx_integer.h"
#ifdef __cplusplus
extern "C" {
#endif
struct vp9_write_bit_buffer {
uint8_t *bit_buffer;
size_t bit_offset;
};
size_t vp9_wb_bytes_written(const struct vp9_write_bit_buffer *wb);
void vp9_wb_write_bit(struct vp9_write_bit_buffer *wb, int bit);
void vp9_wb_write_literal(struct vp9_write_bit_buffer *wb, int data, int bits);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // VP9_ENCODER_VP9_WRITE_BIT_BUFFER_H_

View file

@ -0,0 +1,34 @@
/*
* 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 <assert.h>
#include "vp9/encoder/vp9_writer.h"
#include "vp9/common/vp9_entropy.h"
void vp9_start_encode(vp9_writer *br, uint8_t *source) {
br->lowvalue = 0;
br->range = 255;
br->count = -24;
br->buffer = source;
br->pos = 0;
vp9_write_bit(br, 0);
}
void vp9_stop_encode(vp9_writer *br) {
int i;
for (i = 0; i < 32; i++)
vp9_write_bit(br, 0);
// Ensure there's no ambigous collision with any index marker bytes
if ((br->buffer[br->pos - 1] & 0xe0) == 0xc0)
br->buffer[br->pos++] = 0;
}

View file

@ -0,0 +1,98 @@
/*
* 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.
*/
#ifndef VP9_ENCODER_VP9_WRITER_H_
#define VP9_ENCODER_VP9_WRITER_H_
#include "vpx_ports/mem.h"
#include "vp9/common/vp9_prob.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct vp9_writer {
unsigned int lowvalue;
unsigned int range;
int count;
unsigned int pos;
uint8_t *buffer;
} vp9_writer;
void vp9_start_encode(vp9_writer *bc, uint8_t *buffer);
void vp9_stop_encode(vp9_writer *bc);
static INLINE void vp9_write(vp9_writer *br, int bit, int probability) {
unsigned int split;
int count = br->count;
unsigned int range = br->range;
unsigned int lowvalue = br->lowvalue;
register unsigned int shift;
split = 1 + (((range - 1) * probability) >> 8);
range = split;
if (bit) {
lowvalue += split;
range = br->range - split;
}
shift = vp9_norm[range];
range <<= shift;
count += shift;
if (count >= 0) {
int offset = shift - count;
if ((lowvalue << (offset - 1)) & 0x80000000) {
int x = br->pos - 1;
while (x >= 0 && br->buffer[x] == 0xff) {
br->buffer[x] = 0;
x--;
}
br->buffer[x] += 1;
}
br->buffer[br->pos++] = (lowvalue >> (24 - offset));
lowvalue <<= offset;
shift = count;
lowvalue &= 0xffffff;
count -= 8;
}
lowvalue <<= shift;
br->count = count;
br->lowvalue = lowvalue;
br->range = range;
}
static INLINE void vp9_write_bit(vp9_writer *w, int bit) {
vp9_write(w, bit, 128); // vp9_prob_half
}
static INLINE void vp9_write_literal(vp9_writer *w, int data, int bits) {
int bit;
for (bit = bits - 1; bit >= 0; bit--)
vp9_write_bit(w, 1 & (data >> bit));
}
#define vp9_write_prob(w, v) vp9_write_literal((w), (v), 8)
#ifdef __cplusplus
} // extern "C"
#endif
#endif // VP9_ENCODER_VP9_WRITER_H_

View file

@ -0,0 +1,423 @@
/*
* Copyright (c) 2014 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 <emmintrin.h>
#include "./vp9_rtcd.h"
#include "vpx_ports/mem.h"
void vp9_minmax_8x8_sse2(const uint8_t *s, int p, const uint8_t *d, int dp,
int *min, int *max) {
__m128i u0, s0, d0, diff, maxabsdiff, minabsdiff, negdiff, absdiff0, absdiff;
u0 = _mm_setzero_si128();
// Row 0
s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s)), u0);
d0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(d)), u0);
diff = _mm_subs_epi16(s0, d0);
negdiff = _mm_subs_epi16(u0, diff);
absdiff0 = _mm_max_epi16(diff, negdiff);
// Row 1
s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + p)), u0);
d0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(d + dp)), u0);
diff = _mm_subs_epi16(s0, d0);
negdiff = _mm_subs_epi16(u0, diff);
absdiff = _mm_max_epi16(diff, negdiff);
maxabsdiff = _mm_max_epi16(absdiff0, absdiff);
minabsdiff = _mm_min_epi16(absdiff0, absdiff);
// Row 2
s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 2 * p)), u0);
d0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(d + 2 * dp)), u0);
diff = _mm_subs_epi16(s0, d0);
negdiff = _mm_subs_epi16(u0, diff);
absdiff = _mm_max_epi16(diff, negdiff);
maxabsdiff = _mm_max_epi16(maxabsdiff, absdiff);
minabsdiff = _mm_min_epi16(minabsdiff, absdiff);
// Row 3
s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 3 * p)), u0);
d0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(d + 3 * dp)), u0);
diff = _mm_subs_epi16(s0, d0);
negdiff = _mm_subs_epi16(u0, diff);
absdiff = _mm_max_epi16(diff, negdiff);
maxabsdiff = _mm_max_epi16(maxabsdiff, absdiff);
minabsdiff = _mm_min_epi16(minabsdiff, absdiff);
// Row 4
s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 4 * p)), u0);
d0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(d + 4 * dp)), u0);
diff = _mm_subs_epi16(s0, d0);
negdiff = _mm_subs_epi16(u0, diff);
absdiff = _mm_max_epi16(diff, negdiff);
maxabsdiff = _mm_max_epi16(maxabsdiff, absdiff);
minabsdiff = _mm_min_epi16(minabsdiff, absdiff);
// Row 5
s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 5 * p)), u0);
d0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(d + 5 * dp)), u0);
diff = _mm_subs_epi16(s0, d0);
negdiff = _mm_subs_epi16(u0, diff);
absdiff = _mm_max_epi16(diff, negdiff);
maxabsdiff = _mm_max_epi16(maxabsdiff, absdiff);
minabsdiff = _mm_min_epi16(minabsdiff, absdiff);
// Row 6
s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 6 * p)), u0);
d0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(d + 6 * dp)), u0);
diff = _mm_subs_epi16(s0, d0);
negdiff = _mm_subs_epi16(u0, diff);
absdiff = _mm_max_epi16(diff, negdiff);
maxabsdiff = _mm_max_epi16(maxabsdiff, absdiff);
minabsdiff = _mm_min_epi16(minabsdiff, absdiff);
// Row 7
s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 7 * p)), u0);
d0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(d + 7 * dp)), u0);
diff = _mm_subs_epi16(s0, d0);
negdiff = _mm_subs_epi16(u0, diff);
absdiff = _mm_max_epi16(diff, negdiff);
maxabsdiff = _mm_max_epi16(maxabsdiff, absdiff);
minabsdiff = _mm_min_epi16(minabsdiff, absdiff);
maxabsdiff = _mm_max_epi16(maxabsdiff, _mm_srli_si128(maxabsdiff, 8));
maxabsdiff = _mm_max_epi16(maxabsdiff, _mm_srli_epi64(maxabsdiff, 32));
maxabsdiff = _mm_max_epi16(maxabsdiff, _mm_srli_epi64(maxabsdiff, 16));
*max = _mm_extract_epi16(maxabsdiff, 0);
minabsdiff = _mm_min_epi16(minabsdiff, _mm_srli_si128(minabsdiff, 8));
minabsdiff = _mm_min_epi16(minabsdiff, _mm_srli_epi64(minabsdiff, 32));
minabsdiff = _mm_min_epi16(minabsdiff, _mm_srli_epi64(minabsdiff, 16));
*min = _mm_extract_epi16(minabsdiff, 0);
}
unsigned int vp9_avg_8x8_sse2(const uint8_t *s, int p) {
__m128i s0, s1, u0;
unsigned int avg = 0;
u0 = _mm_setzero_si128();
s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s)), u0);
s1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + p)), u0);
s0 = _mm_adds_epu16(s0, s1);
s1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 2 * p)), u0);
s0 = _mm_adds_epu16(s0, s1);
s1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 3 * p)), u0);
s0 = _mm_adds_epu16(s0, s1);
s1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 4 * p)), u0);
s0 = _mm_adds_epu16(s0, s1);
s1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 5 * p)), u0);
s0 = _mm_adds_epu16(s0, s1);
s1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 6 * p)), u0);
s0 = _mm_adds_epu16(s0, s1);
s1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 7 * p)), u0);
s0 = _mm_adds_epu16(s0, s1);
s0 = _mm_adds_epu16(s0, _mm_srli_si128(s0, 8));
s0 = _mm_adds_epu16(s0, _mm_srli_epi64(s0, 32));
s0 = _mm_adds_epu16(s0, _mm_srli_epi64(s0, 16));
avg = _mm_extract_epi16(s0, 0);
return (avg + 32) >> 6;
}
unsigned int vp9_avg_4x4_sse2(const uint8_t *s, int p) {
__m128i s0, s1, u0;
unsigned int avg = 0;
u0 = _mm_setzero_si128();
s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s)), u0);
s1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + p)), u0);
s0 = _mm_adds_epu16(s0, s1);
s1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 2 * p)), u0);
s0 = _mm_adds_epu16(s0, s1);
s1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 3 * p)), u0);
s0 = _mm_adds_epu16(s0, s1);
s0 = _mm_adds_epu16(s0, _mm_srli_si128(s0, 4));
s0 = _mm_adds_epu16(s0, _mm_srli_epi64(s0, 16));
avg = _mm_extract_epi16(s0, 0);
return (avg + 8) >> 4;
}
static void hadamard_col8_sse2(__m128i *in, int iter) {
__m128i a0 = in[0];
__m128i a1 = in[1];
__m128i a2 = in[2];
__m128i a3 = in[3];
__m128i a4 = in[4];
__m128i a5 = in[5];
__m128i a6 = in[6];
__m128i a7 = in[7];
__m128i b0 = _mm_add_epi16(a0, a1);
__m128i b1 = _mm_sub_epi16(a0, a1);
__m128i b2 = _mm_add_epi16(a2, a3);
__m128i b3 = _mm_sub_epi16(a2, a3);
__m128i b4 = _mm_add_epi16(a4, a5);
__m128i b5 = _mm_sub_epi16(a4, a5);
__m128i b6 = _mm_add_epi16(a6, a7);
__m128i b7 = _mm_sub_epi16(a6, a7);
a0 = _mm_add_epi16(b0, b2);
a1 = _mm_add_epi16(b1, b3);
a2 = _mm_sub_epi16(b0, b2);
a3 = _mm_sub_epi16(b1, b3);
a4 = _mm_add_epi16(b4, b6);
a5 = _mm_add_epi16(b5, b7);
a6 = _mm_sub_epi16(b4, b6);
a7 = _mm_sub_epi16(b5, b7);
if (iter == 0) {
b0 = _mm_add_epi16(a0, a4);
b7 = _mm_add_epi16(a1, a5);
b3 = _mm_add_epi16(a2, a6);
b4 = _mm_add_epi16(a3, a7);
b2 = _mm_sub_epi16(a0, a4);
b6 = _mm_sub_epi16(a1, a5);
b1 = _mm_sub_epi16(a2, a6);
b5 = _mm_sub_epi16(a3, a7);
a0 = _mm_unpacklo_epi16(b0, b1);
a1 = _mm_unpacklo_epi16(b2, b3);
a2 = _mm_unpackhi_epi16(b0, b1);
a3 = _mm_unpackhi_epi16(b2, b3);
a4 = _mm_unpacklo_epi16(b4, b5);
a5 = _mm_unpacklo_epi16(b6, b7);
a6 = _mm_unpackhi_epi16(b4, b5);
a7 = _mm_unpackhi_epi16(b6, b7);
b0 = _mm_unpacklo_epi32(a0, a1);
b1 = _mm_unpacklo_epi32(a4, a5);
b2 = _mm_unpackhi_epi32(a0, a1);
b3 = _mm_unpackhi_epi32(a4, a5);
b4 = _mm_unpacklo_epi32(a2, a3);
b5 = _mm_unpacklo_epi32(a6, a7);
b6 = _mm_unpackhi_epi32(a2, a3);
b7 = _mm_unpackhi_epi32(a6, a7);
in[0] = _mm_unpacklo_epi64(b0, b1);
in[1] = _mm_unpackhi_epi64(b0, b1);
in[2] = _mm_unpacklo_epi64(b2, b3);
in[3] = _mm_unpackhi_epi64(b2, b3);
in[4] = _mm_unpacklo_epi64(b4, b5);
in[5] = _mm_unpackhi_epi64(b4, b5);
in[6] = _mm_unpacklo_epi64(b6, b7);
in[7] = _mm_unpackhi_epi64(b6, b7);
} else {
in[0] = _mm_add_epi16(a0, a4);
in[7] = _mm_add_epi16(a1, a5);
in[3] = _mm_add_epi16(a2, a6);
in[4] = _mm_add_epi16(a3, a7);
in[2] = _mm_sub_epi16(a0, a4);
in[6] = _mm_sub_epi16(a1, a5);
in[1] = _mm_sub_epi16(a2, a6);
in[5] = _mm_sub_epi16(a3, a7);
}
}
void vp9_hadamard_8x8_sse2(int16_t const *src_diff, int src_stride,
int16_t *coeff) {
__m128i src[8];
src[0] = _mm_load_si128((const __m128i *)src_diff);
src[1] = _mm_load_si128((const __m128i *)(src_diff += src_stride));
src[2] = _mm_load_si128((const __m128i *)(src_diff += src_stride));
src[3] = _mm_load_si128((const __m128i *)(src_diff += src_stride));
src[4] = _mm_load_si128((const __m128i *)(src_diff += src_stride));
src[5] = _mm_load_si128((const __m128i *)(src_diff += src_stride));
src[6] = _mm_load_si128((const __m128i *)(src_diff += src_stride));
src[7] = _mm_load_si128((const __m128i *)(src_diff += src_stride));
hadamard_col8_sse2(src, 0);
hadamard_col8_sse2(src, 1);
_mm_store_si128((__m128i *)coeff, src[0]);
coeff += 8;
_mm_store_si128((__m128i *)coeff, src[1]);
coeff += 8;
_mm_store_si128((__m128i *)coeff, src[2]);
coeff += 8;
_mm_store_si128((__m128i *)coeff, src[3]);
coeff += 8;
_mm_store_si128((__m128i *)coeff, src[4]);
coeff += 8;
_mm_store_si128((__m128i *)coeff, src[5]);
coeff += 8;
_mm_store_si128((__m128i *)coeff, src[6]);
coeff += 8;
_mm_store_si128((__m128i *)coeff, src[7]);
}
void vp9_hadamard_16x16_sse2(int16_t const *src_diff, int src_stride,
int16_t *coeff) {
int idx;
for (idx = 0; idx < 4; ++idx) {
int16_t const *src_ptr = src_diff + (idx >> 1) * 8 * src_stride
+ (idx & 0x01) * 8;
vp9_hadamard_8x8_sse2(src_ptr, src_stride, coeff + idx * 64);
}
for (idx = 0; idx < 64; idx += 8) {
__m128i coeff0 = _mm_load_si128((const __m128i *)coeff);
__m128i coeff1 = _mm_load_si128((const __m128i *)(coeff + 64));
__m128i coeff2 = _mm_load_si128((const __m128i *)(coeff + 128));
__m128i coeff3 = _mm_load_si128((const __m128i *)(coeff + 192));
__m128i b0 = _mm_add_epi16(coeff0, coeff1);
__m128i b1 = _mm_sub_epi16(coeff0, coeff1);
__m128i b2 = _mm_add_epi16(coeff2, coeff3);
__m128i b3 = _mm_sub_epi16(coeff2, coeff3);
coeff0 = _mm_add_epi16(b0, b2);
coeff1 = _mm_add_epi16(b1, b3);
coeff0 = _mm_srai_epi16(coeff0, 1);
coeff1 = _mm_srai_epi16(coeff1, 1);
_mm_store_si128((__m128i *)coeff, coeff0);
_mm_store_si128((__m128i *)(coeff + 64), coeff1);
coeff2 = _mm_sub_epi16(b0, b2);
coeff3 = _mm_sub_epi16(b1, b3);
coeff2 = _mm_srai_epi16(coeff2, 1);
coeff3 = _mm_srai_epi16(coeff3, 1);
_mm_store_si128((__m128i *)(coeff + 128), coeff2);
_mm_store_si128((__m128i *)(coeff + 192), coeff3);
coeff += 8;
}
}
int16_t vp9_satd_sse2(const int16_t *coeff, int length) {
int i;
__m128i sum = _mm_load_si128((const __m128i *)coeff);
__m128i sign = _mm_srai_epi16(sum, 15);
__m128i val = _mm_xor_si128(sum, sign);
sum = _mm_sub_epi16(val, sign);
coeff += 8;
for (i = 8; i < length; i += 8) {
__m128i src_line = _mm_load_si128((const __m128i *)coeff);
sign = _mm_srai_epi16(src_line, 15);
val = _mm_xor_si128(src_line, sign);
val = _mm_sub_epi16(val, sign);
sum = _mm_add_epi16(sum, val);
coeff += 8;
}
val = _mm_srli_si128(sum, 8);
sum = _mm_add_epi16(sum, val);
val = _mm_srli_epi64(sum, 32);
sum = _mm_add_epi16(sum, val);
val = _mm_srli_epi32(sum, 16);
sum = _mm_add_epi16(sum, val);
return _mm_extract_epi16(sum, 0);
}
void vp9_int_pro_row_sse2(int16_t *hbuf, uint8_t const*ref,
const int ref_stride, const int height) {
int idx;
__m128i zero = _mm_setzero_si128();
__m128i src_line = _mm_loadu_si128((const __m128i *)ref);
__m128i s0 = _mm_unpacklo_epi8(src_line, zero);
__m128i s1 = _mm_unpackhi_epi8(src_line, zero);
__m128i t0, t1;
int height_1 = height - 1;
ref += ref_stride;
for (idx = 1; idx < height_1; idx += 2) {
src_line = _mm_loadu_si128((const __m128i *)ref);
t0 = _mm_unpacklo_epi8(src_line, zero);
t1 = _mm_unpackhi_epi8(src_line, zero);
s0 = _mm_adds_epu16(s0, t0);
s1 = _mm_adds_epu16(s1, t1);
ref += ref_stride;
src_line = _mm_loadu_si128((const __m128i *)ref);
t0 = _mm_unpacklo_epi8(src_line, zero);
t1 = _mm_unpackhi_epi8(src_line, zero);
s0 = _mm_adds_epu16(s0, t0);
s1 = _mm_adds_epu16(s1, t1);
ref += ref_stride;
}
src_line = _mm_loadu_si128((const __m128i *)ref);
t0 = _mm_unpacklo_epi8(src_line, zero);
t1 = _mm_unpackhi_epi8(src_line, zero);
s0 = _mm_adds_epu16(s0, t0);
s1 = _mm_adds_epu16(s1, t1);
if (height == 64) {
s0 = _mm_srai_epi16(s0, 5);
s1 = _mm_srai_epi16(s1, 5);
} else if (height == 32) {
s0 = _mm_srai_epi16(s0, 4);
s1 = _mm_srai_epi16(s1, 4);
} else {
s0 = _mm_srai_epi16(s0, 3);
s1 = _mm_srai_epi16(s1, 3);
}
_mm_storeu_si128((__m128i *)hbuf, s0);
hbuf += 8;
_mm_storeu_si128((__m128i *)hbuf, s1);
}
int16_t vp9_int_pro_col_sse2(uint8_t const *ref, const int width) {
__m128i zero = _mm_setzero_si128();
__m128i src_line = _mm_load_si128((const __m128i *)ref);
__m128i s0 = _mm_sad_epu8(src_line, zero);
__m128i s1;
int i;
for (i = 16; i < width; i += 16) {
ref += 16;
src_line = _mm_load_si128((const __m128i *)ref);
s1 = _mm_sad_epu8(src_line, zero);
s0 = _mm_adds_epu16(s0, s1);
}
s1 = _mm_srli_si128(s0, 8);
s0 = _mm_adds_epu16(s0, s1);
return _mm_extract_epi16(s0, 0);
}
int vp9_vector_var_sse2(int16_t const *ref, int16_t const *src,
const int bwl) {
int idx;
int width = 4 << bwl;
int16_t mean;
__m128i v0 = _mm_loadu_si128((const __m128i *)ref);
__m128i v1 = _mm_load_si128((const __m128i *)src);
__m128i diff = _mm_subs_epi16(v0, v1);
__m128i sum = diff;
__m128i sse = _mm_madd_epi16(diff, diff);
ref += 8;
src += 8;
for (idx = 8; idx < width; idx += 8) {
v0 = _mm_loadu_si128((const __m128i *)ref);
v1 = _mm_load_si128((const __m128i *)src);
diff = _mm_subs_epi16(v0, v1);
sum = _mm_add_epi16(sum, diff);
v0 = _mm_madd_epi16(diff, diff);
sse = _mm_add_epi32(sse, v0);
ref += 8;
src += 8;
}
v0 = _mm_srli_si128(sum, 8);
sum = _mm_add_epi16(sum, v0);
v0 = _mm_srli_epi64(sum, 32);
sum = _mm_add_epi16(sum, v0);
v0 = _mm_srli_epi32(sum, 16);
sum = _mm_add_epi16(sum, v0);
v1 = _mm_srli_si128(sse, 8);
sse = _mm_add_epi32(sse, v1);
v1 = _mm_srli_epi64(sse, 32);
sse = _mm_add_epi32(sse, v1);
mean = _mm_extract_epi16(sum, 0);
return _mm_cvtsi128_si32(sse) - ((mean * mean) >> (bwl + 2));
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,26 @@
/*
* Copyright (c) 2012 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 <immintrin.h> // AVX2
#include "vp9/common/vp9_idct.h" // for cospi constants
#include "vpx_ports/mem.h"
#define FDCT32x32_2D_AVX2 vp9_fdct32x32_rd_avx2
#define FDCT32x32_HIGH_PRECISION 0
#include "vp9/encoder/x86/vp9_dct32x32_avx2_impl.h"
#undef FDCT32x32_2D_AVX2
#undef FDCT32x32_HIGH_PRECISION
#define FDCT32x32_2D_AVX2 vp9_fdct32x32_avx2
#define FDCT32x32_HIGH_PRECISION 1
#include "vp9/encoder/x86/vp9_dct32x32_avx2_impl.h" // NOLINT
#undef FDCT32x32_2D_AVX2
#undef FDCT32x32_HIGH_PRECISION

View file

@ -0,0 +1,101 @@
;
; Copyright (c) 2014 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 "third_party/x86inc/x86inc.asm"
SECTION .text
%macro TRANSFORM_COLS 0
paddw m0, m1
movq m4, m0
psubw m3, m2
psubw m4, m3
psraw m4, 1
movq m5, m4
psubw m5, m1 ;b1
psubw m4, m2 ;c1
psubw m0, m4
paddw m3, m5
; m0 a0
SWAP 1, 4 ; m1 c1
SWAP 2, 3 ; m2 d1
SWAP 3, 5 ; m3 b1
%endmacro
%macro TRANSPOSE_4X4 0
movq m4, m0
movq m5, m2
punpcklwd m4, m1
punpckhwd m0, m1
punpcklwd m5, m3
punpckhwd m2, m3
movq m1, m4
movq m3, m0
punpckldq m1, m5
punpckhdq m4, m5
punpckldq m3, m2
punpckhdq m0, m2
SWAP 2, 3, 0, 1, 4
%endmacro
INIT_MMX mmx
cglobal fwht4x4, 3, 4, 8, input, output, stride
lea r3q, [inputq + strideq*4]
movq m0, [inputq] ;a1
movq m1, [inputq + strideq*2] ;b1
movq m2, [r3q] ;c1
movq m3, [r3q + strideq*2] ;d1
TRANSFORM_COLS
TRANSPOSE_4X4
TRANSFORM_COLS
TRANSPOSE_4X4
psllw m0, 2
psllw m1, 2
psllw m2, 2
psllw m3, 2
%if CONFIG_VP9_HIGHBITDEPTH
pxor m4, m4
pxor m5, m5
pcmpgtw m4, m0
pcmpgtw m5, m1
movq m6, m0
movq m7, m1
punpcklwd m0, m4
punpcklwd m1, m5
punpckhwd m6, m4
punpckhwd m7, m5
movq [outputq], m0
movq [outputq + 8], m6
movq [outputq + 16], m1
movq [outputq + 24], m7
pxor m4, m4
pxor m5, m5
pcmpgtw m4, m2
pcmpgtw m5, m3
movq m6, m2
movq m7, m3
punpcklwd m2, m4
punpcklwd m3, m5
punpckhwd m6, m4
punpckhwd m7, m5
movq [outputq + 32], m2
movq [outputq + 40], m6
movq [outputq + 48], m3
movq [outputq + 56], m7
%else
movq [outputq], m0
movq [outputq + 8], m1
movq [outputq + 16], m2
movq [outputq + 24], m3
%endif
RET

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,464 @@
/*
* Copyright (c) 2014 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.
*/
#ifndef VP9_ENCODER_X86_VP9_DCT_SSE2_H_
#define VP9_ENCODER_X86_VP9_DCT_SSE2_H_
#ifdef __cplusplus
extern "C" {
#endif
#define pair_set_epi32(a, b) \
_mm_set_epi32((int)(b), (int)(a), (int)(b), (int)(a))
void vp9_fdct4x4_sse2(const int16_t *input, tran_low_t *output, int stride);
void vp9_fdct8x8_sse2(const int16_t *input, tran_low_t *output, int stride);
void vp9_fdct16x16_sse2(const int16_t *input, tran_low_t *output, int stride);
void vp9_highbd_fdct4x4_sse2(const int16_t *input, tran_low_t *output,
int stride);
void vp9_highbd_fdct8x8_sse2(const int16_t *input, tran_low_t *output,
int stride);
void vp9_highbd_fdct16x16_sse2(const int16_t *input, tran_low_t *output,
int stride);
static INLINE __m128i k_madd_epi32(__m128i a, __m128i b) {
__m128i buf0, buf1;
buf0 = _mm_mul_epu32(a, b);
a = _mm_srli_epi64(a, 32);
b = _mm_srli_epi64(b, 32);
buf1 = _mm_mul_epu32(a, b);
return _mm_add_epi64(buf0, buf1);
}
static INLINE __m128i k_packs_epi64(__m128i a, __m128i b) {
__m128i buf0 = _mm_shuffle_epi32(a, _MM_SHUFFLE(0, 0, 2, 0));
__m128i buf1 = _mm_shuffle_epi32(b, _MM_SHUFFLE(0, 0, 2, 0));
return _mm_unpacklo_epi64(buf0, buf1);
}
static INLINE int check_epi16_overflow_x2(const __m128i *preg0,
const __m128i *preg1) {
const __m128i max_overflow = _mm_set1_epi16(0x7fff);
const __m128i min_overflow = _mm_set1_epi16(0x8000);
__m128i cmp0 = _mm_or_si128(_mm_cmpeq_epi16(*preg0, max_overflow),
_mm_cmpeq_epi16(*preg0, min_overflow));
__m128i cmp1 = _mm_or_si128(_mm_cmpeq_epi16(*preg1, max_overflow),
_mm_cmpeq_epi16(*preg1, min_overflow));
cmp0 = _mm_or_si128(cmp0, cmp1);
return _mm_movemask_epi8(cmp0);
}
static INLINE int check_epi16_overflow_x4(const __m128i *preg0,
const __m128i *preg1,
const __m128i *preg2,
const __m128i *preg3) {
const __m128i max_overflow = _mm_set1_epi16(0x7fff);
const __m128i min_overflow = _mm_set1_epi16(0x8000);
__m128i cmp0 = _mm_or_si128(_mm_cmpeq_epi16(*preg0, max_overflow),
_mm_cmpeq_epi16(*preg0, min_overflow));
__m128i cmp1 = _mm_or_si128(_mm_cmpeq_epi16(*preg1, max_overflow),
_mm_cmpeq_epi16(*preg1, min_overflow));
__m128i cmp2 = _mm_or_si128(_mm_cmpeq_epi16(*preg2, max_overflow),
_mm_cmpeq_epi16(*preg2, min_overflow));
__m128i cmp3 = _mm_or_si128(_mm_cmpeq_epi16(*preg3, max_overflow),
_mm_cmpeq_epi16(*preg3, min_overflow));
cmp0 = _mm_or_si128(_mm_or_si128(cmp0, cmp1), _mm_or_si128(cmp2, cmp3));
return _mm_movemask_epi8(cmp0);
}
static INLINE int check_epi16_overflow_x8(const __m128i *preg0,
const __m128i *preg1,
const __m128i *preg2,
const __m128i *preg3,
const __m128i *preg4,
const __m128i *preg5,
const __m128i *preg6,
const __m128i *preg7) {
int res0, res1;
res0 = check_epi16_overflow_x4(preg0, preg1, preg2, preg3);
res1 = check_epi16_overflow_x4(preg4, preg5, preg6, preg7);
return res0 + res1;
}
static INLINE int check_epi16_overflow_x12(const __m128i *preg0,
const __m128i *preg1,
const __m128i *preg2,
const __m128i *preg3,
const __m128i *preg4,
const __m128i *preg5,
const __m128i *preg6,
const __m128i *preg7,
const __m128i *preg8,
const __m128i *preg9,
const __m128i *preg10,
const __m128i *preg11) {
int res0, res1;
res0 = check_epi16_overflow_x4(preg0, preg1, preg2, preg3);
res1 = check_epi16_overflow_x4(preg4, preg5, preg6, preg7);
if (!res0)
res0 = check_epi16_overflow_x4(preg8, preg9, preg10, preg11);
return res0 + res1;
}
static INLINE int check_epi16_overflow_x16(const __m128i *preg0,
const __m128i *preg1,
const __m128i *preg2,
const __m128i *preg3,
const __m128i *preg4,
const __m128i *preg5,
const __m128i *preg6,
const __m128i *preg7,
const __m128i *preg8,
const __m128i *preg9,
const __m128i *preg10,
const __m128i *preg11,
const __m128i *preg12,
const __m128i *preg13,
const __m128i *preg14,
const __m128i *preg15) {
int res0, res1;
res0 = check_epi16_overflow_x4(preg0, preg1, preg2, preg3);
res1 = check_epi16_overflow_x4(preg4, preg5, preg6, preg7);
if (!res0) {
res0 = check_epi16_overflow_x4(preg8, preg9, preg10, preg11);
if (!res1)
res1 = check_epi16_overflow_x4(preg12, preg13, preg14, preg15);
}
return res0 + res1;
}
static INLINE int check_epi16_overflow_x32(const __m128i *preg0,
const __m128i *preg1,
const __m128i *preg2,
const __m128i *preg3,
const __m128i *preg4,
const __m128i *preg5,
const __m128i *preg6,
const __m128i *preg7,
const __m128i *preg8,
const __m128i *preg9,
const __m128i *preg10,
const __m128i *preg11,
const __m128i *preg12,
const __m128i *preg13,
const __m128i *preg14,
const __m128i *preg15,
const __m128i *preg16,
const __m128i *preg17,
const __m128i *preg18,
const __m128i *preg19,
const __m128i *preg20,
const __m128i *preg21,
const __m128i *preg22,
const __m128i *preg23,
const __m128i *preg24,
const __m128i *preg25,
const __m128i *preg26,
const __m128i *preg27,
const __m128i *preg28,
const __m128i *preg29,
const __m128i *preg30,
const __m128i *preg31) {
int res0, res1;
res0 = check_epi16_overflow_x4(preg0, preg1, preg2, preg3);
res1 = check_epi16_overflow_x4(preg4, preg5, preg6, preg7);
if (!res0) {
res0 = check_epi16_overflow_x4(preg8, preg9, preg10, preg11);
if (!res1) {
res1 = check_epi16_overflow_x4(preg12, preg13, preg14, preg15);
if (!res0) {
res0 = check_epi16_overflow_x4(preg16, preg17, preg18, preg19);
if (!res1) {
res1 = check_epi16_overflow_x4(preg20, preg21, preg22, preg23);
if (!res0) {
res0 = check_epi16_overflow_x4(preg24, preg25, preg26, preg27);
if (!res1)
res1 = check_epi16_overflow_x4(preg28, preg29, preg30, preg31);
}
}
}
}
}
return res0 + res1;
}
static INLINE int k_check_epi32_overflow_4(const __m128i *preg0,
const __m128i *preg1,
const __m128i *preg2,
const __m128i *preg3,
const __m128i *zero) {
__m128i minus_one = _mm_set1_epi32(-1);
// Check for overflows
__m128i reg0_shifted = _mm_slli_epi64(*preg0, 1);
__m128i reg1_shifted = _mm_slli_epi64(*preg1, 1);
__m128i reg2_shifted = _mm_slli_epi64(*preg2, 1);
__m128i reg3_shifted = _mm_slli_epi64(*preg3, 1);
__m128i reg0_top_dwords = _mm_shuffle_epi32(
reg0_shifted, _MM_SHUFFLE(0, 0, 3, 1));
__m128i reg1_top_dwords = _mm_shuffle_epi32(
reg1_shifted, _MM_SHUFFLE(0, 0, 3, 1));
__m128i reg2_top_dwords = _mm_shuffle_epi32(
reg2_shifted, _MM_SHUFFLE(0, 0, 3, 1));
__m128i reg3_top_dwords = _mm_shuffle_epi32(
reg3_shifted, _MM_SHUFFLE(0, 0, 3, 1));
__m128i top_dwords_01 = _mm_unpacklo_epi64(reg0_top_dwords, reg1_top_dwords);
__m128i top_dwords_23 = _mm_unpacklo_epi64(reg2_top_dwords, reg3_top_dwords);
__m128i valid_positve_01 = _mm_cmpeq_epi32(top_dwords_01, *zero);
__m128i valid_positve_23 = _mm_cmpeq_epi32(top_dwords_23, *zero);
__m128i valid_negative_01 = _mm_cmpeq_epi32(top_dwords_01, minus_one);
__m128i valid_negative_23 = _mm_cmpeq_epi32(top_dwords_23, minus_one);
int overflow_01 = _mm_movemask_epi8(
_mm_cmpeq_epi32(valid_positve_01, valid_negative_01));
int overflow_23 = _mm_movemask_epi8(
_mm_cmpeq_epi32(valid_positve_23, valid_negative_23));
return (overflow_01 + overflow_23);
}
static INLINE int k_check_epi32_overflow_8(const __m128i *preg0,
const __m128i *preg1,
const __m128i *preg2,
const __m128i *preg3,
const __m128i *preg4,
const __m128i *preg5,
const __m128i *preg6,
const __m128i *preg7,
const __m128i *zero) {
int overflow = k_check_epi32_overflow_4(preg0, preg1, preg2, preg3, zero);
if (!overflow) {
overflow = k_check_epi32_overflow_4(preg4, preg5, preg6, preg7, zero);
}
return overflow;
}
static INLINE int k_check_epi32_overflow_16(const __m128i *preg0,
const __m128i *preg1,
const __m128i *preg2,
const __m128i *preg3,
const __m128i *preg4,
const __m128i *preg5,
const __m128i *preg6,
const __m128i *preg7,
const __m128i *preg8,
const __m128i *preg9,
const __m128i *preg10,
const __m128i *preg11,
const __m128i *preg12,
const __m128i *preg13,
const __m128i *preg14,
const __m128i *preg15,
const __m128i *zero) {
int overflow = k_check_epi32_overflow_4(preg0, preg1, preg2, preg3, zero);
if (!overflow) {
overflow = k_check_epi32_overflow_4(preg4, preg5, preg6, preg7, zero);
if (!overflow) {
overflow = k_check_epi32_overflow_4(preg8, preg9, preg10, preg11,
zero);
if (!overflow) {
overflow = k_check_epi32_overflow_4(preg12, preg13, preg14, preg15,
zero);
}
}
}
return overflow;
}
static INLINE int k_check_epi32_overflow_32(const __m128i *preg0,
const __m128i *preg1,
const __m128i *preg2,
const __m128i *preg3,
const __m128i *preg4,
const __m128i *preg5,
const __m128i *preg6,
const __m128i *preg7,
const __m128i *preg8,
const __m128i *preg9,
const __m128i *preg10,
const __m128i *preg11,
const __m128i *preg12,
const __m128i *preg13,
const __m128i *preg14,
const __m128i *preg15,
const __m128i *preg16,
const __m128i *preg17,
const __m128i *preg18,
const __m128i *preg19,
const __m128i *preg20,
const __m128i *preg21,
const __m128i *preg22,
const __m128i *preg23,
const __m128i *preg24,
const __m128i *preg25,
const __m128i *preg26,
const __m128i *preg27,
const __m128i *preg28,
const __m128i *preg29,
const __m128i *preg30,
const __m128i *preg31,
const __m128i *zero) {
int overflow = k_check_epi32_overflow_4(preg0, preg1, preg2, preg3, zero);
if (!overflow) {
overflow = k_check_epi32_overflow_4(preg4, preg5, preg6, preg7, zero);
if (!overflow) {
overflow = k_check_epi32_overflow_4(preg8, preg9, preg10, preg11, zero);
if (!overflow) {
overflow = k_check_epi32_overflow_4(preg12, preg13, preg14, preg15,
zero);
if (!overflow) {
overflow = k_check_epi32_overflow_4(preg16, preg17, preg18, preg19,
zero);
if (!overflow) {
overflow = k_check_epi32_overflow_4(preg20, preg21,
preg22, preg23, zero);
if (!overflow) {
overflow = k_check_epi32_overflow_4(preg24, preg25,
preg26, preg27, zero);
if (!overflow) {
overflow = k_check_epi32_overflow_4(preg28, preg29,
preg30, preg31, zero);
}
}
}
}
}
}
}
return overflow;
}
static INLINE void store_output(const __m128i *poutput, tran_low_t* dst_ptr) {
#if CONFIG_VP9_HIGHBITDEPTH
const __m128i zero = _mm_setzero_si128();
const __m128i sign_bits = _mm_cmplt_epi16(*poutput, zero);
__m128i out0 = _mm_unpacklo_epi16(*poutput, sign_bits);
__m128i out1 = _mm_unpackhi_epi16(*poutput, sign_bits);
_mm_store_si128((__m128i *)(dst_ptr), out0);
_mm_store_si128((__m128i *)(dst_ptr + 4), out1);
#else
_mm_store_si128((__m128i *)(dst_ptr), *poutput);
#endif // CONFIG_VP9_HIGHBITDEPTH
}
static INLINE void storeu_output(const __m128i *poutput, tran_low_t* dst_ptr) {
#if CONFIG_VP9_HIGHBITDEPTH
const __m128i zero = _mm_setzero_si128();
const __m128i sign_bits = _mm_cmplt_epi16(*poutput, zero);
__m128i out0 = _mm_unpacklo_epi16(*poutput, sign_bits);
__m128i out1 = _mm_unpackhi_epi16(*poutput, sign_bits);
_mm_storeu_si128((__m128i *)(dst_ptr), out0);
_mm_storeu_si128((__m128i *)(dst_ptr + 4), out1);
#else
_mm_storeu_si128((__m128i *)(dst_ptr), *poutput);
#endif // CONFIG_VP9_HIGHBITDEPTH
}
static INLINE __m128i mult_round_shift(const __m128i *pin0,
const __m128i *pin1,
const __m128i *pmultiplier,
const __m128i *prounding,
const int shift) {
const __m128i u0 = _mm_madd_epi16(*pin0, *pmultiplier);
const __m128i u1 = _mm_madd_epi16(*pin1, *pmultiplier);
const __m128i v0 = _mm_add_epi32(u0, *prounding);
const __m128i v1 = _mm_add_epi32(u1, *prounding);
const __m128i w0 = _mm_srai_epi32(v0, shift);
const __m128i w1 = _mm_srai_epi32(v1, shift);
return _mm_packs_epi32(w0, w1);
}
static INLINE void transpose_and_output8x8(
const __m128i *pin00, const __m128i *pin01,
const __m128i *pin02, const __m128i *pin03,
const __m128i *pin04, const __m128i *pin05,
const __m128i *pin06, const __m128i *pin07,
const int pass, int16_t* out0_ptr,
tran_low_t* out1_ptr) {
// 00 01 02 03 04 05 06 07
// 10 11 12 13 14 15 16 17
// 20 21 22 23 24 25 26 27
// 30 31 32 33 34 35 36 37
// 40 41 42 43 44 45 46 47
// 50 51 52 53 54 55 56 57
// 60 61 62 63 64 65 66 67
// 70 71 72 73 74 75 76 77
const __m128i tr0_0 = _mm_unpacklo_epi16(*pin00, *pin01);
const __m128i tr0_1 = _mm_unpacklo_epi16(*pin02, *pin03);
const __m128i tr0_2 = _mm_unpackhi_epi16(*pin00, *pin01);
const __m128i tr0_3 = _mm_unpackhi_epi16(*pin02, *pin03);
const __m128i tr0_4 = _mm_unpacklo_epi16(*pin04, *pin05);
const __m128i tr0_5 = _mm_unpacklo_epi16(*pin06, *pin07);
const __m128i tr0_6 = _mm_unpackhi_epi16(*pin04, *pin05);
const __m128i tr0_7 = _mm_unpackhi_epi16(*pin06, *pin07);
// 00 10 01 11 02 12 03 13
// 20 30 21 31 22 32 23 33
// 04 14 05 15 06 16 07 17
// 24 34 25 35 26 36 27 37
// 40 50 41 51 42 52 43 53
// 60 70 61 71 62 72 63 73
// 54 54 55 55 56 56 57 57
// 64 74 65 75 66 76 67 77
const __m128i tr1_0 = _mm_unpacklo_epi32(tr0_0, tr0_1);
const __m128i tr1_1 = _mm_unpacklo_epi32(tr0_2, tr0_3);
const __m128i tr1_2 = _mm_unpackhi_epi32(tr0_0, tr0_1);
const __m128i tr1_3 = _mm_unpackhi_epi32(tr0_2, tr0_3);
const __m128i tr1_4 = _mm_unpacklo_epi32(tr0_4, tr0_5);
const __m128i tr1_5 = _mm_unpacklo_epi32(tr0_6, tr0_7);
const __m128i tr1_6 = _mm_unpackhi_epi32(tr0_4, tr0_5);
const __m128i tr1_7 = _mm_unpackhi_epi32(tr0_6, tr0_7);
// 00 10 20 30 01 11 21 31
// 40 50 60 70 41 51 61 71
// 02 12 22 32 03 13 23 33
// 42 52 62 72 43 53 63 73
// 04 14 24 34 05 15 21 36
// 44 54 64 74 45 55 61 76
// 06 16 26 36 07 17 27 37
// 46 56 66 76 47 57 67 77
const __m128i tr2_0 = _mm_unpacklo_epi64(tr1_0, tr1_4);
const __m128i tr2_1 = _mm_unpackhi_epi64(tr1_0, tr1_4);
const __m128i tr2_2 = _mm_unpacklo_epi64(tr1_2, tr1_6);
const __m128i tr2_3 = _mm_unpackhi_epi64(tr1_2, tr1_6);
const __m128i tr2_4 = _mm_unpacklo_epi64(tr1_1, tr1_5);
const __m128i tr2_5 = _mm_unpackhi_epi64(tr1_1, tr1_5);
const __m128i tr2_6 = _mm_unpacklo_epi64(tr1_3, tr1_7);
const __m128i tr2_7 = _mm_unpackhi_epi64(tr1_3, tr1_7);
// 00 10 20 30 40 50 60 70
// 01 11 21 31 41 51 61 71
// 02 12 22 32 42 52 62 72
// 03 13 23 33 43 53 63 73
// 04 14 24 34 44 54 64 74
// 05 15 25 35 45 55 65 75
// 06 16 26 36 46 56 66 76
// 07 17 27 37 47 57 67 77
if (pass == 0) {
_mm_storeu_si128((__m128i*)(out0_ptr + 0 * 16), tr2_0);
_mm_storeu_si128((__m128i*)(out0_ptr + 1 * 16), tr2_1);
_mm_storeu_si128((__m128i*)(out0_ptr + 2 * 16), tr2_2);
_mm_storeu_si128((__m128i*)(out0_ptr + 3 * 16), tr2_3);
_mm_storeu_si128((__m128i*)(out0_ptr + 4 * 16), tr2_4);
_mm_storeu_si128((__m128i*)(out0_ptr + 5 * 16), tr2_5);
_mm_storeu_si128((__m128i*)(out0_ptr + 6 * 16), tr2_6);
_mm_storeu_si128((__m128i*)(out0_ptr + 7 * 16), tr2_7);
} else {
storeu_output(&tr2_0, (out1_ptr + 0 * 16));
storeu_output(&tr2_1, (out1_ptr + 1 * 16));
storeu_output(&tr2_2, (out1_ptr + 2 * 16));
storeu_output(&tr2_3, (out1_ptr + 3 * 16));
storeu_output(&tr2_4, (out1_ptr + 4 * 16));
storeu_output(&tr2_5, (out1_ptr + 5 * 16));
storeu_output(&tr2_6, (out1_ptr + 6 * 16));
storeu_output(&tr2_7, (out1_ptr + 7 * 16));
}
}
#ifdef __cplusplus
} // extern "C"
#endif
#endif // VP9_ENCODER_X86_VP9_DCT_SSE2_H_

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,471 @@
/*
* Copyright (c) 2014 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 <assert.h>
#if defined(_MSC_VER) && _MSC_VER <= 1500
// Need to include math.h before calling tmmintrin.h/intrin.h
// in certain versions of MSVS.
#include <math.h>
#endif
#include <tmmintrin.h> // SSSE3
#include "./vp9_rtcd.h"
#include "vp9/common/x86/vp9_idct_intrin_sse2.h"
void vp9_fdct8x8_quant_ssse3(const int16_t *input, int stride,
int16_t* coeff_ptr, intptr_t n_coeffs,
int skip_block, const int16_t* zbin_ptr,
const int16_t* round_ptr, const int16_t* quant_ptr,
const int16_t* quant_shift_ptr,
int16_t* qcoeff_ptr,
int16_t* dqcoeff_ptr, const int16_t* dequant_ptr,
uint16_t* eob_ptr,
const int16_t* scan_ptr,
const int16_t* iscan_ptr) {
__m128i zero;
int pass;
// Constants
// When we use them, in one case, they are all the same. In all others
// it's a pair of them that we need to repeat four times. This is done
// by constructing the 32 bit constant corresponding to that pair.
const __m128i k__dual_p16_p16 = dual_set_epi16(23170, 23170);
const __m128i k__cospi_p16_p16 = _mm_set1_epi16((int16_t)cospi_16_64);
const __m128i k__cospi_p16_m16 = pair_set_epi16(cospi_16_64, -cospi_16_64);
const __m128i k__cospi_p24_p08 = pair_set_epi16(cospi_24_64, cospi_8_64);
const __m128i k__cospi_m08_p24 = pair_set_epi16(-cospi_8_64, cospi_24_64);
const __m128i k__cospi_p28_p04 = pair_set_epi16(cospi_28_64, cospi_4_64);
const __m128i k__cospi_m04_p28 = pair_set_epi16(-cospi_4_64, cospi_28_64);
const __m128i k__cospi_p12_p20 = pair_set_epi16(cospi_12_64, cospi_20_64);
const __m128i k__cospi_m20_p12 = pair_set_epi16(-cospi_20_64, cospi_12_64);
const __m128i k__DCT_CONST_ROUNDING = _mm_set1_epi32(DCT_CONST_ROUNDING);
// Load input
__m128i in0 = _mm_load_si128((const __m128i *)(input + 0 * stride));
__m128i in1 = _mm_load_si128((const __m128i *)(input + 1 * stride));
__m128i in2 = _mm_load_si128((const __m128i *)(input + 2 * stride));
__m128i in3 = _mm_load_si128((const __m128i *)(input + 3 * stride));
__m128i in4 = _mm_load_si128((const __m128i *)(input + 4 * stride));
__m128i in5 = _mm_load_si128((const __m128i *)(input + 5 * stride));
__m128i in6 = _mm_load_si128((const __m128i *)(input + 6 * stride));
__m128i in7 = _mm_load_si128((const __m128i *)(input + 7 * stride));
__m128i *in[8];
int index = 0;
(void)scan_ptr;
(void)zbin_ptr;
(void)quant_shift_ptr;
(void)coeff_ptr;
// Pre-condition input (shift by two)
in0 = _mm_slli_epi16(in0, 2);
in1 = _mm_slli_epi16(in1, 2);
in2 = _mm_slli_epi16(in2, 2);
in3 = _mm_slli_epi16(in3, 2);
in4 = _mm_slli_epi16(in4, 2);
in5 = _mm_slli_epi16(in5, 2);
in6 = _mm_slli_epi16(in6, 2);
in7 = _mm_slli_epi16(in7, 2);
in[0] = &in0;
in[1] = &in1;
in[2] = &in2;
in[3] = &in3;
in[4] = &in4;
in[5] = &in5;
in[6] = &in6;
in[7] = &in7;
// We do two passes, first the columns, then the rows. The results of the
// first pass are transposed so that the same column code can be reused. The
// results of the second pass are also transposed so that the rows (processed
// as columns) are put back in row positions.
for (pass = 0; pass < 2; pass++) {
// To store results of each pass before the transpose.
__m128i res0, res1, res2, res3, res4, res5, res6, res7;
// Add/subtract
const __m128i q0 = _mm_add_epi16(in0, in7);
const __m128i q1 = _mm_add_epi16(in1, in6);
const __m128i q2 = _mm_add_epi16(in2, in5);
const __m128i q3 = _mm_add_epi16(in3, in4);
const __m128i q4 = _mm_sub_epi16(in3, in4);
const __m128i q5 = _mm_sub_epi16(in2, in5);
const __m128i q6 = _mm_sub_epi16(in1, in6);
const __m128i q7 = _mm_sub_epi16(in0, in7);
// Work on first four results
{
// Add/subtract
const __m128i r0 = _mm_add_epi16(q0, q3);
const __m128i r1 = _mm_add_epi16(q1, q2);
const __m128i r2 = _mm_sub_epi16(q1, q2);
const __m128i r3 = _mm_sub_epi16(q0, q3);
// Interleave to do the multiply by constants which gets us into 32bits
const __m128i t0 = _mm_unpacklo_epi16(r0, r1);
const __m128i t1 = _mm_unpackhi_epi16(r0, r1);
const __m128i t2 = _mm_unpacklo_epi16(r2, r3);
const __m128i t3 = _mm_unpackhi_epi16(r2, r3);
const __m128i u0 = _mm_madd_epi16(t0, k__cospi_p16_p16);
const __m128i u1 = _mm_madd_epi16(t1, k__cospi_p16_p16);
const __m128i u2 = _mm_madd_epi16(t0, k__cospi_p16_m16);
const __m128i u3 = _mm_madd_epi16(t1, k__cospi_p16_m16);
const __m128i u4 = _mm_madd_epi16(t2, k__cospi_p24_p08);
const __m128i u5 = _mm_madd_epi16(t3, k__cospi_p24_p08);
const __m128i u6 = _mm_madd_epi16(t2, k__cospi_m08_p24);
const __m128i u7 = _mm_madd_epi16(t3, k__cospi_m08_p24);
// dct_const_round_shift
const __m128i v0 = _mm_add_epi32(u0, k__DCT_CONST_ROUNDING);
const __m128i v1 = _mm_add_epi32(u1, k__DCT_CONST_ROUNDING);
const __m128i v2 = _mm_add_epi32(u2, k__DCT_CONST_ROUNDING);
const __m128i v3 = _mm_add_epi32(u3, k__DCT_CONST_ROUNDING);
const __m128i v4 = _mm_add_epi32(u4, k__DCT_CONST_ROUNDING);
const __m128i v5 = _mm_add_epi32(u5, k__DCT_CONST_ROUNDING);
const __m128i v6 = _mm_add_epi32(u6, k__DCT_CONST_ROUNDING);
const __m128i v7 = _mm_add_epi32(u7, k__DCT_CONST_ROUNDING);
const __m128i w0 = _mm_srai_epi32(v0, DCT_CONST_BITS);
const __m128i w1 = _mm_srai_epi32(v1, DCT_CONST_BITS);
const __m128i w2 = _mm_srai_epi32(v2, DCT_CONST_BITS);
const __m128i w3 = _mm_srai_epi32(v3, DCT_CONST_BITS);
const __m128i w4 = _mm_srai_epi32(v4, DCT_CONST_BITS);
const __m128i w5 = _mm_srai_epi32(v5, DCT_CONST_BITS);
const __m128i w6 = _mm_srai_epi32(v6, DCT_CONST_BITS);
const __m128i w7 = _mm_srai_epi32(v7, DCT_CONST_BITS);
// Combine
res0 = _mm_packs_epi32(w0, w1);
res4 = _mm_packs_epi32(w2, w3);
res2 = _mm_packs_epi32(w4, w5);
res6 = _mm_packs_epi32(w6, w7);
}
// Work on next four results
{
// Interleave to do the multiply by constants which gets us into 32bits
const __m128i d0 = _mm_sub_epi16(q6, q5);
const __m128i d1 = _mm_add_epi16(q6, q5);
const __m128i r0 = _mm_mulhrs_epi16(d0, k__dual_p16_p16);
const __m128i r1 = _mm_mulhrs_epi16(d1, k__dual_p16_p16);
// Add/subtract
const __m128i x0 = _mm_add_epi16(q4, r0);
const __m128i x1 = _mm_sub_epi16(q4, r0);
const __m128i x2 = _mm_sub_epi16(q7, r1);
const __m128i x3 = _mm_add_epi16(q7, r1);
// Interleave to do the multiply by constants which gets us into 32bits
const __m128i t0 = _mm_unpacklo_epi16(x0, x3);
const __m128i t1 = _mm_unpackhi_epi16(x0, x3);
const __m128i t2 = _mm_unpacklo_epi16(x1, x2);
const __m128i t3 = _mm_unpackhi_epi16(x1, x2);
const __m128i u0 = _mm_madd_epi16(t0, k__cospi_p28_p04);
const __m128i u1 = _mm_madd_epi16(t1, k__cospi_p28_p04);
const __m128i u2 = _mm_madd_epi16(t0, k__cospi_m04_p28);
const __m128i u3 = _mm_madd_epi16(t1, k__cospi_m04_p28);
const __m128i u4 = _mm_madd_epi16(t2, k__cospi_p12_p20);
const __m128i u5 = _mm_madd_epi16(t3, k__cospi_p12_p20);
const __m128i u6 = _mm_madd_epi16(t2, k__cospi_m20_p12);
const __m128i u7 = _mm_madd_epi16(t3, k__cospi_m20_p12);
// dct_const_round_shift
const __m128i v0 = _mm_add_epi32(u0, k__DCT_CONST_ROUNDING);
const __m128i v1 = _mm_add_epi32(u1, k__DCT_CONST_ROUNDING);
const __m128i v2 = _mm_add_epi32(u2, k__DCT_CONST_ROUNDING);
const __m128i v3 = _mm_add_epi32(u3, k__DCT_CONST_ROUNDING);
const __m128i v4 = _mm_add_epi32(u4, k__DCT_CONST_ROUNDING);
const __m128i v5 = _mm_add_epi32(u5, k__DCT_CONST_ROUNDING);
const __m128i v6 = _mm_add_epi32(u6, k__DCT_CONST_ROUNDING);
const __m128i v7 = _mm_add_epi32(u7, k__DCT_CONST_ROUNDING);
const __m128i w0 = _mm_srai_epi32(v0, DCT_CONST_BITS);
const __m128i w1 = _mm_srai_epi32(v1, DCT_CONST_BITS);
const __m128i w2 = _mm_srai_epi32(v2, DCT_CONST_BITS);
const __m128i w3 = _mm_srai_epi32(v3, DCT_CONST_BITS);
const __m128i w4 = _mm_srai_epi32(v4, DCT_CONST_BITS);
const __m128i w5 = _mm_srai_epi32(v5, DCT_CONST_BITS);
const __m128i w6 = _mm_srai_epi32(v6, DCT_CONST_BITS);
const __m128i w7 = _mm_srai_epi32(v7, DCT_CONST_BITS);
// Combine
res1 = _mm_packs_epi32(w0, w1);
res7 = _mm_packs_epi32(w2, w3);
res5 = _mm_packs_epi32(w4, w5);
res3 = _mm_packs_epi32(w6, w7);
}
// Transpose the 8x8.
{
// 00 01 02 03 04 05 06 07
// 10 11 12 13 14 15 16 17
// 20 21 22 23 24 25 26 27
// 30 31 32 33 34 35 36 37
// 40 41 42 43 44 45 46 47
// 50 51 52 53 54 55 56 57
// 60 61 62 63 64 65 66 67
// 70 71 72 73 74 75 76 77
const __m128i tr0_0 = _mm_unpacklo_epi16(res0, res1);
const __m128i tr0_1 = _mm_unpacklo_epi16(res2, res3);
const __m128i tr0_2 = _mm_unpackhi_epi16(res0, res1);
const __m128i tr0_3 = _mm_unpackhi_epi16(res2, res3);
const __m128i tr0_4 = _mm_unpacklo_epi16(res4, res5);
const __m128i tr0_5 = _mm_unpacklo_epi16(res6, res7);
const __m128i tr0_6 = _mm_unpackhi_epi16(res4, res5);
const __m128i tr0_7 = _mm_unpackhi_epi16(res6, res7);
// 00 10 01 11 02 12 03 13
// 20 30 21 31 22 32 23 33
// 04 14 05 15 06 16 07 17
// 24 34 25 35 26 36 27 37
// 40 50 41 51 42 52 43 53
// 60 70 61 71 62 72 63 73
// 54 54 55 55 56 56 57 57
// 64 74 65 75 66 76 67 77
const __m128i tr1_0 = _mm_unpacklo_epi32(tr0_0, tr0_1);
const __m128i tr1_1 = _mm_unpacklo_epi32(tr0_2, tr0_3);
const __m128i tr1_2 = _mm_unpackhi_epi32(tr0_0, tr0_1);
const __m128i tr1_3 = _mm_unpackhi_epi32(tr0_2, tr0_3);
const __m128i tr1_4 = _mm_unpacklo_epi32(tr0_4, tr0_5);
const __m128i tr1_5 = _mm_unpacklo_epi32(tr0_6, tr0_7);
const __m128i tr1_6 = _mm_unpackhi_epi32(tr0_4, tr0_5);
const __m128i tr1_7 = _mm_unpackhi_epi32(tr0_6, tr0_7);
// 00 10 20 30 01 11 21 31
// 40 50 60 70 41 51 61 71
// 02 12 22 32 03 13 23 33
// 42 52 62 72 43 53 63 73
// 04 14 24 34 05 15 21 36
// 44 54 64 74 45 55 61 76
// 06 16 26 36 07 17 27 37
// 46 56 66 76 47 57 67 77
in0 = _mm_unpacklo_epi64(tr1_0, tr1_4);
in1 = _mm_unpackhi_epi64(tr1_0, tr1_4);
in2 = _mm_unpacklo_epi64(tr1_2, tr1_6);
in3 = _mm_unpackhi_epi64(tr1_2, tr1_6);
in4 = _mm_unpacklo_epi64(tr1_1, tr1_5);
in5 = _mm_unpackhi_epi64(tr1_1, tr1_5);
in6 = _mm_unpacklo_epi64(tr1_3, tr1_7);
in7 = _mm_unpackhi_epi64(tr1_3, tr1_7);
// 00 10 20 30 40 50 60 70
// 01 11 21 31 41 51 61 71
// 02 12 22 32 42 52 62 72
// 03 13 23 33 43 53 63 73
// 04 14 24 34 44 54 64 74
// 05 15 25 35 45 55 65 75
// 06 16 26 36 46 56 66 76
// 07 17 27 37 47 57 67 77
}
}
// Post-condition output and store it
{
// Post-condition (division by two)
// division of two 16 bits signed numbers using shifts
// n / 2 = (n - (n >> 15)) >> 1
const __m128i sign_in0 = _mm_srai_epi16(in0, 15);
const __m128i sign_in1 = _mm_srai_epi16(in1, 15);
const __m128i sign_in2 = _mm_srai_epi16(in2, 15);
const __m128i sign_in3 = _mm_srai_epi16(in3, 15);
const __m128i sign_in4 = _mm_srai_epi16(in4, 15);
const __m128i sign_in5 = _mm_srai_epi16(in5, 15);
const __m128i sign_in6 = _mm_srai_epi16(in6, 15);
const __m128i sign_in7 = _mm_srai_epi16(in7, 15);
in0 = _mm_sub_epi16(in0, sign_in0);
in1 = _mm_sub_epi16(in1, sign_in1);
in2 = _mm_sub_epi16(in2, sign_in2);
in3 = _mm_sub_epi16(in3, sign_in3);
in4 = _mm_sub_epi16(in4, sign_in4);
in5 = _mm_sub_epi16(in5, sign_in5);
in6 = _mm_sub_epi16(in6, sign_in6);
in7 = _mm_sub_epi16(in7, sign_in7);
in0 = _mm_srai_epi16(in0, 1);
in1 = _mm_srai_epi16(in1, 1);
in2 = _mm_srai_epi16(in2, 1);
in3 = _mm_srai_epi16(in3, 1);
in4 = _mm_srai_epi16(in4, 1);
in5 = _mm_srai_epi16(in5, 1);
in6 = _mm_srai_epi16(in6, 1);
in7 = _mm_srai_epi16(in7, 1);
}
iscan_ptr += n_coeffs;
qcoeff_ptr += n_coeffs;
dqcoeff_ptr += n_coeffs;
n_coeffs = -n_coeffs;
zero = _mm_setzero_si128();
if (!skip_block) {
__m128i eob;
__m128i round, quant, dequant, thr;
int16_t nzflag;
{
__m128i coeff0, coeff1;
// Setup global values
{
round = _mm_load_si128((const __m128i*)round_ptr);
quant = _mm_load_si128((const __m128i*)quant_ptr);
dequant = _mm_load_si128((const __m128i*)dequant_ptr);
}
{
__m128i coeff0_sign, coeff1_sign;
__m128i qcoeff0, qcoeff1;
__m128i qtmp0, qtmp1;
// Do DC and first 15 AC
coeff0 = *in[0];
coeff1 = *in[1];
// Poor man's sign extract
coeff0_sign = _mm_srai_epi16(coeff0, 15);
coeff1_sign = _mm_srai_epi16(coeff1, 15);
qcoeff0 = _mm_xor_si128(coeff0, coeff0_sign);
qcoeff1 = _mm_xor_si128(coeff1, coeff1_sign);
qcoeff0 = _mm_sub_epi16(qcoeff0, coeff0_sign);
qcoeff1 = _mm_sub_epi16(qcoeff1, coeff1_sign);
qcoeff0 = _mm_adds_epi16(qcoeff0, round);
round = _mm_unpackhi_epi64(round, round);
qcoeff1 = _mm_adds_epi16(qcoeff1, round);
qtmp0 = _mm_mulhi_epi16(qcoeff0, quant);
quant = _mm_unpackhi_epi64(quant, quant);
qtmp1 = _mm_mulhi_epi16(qcoeff1, quant);
// Reinsert signs
qcoeff0 = _mm_xor_si128(qtmp0, coeff0_sign);
qcoeff1 = _mm_xor_si128(qtmp1, coeff1_sign);
qcoeff0 = _mm_sub_epi16(qcoeff0, coeff0_sign);
qcoeff1 = _mm_sub_epi16(qcoeff1, coeff1_sign);
_mm_store_si128((__m128i*)(qcoeff_ptr + n_coeffs), qcoeff0);
_mm_store_si128((__m128i*)(qcoeff_ptr + n_coeffs) + 1, qcoeff1);
coeff0 = _mm_mullo_epi16(qcoeff0, dequant);
dequant = _mm_unpackhi_epi64(dequant, dequant);
coeff1 = _mm_mullo_epi16(qcoeff1, dequant);
_mm_store_si128((__m128i*)(dqcoeff_ptr + n_coeffs), coeff0);
_mm_store_si128((__m128i*)(dqcoeff_ptr + n_coeffs) + 1, coeff1);
}
{
// Scan for eob
__m128i zero_coeff0, zero_coeff1;
__m128i nzero_coeff0, nzero_coeff1;
__m128i iscan0, iscan1;
__m128i eob1;
zero_coeff0 = _mm_cmpeq_epi16(coeff0, zero);
zero_coeff1 = _mm_cmpeq_epi16(coeff1, zero);
nzero_coeff0 = _mm_cmpeq_epi16(zero_coeff0, zero);
nzero_coeff1 = _mm_cmpeq_epi16(zero_coeff1, zero);
iscan0 = _mm_load_si128((const __m128i*)(iscan_ptr + n_coeffs));
iscan1 = _mm_load_si128((const __m128i*)(iscan_ptr + n_coeffs) + 1);
// Add one to convert from indices to counts
iscan0 = _mm_sub_epi16(iscan0, nzero_coeff0);
iscan1 = _mm_sub_epi16(iscan1, nzero_coeff1);
eob = _mm_and_si128(iscan0, nzero_coeff0);
eob1 = _mm_and_si128(iscan1, nzero_coeff1);
eob = _mm_max_epi16(eob, eob1);
}
n_coeffs += 8 * 2;
}
// AC only loop
index = 2;
thr = _mm_srai_epi16(dequant, 1);
while (n_coeffs < 0) {
__m128i coeff0, coeff1;
{
__m128i coeff0_sign, coeff1_sign;
__m128i qcoeff0, qcoeff1;
__m128i qtmp0, qtmp1;
assert(index < (int)(sizeof(in) / sizeof(in[0])) - 1);
coeff0 = *in[index];
coeff1 = *in[index + 1];
// Poor man's sign extract
coeff0_sign = _mm_srai_epi16(coeff0, 15);
coeff1_sign = _mm_srai_epi16(coeff1, 15);
qcoeff0 = _mm_xor_si128(coeff0, coeff0_sign);
qcoeff1 = _mm_xor_si128(coeff1, coeff1_sign);
qcoeff0 = _mm_sub_epi16(qcoeff0, coeff0_sign);
qcoeff1 = _mm_sub_epi16(qcoeff1, coeff1_sign);
nzflag = _mm_movemask_epi8(_mm_cmpgt_epi16(qcoeff0, thr)) |
_mm_movemask_epi8(_mm_cmpgt_epi16(qcoeff1, thr));
if (nzflag) {
qcoeff0 = _mm_adds_epi16(qcoeff0, round);
qcoeff1 = _mm_adds_epi16(qcoeff1, round);
qtmp0 = _mm_mulhi_epi16(qcoeff0, quant);
qtmp1 = _mm_mulhi_epi16(qcoeff1, quant);
// Reinsert signs
qcoeff0 = _mm_xor_si128(qtmp0, coeff0_sign);
qcoeff1 = _mm_xor_si128(qtmp1, coeff1_sign);
qcoeff0 = _mm_sub_epi16(qcoeff0, coeff0_sign);
qcoeff1 = _mm_sub_epi16(qcoeff1, coeff1_sign);
_mm_store_si128((__m128i*)(qcoeff_ptr + n_coeffs), qcoeff0);
_mm_store_si128((__m128i*)(qcoeff_ptr + n_coeffs) + 1, qcoeff1);
coeff0 = _mm_mullo_epi16(qcoeff0, dequant);
coeff1 = _mm_mullo_epi16(qcoeff1, dequant);
_mm_store_si128((__m128i*)(dqcoeff_ptr + n_coeffs), coeff0);
_mm_store_si128((__m128i*)(dqcoeff_ptr + n_coeffs) + 1, coeff1);
} else {
_mm_store_si128((__m128i*)(qcoeff_ptr + n_coeffs), zero);
_mm_store_si128((__m128i*)(qcoeff_ptr + n_coeffs) + 1, zero);
_mm_store_si128((__m128i*)(dqcoeff_ptr + n_coeffs), zero);
_mm_store_si128((__m128i*)(dqcoeff_ptr + n_coeffs) + 1, zero);
}
}
if (nzflag) {
// Scan for eob
__m128i zero_coeff0, zero_coeff1;
__m128i nzero_coeff0, nzero_coeff1;
__m128i iscan0, iscan1;
__m128i eob0, eob1;
zero_coeff0 = _mm_cmpeq_epi16(coeff0, zero);
zero_coeff1 = _mm_cmpeq_epi16(coeff1, zero);
nzero_coeff0 = _mm_cmpeq_epi16(zero_coeff0, zero);
nzero_coeff1 = _mm_cmpeq_epi16(zero_coeff1, zero);
iscan0 = _mm_load_si128((const __m128i*)(iscan_ptr + n_coeffs));
iscan1 = _mm_load_si128((const __m128i*)(iscan_ptr + n_coeffs) + 1);
// Add one to convert from indices to counts
iscan0 = _mm_sub_epi16(iscan0, nzero_coeff0);
iscan1 = _mm_sub_epi16(iscan1, nzero_coeff1);
eob0 = _mm_and_si128(iscan0, nzero_coeff0);
eob1 = _mm_and_si128(iscan1, nzero_coeff1);
eob0 = _mm_max_epi16(eob0, eob1);
eob = _mm_max_epi16(eob, eob0);
}
n_coeffs += 8 * 2;
index += 2;
}
// Accumulate EOB
{
__m128i eob_shuffled;
eob_shuffled = _mm_shuffle_epi32(eob, 0xe);
eob = _mm_max_epi16(eob, eob_shuffled);
eob_shuffled = _mm_shufflelo_epi16(eob, 0xe);
eob = _mm_max_epi16(eob, eob_shuffled);
eob_shuffled = _mm_shufflelo_epi16(eob, 0x1);
eob = _mm_max_epi16(eob, eob_shuffled);
*eob_ptr = _mm_extract_epi16(eob, 1);
}
} else {
do {
_mm_store_si128((__m128i*)(dqcoeff_ptr + n_coeffs), zero);
_mm_store_si128((__m128i*)(dqcoeff_ptr + n_coeffs) + 1, zero);
_mm_store_si128((__m128i*)(qcoeff_ptr + n_coeffs), zero);
_mm_store_si128((__m128i*)(qcoeff_ptr + n_coeffs) + 1, zero);
n_coeffs += 8 * 2;
} while (n_coeffs < 0);
*eob_ptr = 0;
}
}

View file

@ -0,0 +1,255 @@
;
; Copyright (c) 2014 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 "third_party/x86inc/x86inc.asm"
; This file provides SSSE3 version of the forward transformation. Part
; of the macro definitions are originally derived from the ffmpeg project.
; The current version applies to x86 64-bit only.
SECTION_RODATA
pw_11585x2: times 8 dw 23170
pd_8192: times 4 dd 8192
%macro TRANSFORM_COEFFS 2
pw_%1_%2: dw %1, %2, %1, %2, %1, %2, %1, %2
pw_%2_m%1: dw %2, -%1, %2, -%1, %2, -%1, %2, -%1
%endmacro
TRANSFORM_COEFFS 11585, 11585
TRANSFORM_COEFFS 15137, 6270
TRANSFORM_COEFFS 16069, 3196
TRANSFORM_COEFFS 9102, 13623
SECTION .text
%if ARCH_X86_64
%macro SUM_SUB 3
psubw m%3, m%1, m%2
paddw m%1, m%2
SWAP %2, %3
%endmacro
; butterfly operation
%macro MUL_ADD_2X 6 ; dst1, dst2, src, round, coefs1, coefs2
pmaddwd m%1, m%3, %5
pmaddwd m%2, m%3, %6
paddd m%1, %4
paddd m%2, %4
psrad m%1, 14
psrad m%2, 14
%endmacro
%macro BUTTERFLY_4X 7 ; dst1, dst2, coef1, coef2, round, tmp1, tmp2
punpckhwd m%6, m%2, m%1
MUL_ADD_2X %7, %6, %6, %5, [pw_%4_%3], [pw_%3_m%4]
punpcklwd m%2, m%1
MUL_ADD_2X %1, %2, %2, %5, [pw_%4_%3], [pw_%3_m%4]
packssdw m%1, m%7
packssdw m%2, m%6
%endmacro
; matrix transpose
%macro INTERLEAVE_2X 4
punpckh%1 m%4, m%2, m%3
punpckl%1 m%2, m%3
SWAP %3, %4
%endmacro
%macro TRANSPOSE8X8 9
INTERLEAVE_2X wd, %1, %2, %9
INTERLEAVE_2X wd, %3, %4, %9
INTERLEAVE_2X wd, %5, %6, %9
INTERLEAVE_2X wd, %7, %8, %9
INTERLEAVE_2X dq, %1, %3, %9
INTERLEAVE_2X dq, %2, %4, %9
INTERLEAVE_2X dq, %5, %7, %9
INTERLEAVE_2X dq, %6, %8, %9
INTERLEAVE_2X qdq, %1, %5, %9
INTERLEAVE_2X qdq, %3, %7, %9
INTERLEAVE_2X qdq, %2, %6, %9
INTERLEAVE_2X qdq, %4, %8, %9
SWAP %2, %5
SWAP %4, %7
%endmacro
; 1D forward 8x8 DCT transform
%macro FDCT8_1D 1
SUM_SUB 0, 7, 9
SUM_SUB 1, 6, 9
SUM_SUB 2, 5, 9
SUM_SUB 3, 4, 9
SUM_SUB 0, 3, 9
SUM_SUB 1, 2, 9
SUM_SUB 6, 5, 9
%if %1 == 0
SUM_SUB 0, 1, 9
%endif
BUTTERFLY_4X 2, 3, 6270, 15137, m8, 9, 10
pmulhrsw m6, m12
pmulhrsw m5, m12
%if %1 == 0
pmulhrsw m0, m12
pmulhrsw m1, m12
%else
BUTTERFLY_4X 1, 0, 11585, 11585, m8, 9, 10
SWAP 0, 1
%endif
SUM_SUB 4, 5, 9
SUM_SUB 7, 6, 9
BUTTERFLY_4X 4, 7, 3196, 16069, m8, 9, 10
BUTTERFLY_4X 5, 6, 13623, 9102, m8, 9, 10
SWAP 1, 4
SWAP 3, 6
%endmacro
%macro DIVIDE_ROUND_2X 4 ; dst1, dst2, tmp1, tmp2
psraw m%3, m%1, 15
psraw m%4, m%2, 15
psubw m%1, m%3
psubw m%2, m%4
psraw m%1, 1
psraw m%2, 1
%endmacro
INIT_XMM ssse3
cglobal fdct8x8, 3, 5, 13, input, output, stride
mova m8, [pd_8192]
mova m12, [pw_11585x2]
pxor m11, m11
lea r3, [2 * strideq]
lea r4, [4 * strideq]
mova m0, [inputq]
mova m1, [inputq + r3]
lea inputq, [inputq + r4]
mova m2, [inputq]
mova m3, [inputq + r3]
lea inputq, [inputq + r4]
mova m4, [inputq]
mova m5, [inputq + r3]
lea inputq, [inputq + r4]
mova m6, [inputq]
mova m7, [inputq + r3]
; left shift by 2 to increase forward transformation precision
psllw m0, 2
psllw m1, 2
psllw m2, 2
psllw m3, 2
psllw m4, 2
psllw m5, 2
psllw m6, 2
psllw m7, 2
; column transform
FDCT8_1D 0
TRANSPOSE8X8 0, 1, 2, 3, 4, 5, 6, 7, 9
FDCT8_1D 1
TRANSPOSE8X8 0, 1, 2, 3, 4, 5, 6, 7, 9
DIVIDE_ROUND_2X 0, 1, 9, 10
DIVIDE_ROUND_2X 2, 3, 9, 10
DIVIDE_ROUND_2X 4, 5, 9, 10
DIVIDE_ROUND_2X 6, 7, 9, 10
mova [outputq + 0], m0
mova [outputq + 16], m1
mova [outputq + 32], m2
mova [outputq + 48], m3
mova [outputq + 64], m4
mova [outputq + 80], m5
mova [outputq + 96], m6
mova [outputq + 112], m7
RET
%macro HMD8_1D 0
psubw m8, m0, m1
psubw m9, m2, m3
paddw m0, m1
paddw m2, m3
SWAP 1, 8
SWAP 3, 9
psubw m8, m4, m5
psubw m9, m6, m7
paddw m4, m5
paddw m6, m7
SWAP 5, 8
SWAP 7, 9
psubw m8, m0, m2
psubw m9, m1, m3
paddw m0, m2
paddw m1, m3
SWAP 2, 8
SWAP 3, 9
psubw m8, m4, m6
psubw m9, m5, m7
paddw m4, m6
paddw m5, m7
SWAP 6, 8
SWAP 7, 9
psubw m8, m0, m4
psubw m9, m1, m5
paddw m0, m4
paddw m1, m5
SWAP 4, 8
SWAP 5, 9
psubw m8, m2, m6
psubw m9, m3, m7
paddw m2, m6
paddw m3, m7
SWAP 6, 8
SWAP 7, 9
%endmacro
INIT_XMM ssse3
cglobal hadamard_8x8, 3, 5, 10, input, stride, output
lea r3, [2 * strideq]
lea r4, [4 * strideq]
mova m0, [inputq]
mova m1, [inputq + r3]
lea inputq, [inputq + r4]
mova m2, [inputq]
mova m3, [inputq + r3]
lea inputq, [inputq + r4]
mova m4, [inputq]
mova m5, [inputq + r3]
lea inputq, [inputq + r4]
mova m6, [inputq]
mova m7, [inputq + r3]
HMD8_1D
TRANSPOSE8X8 0, 1, 2, 3, 4, 5, 6, 7, 9
HMD8_1D
mova [outputq + 0], m0
mova [outputq + 16], m1
mova [outputq + 32], m2
mova [outputq + 48], m3
mova [outputq + 64], m4
mova [outputq + 80], m5
mova [outputq + 96], m6
mova [outputq + 112], m7
RET
%endif

View file

@ -0,0 +1,375 @@
/*
* Copyright (c) 2014 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 <emmintrin.h>
#include "./vpx_config.h"
#include "./vp9_rtcd.h"
#include "vpx_ports/emmintrin_compat.h"
#include "vpx/vpx_integer.h"
#include "vp9/common/vp9_reconinter.h"
#include "vp9/encoder/vp9_context_tree.h"
#include "vp9/encoder/vp9_denoiser.h"
#include "vpx_mem/vpx_mem.h"
// Compute the sum of all pixel differences of this MB.
static INLINE int sum_diff_16x1(__m128i acc_diff) {
const __m128i k_1 = _mm_set1_epi16(1);
const __m128i acc_diff_lo =
_mm_srai_epi16(_mm_unpacklo_epi8(acc_diff, acc_diff), 8);
const __m128i acc_diff_hi =
_mm_srai_epi16(_mm_unpackhi_epi8(acc_diff, acc_diff), 8);
const __m128i acc_diff_16 = _mm_add_epi16(acc_diff_lo, acc_diff_hi);
const __m128i hg_fe_dc_ba = _mm_madd_epi16(acc_diff_16, k_1);
const __m128i hgfe_dcba =
_mm_add_epi32(hg_fe_dc_ba, _mm_srli_si128(hg_fe_dc_ba, 8));
const __m128i hgfedcba =
_mm_add_epi32(hgfe_dcba, _mm_srli_si128(hgfe_dcba, 4));
return _mm_cvtsi128_si32(hgfedcba);
}
// Denoise a 16x1 vector.
static INLINE __m128i vp9_denoiser_16x1_sse2(const uint8_t *sig,
const uint8_t *mc_running_avg_y,
uint8_t *running_avg_y,
const __m128i *k_0,
const __m128i *k_4,
const __m128i *k_8,
const __m128i *k_16,
const __m128i *l3,
const __m128i *l32,
const __m128i *l21,
__m128i acc_diff) {
// Calculate differences
const __m128i v_sig = _mm_loadu_si128((const __m128i *)(&sig[0]));
const __m128i v_mc_running_avg_y =
_mm_loadu_si128((const __m128i *)(&mc_running_avg_y[0]));
__m128i v_running_avg_y;
const __m128i pdiff = _mm_subs_epu8(v_mc_running_avg_y, v_sig);
const __m128i ndiff = _mm_subs_epu8(v_sig, v_mc_running_avg_y);
// Obtain the sign. FF if diff is negative.
const __m128i diff_sign = _mm_cmpeq_epi8(pdiff, *k_0);
// Clamp absolute difference to 16 to be used to get mask. Doing this
// allows us to use _mm_cmpgt_epi8, which operates on signed byte.
const __m128i clamped_absdiff =
_mm_min_epu8(_mm_or_si128(pdiff, ndiff), *k_16);
// Get masks for l2 l1 and l0 adjustments.
const __m128i mask2 = _mm_cmpgt_epi8(*k_16, clamped_absdiff);
const __m128i mask1 = _mm_cmpgt_epi8(*k_8, clamped_absdiff);
const __m128i mask0 = _mm_cmpgt_epi8(*k_4, clamped_absdiff);
// Get adjustments for l2, l1, and l0.
__m128i adj2 = _mm_and_si128(mask2, *l32);
const __m128i adj1 = _mm_and_si128(mask1, *l21);
const __m128i adj0 = _mm_and_si128(mask0, clamped_absdiff);
__m128i adj, padj, nadj;
// Combine the adjustments and get absolute adjustments.
adj2 = _mm_add_epi8(adj2, adj1);
adj = _mm_sub_epi8(*l3, adj2);
adj = _mm_andnot_si128(mask0, adj);
adj = _mm_or_si128(adj, adj0);
// Restore the sign and get positive and negative adjustments.
padj = _mm_andnot_si128(diff_sign, adj);
nadj = _mm_and_si128(diff_sign, adj);
// Calculate filtered value.
v_running_avg_y = _mm_adds_epu8(v_sig, padj);
v_running_avg_y = _mm_subs_epu8(v_running_avg_y, nadj);
_mm_storeu_si128((__m128i *)running_avg_y, v_running_avg_y);
// Adjustments <=7, and each element in acc_diff can fit in signed
// char.
acc_diff = _mm_adds_epi8(acc_diff, padj);
acc_diff = _mm_subs_epi8(acc_diff, nadj);
return acc_diff;
}
// Denoise a 16x1 vector with a weaker filter.
static INLINE __m128i vp9_denoiser_adj_16x1_sse2(
const uint8_t *sig, const uint8_t *mc_running_avg_y,
uint8_t *running_avg_y, const __m128i k_0,
const __m128i k_delta, __m128i acc_diff) {
__m128i v_running_avg_y = _mm_loadu_si128((__m128i *)(&running_avg_y[0]));
// Calculate differences.
const __m128i v_sig = _mm_loadu_si128((const __m128i *)(&sig[0]));
const __m128i v_mc_running_avg_y =
_mm_loadu_si128((const __m128i *)(&mc_running_avg_y[0]));
const __m128i pdiff = _mm_subs_epu8(v_mc_running_avg_y, v_sig);
const __m128i ndiff = _mm_subs_epu8(v_sig, v_mc_running_avg_y);
// Obtain the sign. FF if diff is negative.
const __m128i diff_sign = _mm_cmpeq_epi8(pdiff, k_0);
// Clamp absolute difference to delta to get the adjustment.
const __m128i adj =
_mm_min_epu8(_mm_or_si128(pdiff, ndiff), k_delta);
// Restore the sign and get positive and negative adjustments.
__m128i padj, nadj;
padj = _mm_andnot_si128(diff_sign, adj);
nadj = _mm_and_si128(diff_sign, adj);
// Calculate filtered value.
v_running_avg_y = _mm_subs_epu8(v_running_avg_y, padj);
v_running_avg_y = _mm_adds_epu8(v_running_avg_y, nadj);
_mm_storeu_si128((__m128i *)running_avg_y, v_running_avg_y);
// Accumulate the adjustments.
acc_diff = _mm_subs_epi8(acc_diff, padj);
acc_diff = _mm_adds_epi8(acc_diff, nadj);
return acc_diff;
}
// Denoiser for 4xM and 8xM blocks.
static int vp9_denoiser_NxM_sse2_small(
const uint8_t *sig, int sig_stride, const uint8_t *mc_running_avg_y,
int mc_avg_y_stride, uint8_t *running_avg_y, int avg_y_stride,
int increase_denoising, BLOCK_SIZE bs, int motion_magnitude, int width) {
int sum_diff_thresh, r, sum_diff = 0;
const int shift_inc = (increase_denoising &&
motion_magnitude <= MOTION_MAGNITUDE_THRESHOLD) ?
1 : 0;
uint8_t sig_buffer[8][16], mc_running_buffer[8][16], running_buffer[8][16];
__m128i acc_diff = _mm_setzero_si128();
const __m128i k_0 = _mm_setzero_si128();
const __m128i k_4 = _mm_set1_epi8(4 + shift_inc);
const __m128i k_8 = _mm_set1_epi8(8);
const __m128i k_16 = _mm_set1_epi8(16);
// Modify each level's adjustment according to motion_magnitude.
const __m128i l3 = _mm_set1_epi8(
(motion_magnitude <= MOTION_MAGNITUDE_THRESHOLD) ? 7 + shift_inc : 6);
// Difference between level 3 and level 2 is 2.
const __m128i l32 = _mm_set1_epi8(2);
// Difference between level 2 and level 1 is 1.
const __m128i l21 = _mm_set1_epi8(1);
const uint8_t shift = (width == 4) ? 2 : 1;
for (r = 0; r < ((4 << b_height_log2_lookup[bs]) >> shift); ++r) {
memcpy(sig_buffer[r], sig, width);
memcpy(sig_buffer[r] + width, sig + sig_stride, width);
memcpy(mc_running_buffer[r], mc_running_avg_y, width);
memcpy(mc_running_buffer[r] + width,
mc_running_avg_y + mc_avg_y_stride, width);
memcpy(running_buffer[r], running_avg_y, width);
memcpy(running_buffer[r] + width, running_avg_y + avg_y_stride, width);
if (width == 4) {
memcpy(sig_buffer[r] + width * 2, sig + sig_stride * 2, width);
memcpy(sig_buffer[r] + width * 3, sig + sig_stride * 3, width);
memcpy(mc_running_buffer[r] + width * 2,
mc_running_avg_y + mc_avg_y_stride * 2, width);
memcpy(mc_running_buffer[r] + width * 3,
mc_running_avg_y + mc_avg_y_stride * 3, width);
memcpy(running_buffer[r] + width * 2,
running_avg_y + avg_y_stride * 2, width);
memcpy(running_buffer[r] + width * 3,
running_avg_y + avg_y_stride * 3, width);
}
acc_diff = vp9_denoiser_16x1_sse2(sig_buffer[r],
mc_running_buffer[r],
running_buffer[r],
&k_0, &k_4, &k_8, &k_16,
&l3, &l32, &l21, acc_diff);
memcpy(running_avg_y, running_buffer[r], width);
memcpy(running_avg_y + avg_y_stride, running_buffer[r] + width, width);
if (width == 4) {
memcpy(running_avg_y + avg_y_stride * 2,
running_buffer[r] + width * 2, width);
memcpy(running_avg_y + avg_y_stride * 3,
running_buffer[r] + width * 3, width);
}
// Update pointers for next iteration.
sig += (sig_stride << shift);
mc_running_avg_y += (mc_avg_y_stride << shift);
running_avg_y += (avg_y_stride << shift);
}
{
sum_diff = sum_diff_16x1(acc_diff);
sum_diff_thresh = total_adj_strong_thresh(bs, increase_denoising);
if (abs(sum_diff) > sum_diff_thresh) {
// Before returning to copy the block (i.e., apply no denoising),
// check if we can still apply some (weaker) temporal filtering to
// this block, that would otherwise not be denoised at all. Simplest
// is to apply an additional adjustment to running_avg_y to bring it
// closer to sig. The adjustment is capped by a maximum delta, and
// chosen such that in most cases the resulting sum_diff will be
// within the acceptable range given by sum_diff_thresh.
// The delta is set by the excess of absolute pixel diff over the
// threshold.
const int delta = ((abs(sum_diff) - sum_diff_thresh) >>
num_pels_log2_lookup[bs]) + 1;
// Only apply the adjustment for max delta up to 3.
if (delta < 4) {
const __m128i k_delta = _mm_set1_epi8(delta);
running_avg_y -= avg_y_stride * (4 << b_height_log2_lookup[bs]);
for (r = 0; r < ((4 << b_height_log2_lookup[bs]) >> shift); ++r) {
acc_diff = vp9_denoiser_adj_16x1_sse2(
sig_buffer[r], mc_running_buffer[r], running_buffer[r],
k_0, k_delta, acc_diff);
memcpy(running_avg_y, running_buffer[r], width);
memcpy(running_avg_y + avg_y_stride,
running_buffer[r] + width, width);
if (width == 4) {
memcpy(running_avg_y + avg_y_stride * 2,
running_buffer[r] + width * 2, width);
memcpy(running_avg_y + avg_y_stride * 3,
running_buffer[r] + width * 3, width);
}
// Update pointers for next iteration.
running_avg_y += (avg_y_stride << shift);
}
sum_diff = sum_diff_16x1(acc_diff);
if (abs(sum_diff) > sum_diff_thresh) {
return COPY_BLOCK;
}
} else {
return COPY_BLOCK;
}
}
}
return FILTER_BLOCK;
}
// Denoiser for 16xM, 32xM and 64xM blocks
static int vp9_denoiser_NxM_sse2_big(const uint8_t *sig, int sig_stride,
const uint8_t *mc_running_avg_y,
int mc_avg_y_stride,
uint8_t *running_avg_y,
int avg_y_stride,
int increase_denoising, BLOCK_SIZE bs,
int motion_magnitude) {
int sum_diff_thresh, r, c, sum_diff = 0;
const int shift_inc = (increase_denoising &&
motion_magnitude <= MOTION_MAGNITUDE_THRESHOLD) ?
1 : 0;
__m128i acc_diff[4][4];
const __m128i k_0 = _mm_setzero_si128();
const __m128i k_4 = _mm_set1_epi8(4 + shift_inc);
const __m128i k_8 = _mm_set1_epi8(8);
const __m128i k_16 = _mm_set1_epi8(16);
// Modify each level's adjustment according to motion_magnitude.
const __m128i l3 = _mm_set1_epi8(
(motion_magnitude <= MOTION_MAGNITUDE_THRESHOLD) ? 7 + shift_inc : 6);
// Difference between level 3 and level 2 is 2.
const __m128i l32 = _mm_set1_epi8(2);
// Difference between level 2 and level 1 is 1.
const __m128i l21 = _mm_set1_epi8(1);
for (c = 0; c < 4; ++c) {
for (r = 0; r < 4; ++r) {
acc_diff[c][r] = _mm_setzero_si128();
}
}
for (r = 0; r < (4 << b_height_log2_lookup[bs]); ++r) {
for (c = 0; c < (4 << b_width_log2_lookup[bs]); c += 16) {
acc_diff[c>>4][r>>4] = vp9_denoiser_16x1_sse2(
sig, mc_running_avg_y, running_avg_y, &k_0, &k_4,
&k_8, &k_16, &l3, &l32, &l21, acc_diff[c>>4][r>>4]);
// Update pointers for next iteration.
sig += 16;
mc_running_avg_y += 16;
running_avg_y += 16;
}
if ((r + 1) % 16 == 0 || (bs == BLOCK_16X8 && r == 7)) {
for (c = 0; c < (4 << b_width_log2_lookup[bs]); c += 16) {
sum_diff += sum_diff_16x1(acc_diff[c>>4][r>>4]);
}
}
// Update pointers for next iteration.
sig = sig - 16 * ((4 << b_width_log2_lookup[bs]) >> 4) + sig_stride;
mc_running_avg_y = mc_running_avg_y -
16 * ((4 << b_width_log2_lookup[bs]) >> 4) +
mc_avg_y_stride;
running_avg_y = running_avg_y -
16 * ((4 << b_width_log2_lookup[bs]) >> 4) +
avg_y_stride;
}
{
sum_diff_thresh = total_adj_strong_thresh(bs, increase_denoising);
if (abs(sum_diff) > sum_diff_thresh) {
const int delta = ((abs(sum_diff) - sum_diff_thresh) >>
num_pels_log2_lookup[bs]) + 1;
// Only apply the adjustment for max delta up to 3.
if (delta < 4) {
const __m128i k_delta = _mm_set1_epi8(delta);
sig -= sig_stride * (4 << b_height_log2_lookup[bs]);
mc_running_avg_y -= mc_avg_y_stride * (4 << b_height_log2_lookup[bs]);
running_avg_y -= avg_y_stride * (4 << b_height_log2_lookup[bs]);
sum_diff = 0;
for (r = 0; r < (4 << b_height_log2_lookup[bs]); ++r) {
for (c = 0; c < (4 << b_width_log2_lookup[bs]); c += 16) {
acc_diff[c>>4][r>>4] = vp9_denoiser_adj_16x1_sse2(
sig, mc_running_avg_y, running_avg_y, k_0,
k_delta, acc_diff[c>>4][r>>4]);
// Update pointers for next iteration.
sig += 16;
mc_running_avg_y += 16;
running_avg_y += 16;
}
if ((r + 1) % 16 == 0 || (bs == BLOCK_16X8 && r == 7)) {
for (c = 0; c < (4 << b_width_log2_lookup[bs]); c += 16) {
sum_diff += sum_diff_16x1(acc_diff[c>>4][r>>4]);
}
}
sig = sig - 16 * ((4 << b_width_log2_lookup[bs]) >> 4) + sig_stride;
mc_running_avg_y = mc_running_avg_y -
16 * ((4 << b_width_log2_lookup[bs]) >> 4) +
mc_avg_y_stride;
running_avg_y = running_avg_y -
16 * ((4 << b_width_log2_lookup[bs]) >> 4) +
avg_y_stride;
}
if (abs(sum_diff) > sum_diff_thresh) {
return COPY_BLOCK;
}
} else {
return COPY_BLOCK;
}
}
}
return FILTER_BLOCK;
}
int vp9_denoiser_filter_sse2(const uint8_t *sig, int sig_stride,
const uint8_t *mc_avg,
int mc_avg_stride,
uint8_t *avg, int avg_stride,
int increase_denoising,
BLOCK_SIZE bs,
int motion_magnitude) {
if (bs == BLOCK_4X4 || bs == BLOCK_4X8) {
return vp9_denoiser_NxM_sse2_small(sig, sig_stride,
mc_avg, mc_avg_stride,
avg, avg_stride,
increase_denoising,
bs, motion_magnitude, 4);
} else if (bs == BLOCK_8X4 || bs == BLOCK_8X8 || bs == BLOCK_8X16) {
return vp9_denoiser_NxM_sse2_small(sig, sig_stride,
mc_avg, mc_avg_stride,
avg, avg_stride,
increase_denoising,
bs, motion_magnitude, 8);
} else if (bs == BLOCK_16X8 || bs == BLOCK_16X16 || bs == BLOCK_16X32 ||
bs == BLOCK_32X16|| bs == BLOCK_32X32 || bs == BLOCK_32X64 ||
bs == BLOCK_64X32 || bs == BLOCK_64X64) {
return vp9_denoiser_NxM_sse2_big(sig, sig_stride,
mc_avg, mc_avg_stride,
avg, avg_stride,
increase_denoising,
bs, motion_magnitude);
} else {
return COPY_BLOCK;
}
}

View file

@ -0,0 +1,73 @@
/*
* Copyright (c) 2014 The WebM project authors. All Rights Reserved.
*
* Usee 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 <immintrin.h> // AVX2
#include "./vp9_rtcd.h"
#include "vpx/vpx_integer.h"
int64_t vp9_block_error_avx2(const int16_t *coeff,
const int16_t *dqcoeff,
intptr_t block_size,
int64_t *ssz) {
__m256i sse_reg, ssz_reg, coeff_reg, dqcoeff_reg;
__m256i exp_dqcoeff_lo, exp_dqcoeff_hi, exp_coeff_lo, exp_coeff_hi;
__m256i sse_reg_64hi, ssz_reg_64hi;
__m128i sse_reg128, ssz_reg128;
int64_t sse;
int i;
const __m256i zero_reg = _mm256_set1_epi16(0);
// init sse and ssz registerd to zero
sse_reg = _mm256_set1_epi16(0);
ssz_reg = _mm256_set1_epi16(0);
for (i = 0 ; i < block_size ; i+= 16) {
// load 32 bytes from coeff and dqcoeff
coeff_reg = _mm256_loadu_si256((const __m256i *)(coeff + i));
dqcoeff_reg = _mm256_loadu_si256((const __m256i *)(dqcoeff + i));
// dqcoeff - coeff
dqcoeff_reg = _mm256_sub_epi16(dqcoeff_reg, coeff_reg);
// madd (dqcoeff - coeff)
dqcoeff_reg = _mm256_madd_epi16(dqcoeff_reg, dqcoeff_reg);
// madd coeff
coeff_reg = _mm256_madd_epi16(coeff_reg, coeff_reg);
// expand each double word of madd (dqcoeff - coeff) to quad word
exp_dqcoeff_lo = _mm256_unpacklo_epi32(dqcoeff_reg, zero_reg);
exp_dqcoeff_hi = _mm256_unpackhi_epi32(dqcoeff_reg, zero_reg);
// expand each double word of madd (coeff) to quad word
exp_coeff_lo = _mm256_unpacklo_epi32(coeff_reg, zero_reg);
exp_coeff_hi = _mm256_unpackhi_epi32(coeff_reg, zero_reg);
// add each quad word of madd (dqcoeff - coeff) and madd (coeff)
sse_reg = _mm256_add_epi64(sse_reg, exp_dqcoeff_lo);
ssz_reg = _mm256_add_epi64(ssz_reg, exp_coeff_lo);
sse_reg = _mm256_add_epi64(sse_reg, exp_dqcoeff_hi);
ssz_reg = _mm256_add_epi64(ssz_reg, exp_coeff_hi);
}
// save the higher 64 bit of each 128 bit lane
sse_reg_64hi = _mm256_srli_si256(sse_reg, 8);
ssz_reg_64hi = _mm256_srli_si256(ssz_reg, 8);
// add the higher 64 bit to the low 64 bit
sse_reg = _mm256_add_epi64(sse_reg, sse_reg_64hi);
ssz_reg = _mm256_add_epi64(ssz_reg, ssz_reg_64hi);
// add each 64 bit from each of the 128 bit lane of the 256 bit
sse_reg128 = _mm_add_epi64(_mm256_castsi256_si128(sse_reg),
_mm256_extractf128_si256(sse_reg, 1));
ssz_reg128 = _mm_add_epi64(_mm256_castsi256_si128(ssz_reg),
_mm256_extractf128_si256(ssz_reg, 1));
// store the results
_mm_storel_epi64((__m128i*)(&sse), sse_reg128);
_mm_storel_epi64((__m128i*)(ssz), ssz_reg128);
return sse;
}

View file

@ -0,0 +1,120 @@
;
; 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 "third_party/x86inc/x86inc.asm"
SECTION .text
; int64_t vp9_block_error(int16_t *coeff, int16_t *dqcoeff, intptr_t block_size,
; int64_t *ssz)
INIT_XMM sse2
cglobal block_error, 3, 3, 8, uqc, dqc, size, ssz
pxor m4, m4 ; sse accumulator
pxor m6, m6 ; ssz accumulator
pxor m5, m5 ; dedicated zero register
lea uqcq, [uqcq+sizeq*2]
lea dqcq, [dqcq+sizeq*2]
neg sizeq
.loop:
mova m2, [uqcq+sizeq*2]
mova m0, [dqcq+sizeq*2]
mova m3, [uqcq+sizeq*2+mmsize]
mova m1, [dqcq+sizeq*2+mmsize]
psubw m0, m2
psubw m1, m3
; individual errors are max. 15bit+sign, so squares are 30bit, and
; thus the sum of 2 should fit in a 31bit integer (+ unused sign bit)
pmaddwd m0, m0
pmaddwd m1, m1
pmaddwd m2, m2
pmaddwd m3, m3
; accumulate in 64bit
punpckldq m7, m0, m5
punpckhdq m0, m5
paddq m4, m7
punpckldq m7, m1, m5
paddq m4, m0
punpckhdq m1, m5
paddq m4, m7
punpckldq m7, m2, m5
paddq m4, m1
punpckhdq m2, m5
paddq m6, m7
punpckldq m7, m3, m5
paddq m6, m2
punpckhdq m3, m5
paddq m6, m7
paddq m6, m3
add sizeq, mmsize
jl .loop
; accumulate horizontally and store in return value
movhlps m5, m4
movhlps m7, m6
paddq m4, m5
paddq m6, m7
%if ARCH_X86_64
movq rax, m4
movq [sszq], m6
%else
mov eax, sszm
pshufd m5, m4, 0x1
movq [eax], m6
movd eax, m4
movd edx, m5
%endif
RET
; Compute the sum of squared difference between two int16_t vectors.
; int64_t vp9_block_error_fp(int16_t *coeff, int16_t *dqcoeff,
; intptr_t block_size)
INIT_XMM sse2
cglobal block_error_fp, 3, 3, 6, uqc, dqc, size
pxor m4, m4 ; sse accumulator
pxor m5, m5 ; dedicated zero register
lea uqcq, [uqcq+sizeq*2]
lea dqcq, [dqcq+sizeq*2]
neg sizeq
.loop:
mova m2, [uqcq+sizeq*2]
mova m0, [dqcq+sizeq*2]
mova m3, [uqcq+sizeq*2+mmsize]
mova m1, [dqcq+sizeq*2+mmsize]
psubw m0, m2
psubw m1, m3
; individual errors are max. 15bit+sign, so squares are 30bit, and
; thus the sum of 2 should fit in a 31bit integer (+ unused sign bit)
pmaddwd m0, m0
pmaddwd m1, m1
; accumulate in 64bit
punpckldq m3, m0, m5
punpckhdq m0, m5
paddq m4, m3
punpckldq m3, m1, m5
paddq m4, m0
punpckhdq m1, m5
paddq m4, m3
paddq m4, m1
add sizeq, mmsize
jl .loop
; accumulate horizontally and store in return value
movhlps m5, m4
paddq m4, m5
%if ARCH_X86_64
movq rax, m4
%else
pshufd m5, m4, 0x1
movd eax, m4
movd edx, m5
%endif
RET

View file

@ -0,0 +1,71 @@
/*
* Copyright (c) 2014 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 <emmintrin.h>
#include <stdio.h>
#include "vp9/common/vp9_common.h"
int64_t vp9_highbd_block_error_sse2(tran_low_t *coeff, tran_low_t *dqcoeff,
intptr_t block_size, int64_t *ssz,
int bps) {
int i, j, test;
uint32_t temp[4];
__m128i max, min, cmp0, cmp1, cmp2, cmp3;
int64_t error = 0, sqcoeff = 0;
const int shift = 2 * (bps - 8);
const int rounding = shift > 0 ? 1 << (shift - 1) : 0;
for (i = 0; i < block_size; i+=8) {
// Load the data into xmm registers
__m128i mm_coeff = _mm_load_si128((__m128i*) (coeff + i));
__m128i mm_coeff2 = _mm_load_si128((__m128i*) (coeff + i + 4));
__m128i mm_dqcoeff = _mm_load_si128((__m128i*) (dqcoeff + i));
__m128i mm_dqcoeff2 = _mm_load_si128((__m128i*) (dqcoeff + i + 4));
// Check if any values require more than 15 bit
max = _mm_set1_epi32(0x3fff);
min = _mm_set1_epi32(0xffffc000);
cmp0 = _mm_xor_si128(_mm_cmpgt_epi32(mm_coeff, max),
_mm_cmplt_epi32(mm_coeff, min));
cmp1 = _mm_xor_si128(_mm_cmpgt_epi32(mm_coeff2, max),
_mm_cmplt_epi32(mm_coeff2, min));
cmp2 = _mm_xor_si128(_mm_cmpgt_epi32(mm_dqcoeff, max),
_mm_cmplt_epi32(mm_dqcoeff, min));
cmp3 = _mm_xor_si128(_mm_cmpgt_epi32(mm_dqcoeff2, max),
_mm_cmplt_epi32(mm_dqcoeff2, min));
test = _mm_movemask_epi8(_mm_or_si128(_mm_or_si128(cmp0, cmp1),
_mm_or_si128(cmp2, cmp3)));
if (!test) {
__m128i mm_diff, error_sse2, sqcoeff_sse2;;
mm_coeff = _mm_packs_epi32(mm_coeff, mm_coeff2);
mm_dqcoeff = _mm_packs_epi32(mm_dqcoeff, mm_dqcoeff2);
mm_diff = _mm_sub_epi16(mm_coeff, mm_dqcoeff);
error_sse2 = _mm_madd_epi16(mm_diff, mm_diff);
sqcoeff_sse2 = _mm_madd_epi16(mm_coeff, mm_coeff);
_mm_storeu_si128((__m128i*)temp, error_sse2);
error = error + temp[0] + temp[1] + temp[2] + temp[3];
_mm_storeu_si128((__m128i*)temp, sqcoeff_sse2);
sqcoeff += temp[0] + temp[1] + temp[2] + temp[3];
} else {
for (j = 0; j < 8; j++) {
const int64_t diff = coeff[i + j] - dqcoeff[i + j];
error += diff * diff;
sqcoeff += (int64_t)coeff[i + j] * (int64_t)coeff[i + j];
}
}
}
assert(error >= 0 && sqcoeff >= 0);
error = (error + rounding) >> shift;
sqcoeff = (sqcoeff + rounding) >> shift;
*ssz = sqcoeff;
return error;
}

View file

@ -0,0 +1,181 @@
/*
* Copyright (c) 2014 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 <emmintrin.h>
#include "vpx_ports/mem.h"
#include "vp9/common/vp9_common.h"
#if CONFIG_VP9_HIGHBITDEPTH
// from vp9_idct.h: typedef int32_t tran_low_t;
void vp9_highbd_quantize_b_sse2(const tran_low_t *coeff_ptr,
intptr_t count,
int skip_block,
const int16_t *zbin_ptr,
const int16_t *round_ptr,
const int16_t *quant_ptr,
const int16_t *quant_shift_ptr,
tran_low_t *qcoeff_ptr,
tran_low_t *dqcoeff_ptr,
const int16_t *dequant_ptr,
uint16_t *eob_ptr,
const int16_t *scan,
const int16_t *iscan) {
int i, j, non_zero_regs = (int)count / 4, eob_i = -1;
__m128i zbins[2];
__m128i nzbins[2];
zbins[0] = _mm_set_epi32((int)zbin_ptr[1],
(int)zbin_ptr[1],
(int)zbin_ptr[1],
(int)zbin_ptr[0]);
zbins[1] = _mm_set1_epi32((int)zbin_ptr[1]);
nzbins[0] = _mm_setzero_si128();
nzbins[1] = _mm_setzero_si128();
nzbins[0] = _mm_sub_epi32(nzbins[0], zbins[0]);
nzbins[1] = _mm_sub_epi32(nzbins[1], zbins[1]);
(void)scan;
memset(qcoeff_ptr, 0, count * sizeof(*qcoeff_ptr));
memset(dqcoeff_ptr, 0, count * sizeof(*dqcoeff_ptr));
if (!skip_block) {
// Pre-scan pass
for (i = ((int)count / 4) - 1; i >= 0; i--) {
__m128i coeffs, cmp1, cmp2;
int test;
coeffs = _mm_load_si128((const __m128i *)(coeff_ptr + i * 4));
cmp1 = _mm_cmplt_epi32(coeffs, zbins[i != 0]);
cmp2 = _mm_cmpgt_epi32(coeffs, nzbins[i != 0]);
cmp1 = _mm_and_si128(cmp1, cmp2);
test = _mm_movemask_epi8(cmp1);
if (test == 0xffff)
non_zero_regs--;
else
break;
}
// Quantization pass:
for (i = 0; i < non_zero_regs; i++) {
__m128i coeffs, coeffs_sign, tmp1, tmp2;
int test;
int abs_coeff[4];
int coeff_sign[4];
coeffs = _mm_load_si128((const __m128i *)(coeff_ptr + i * 4));
coeffs_sign = _mm_srai_epi32(coeffs, 31);
coeffs = _mm_sub_epi32(
_mm_xor_si128(coeffs, coeffs_sign), coeffs_sign);
tmp1 = _mm_cmpgt_epi32(coeffs, zbins[i != 0]);
tmp2 = _mm_cmpeq_epi32(coeffs, zbins[i != 0]);
tmp1 = _mm_or_si128(tmp1, tmp2);
test = _mm_movemask_epi8(tmp1);
_mm_storeu_si128((__m128i*)abs_coeff, coeffs);
_mm_storeu_si128((__m128i*)coeff_sign, coeffs_sign);
for (j = 0; j < 4; j++) {
if (test & (1 << (4 * j))) {
int k = 4 * i + j;
int64_t tmp = clamp(abs_coeff[j] + round_ptr[k != 0],
INT32_MIN, INT32_MAX);
tmp = ((((tmp * quant_ptr[k != 0]) >> 16) + tmp) *
quant_shift_ptr[k != 0]) >> 16; // quantization
qcoeff_ptr[k] = (tmp ^ coeff_sign[j]) - coeff_sign[j];
dqcoeff_ptr[k] = qcoeff_ptr[k] * dequant_ptr[k != 0];
if (tmp)
eob_i = iscan[k] > eob_i ? iscan[k] : eob_i;
}
}
}
}
*eob_ptr = eob_i + 1;
}
void vp9_highbd_quantize_b_32x32_sse2(const tran_low_t *coeff_ptr,
intptr_t n_coeffs,
int skip_block,
const int16_t *zbin_ptr,
const int16_t *round_ptr,
const int16_t *quant_ptr,
const int16_t *quant_shift_ptr,
tran_low_t *qcoeff_ptr,
tran_low_t *dqcoeff_ptr,
const int16_t *dequant_ptr,
uint16_t *eob_ptr,
const int16_t *scan,
const int16_t *iscan) {
__m128i zbins[2];
__m128i nzbins[2];
int idx = 0;
int idx_arr[1024];
int i, eob = -1;
const int zbin0_tmp = ROUND_POWER_OF_TWO(zbin_ptr[0], 1);
const int zbin1_tmp = ROUND_POWER_OF_TWO(zbin_ptr[1], 1);
(void)scan;
zbins[0] = _mm_set_epi32(zbin1_tmp,
zbin1_tmp,
zbin1_tmp,
zbin0_tmp);
zbins[1] = _mm_set1_epi32(zbin1_tmp);
nzbins[0] = _mm_setzero_si128();
nzbins[1] = _mm_setzero_si128();
nzbins[0] = _mm_sub_epi32(nzbins[0], zbins[0]);
nzbins[1] = _mm_sub_epi32(nzbins[1], zbins[1]);
memset(qcoeff_ptr, 0, n_coeffs * sizeof(*qcoeff_ptr));
memset(dqcoeff_ptr, 0, n_coeffs * sizeof(*dqcoeff_ptr));
if (!skip_block) {
// Pre-scan pass
for (i = 0; i < n_coeffs / 4; i++) {
__m128i coeffs, cmp1, cmp2;
int test;
coeffs = _mm_load_si128((const __m128i *)(coeff_ptr + i * 4));
cmp1 = _mm_cmplt_epi32(coeffs, zbins[i != 0]);
cmp2 = _mm_cmpgt_epi32(coeffs, nzbins[i != 0]);
cmp1 = _mm_and_si128(cmp1, cmp2);
test = _mm_movemask_epi8(cmp1);
if (!(test & 0xf))
idx_arr[idx++] = i * 4;
if (!(test & 0xf0))
idx_arr[idx++] = i * 4 + 1;
if (!(test & 0xf00))
idx_arr[idx++] = i * 4 + 2;
if (!(test & 0xf000))
idx_arr[idx++] = i * 4 + 3;
}
// Quantization pass: only process the coefficients selected in
// pre-scan pass. Note: idx can be zero.
for (i = 0; i < idx; i++) {
const int rc = idx_arr[i];
const int coeff = coeff_ptr[rc];
const int coeff_sign = (coeff >> 31);
int abs_coeff = (coeff ^ coeff_sign) - coeff_sign;
int64_t tmp = clamp(abs_coeff +
ROUND_POWER_OF_TWO(round_ptr[rc != 0], 1),
INT32_MIN, INT32_MAX);
tmp = ((((tmp * quant_ptr[rc != 0]) >> 16) + tmp) *
quant_shift_ptr[rc != 0]) >> 15;
qcoeff_ptr[rc] = (tmp ^ coeff_sign) - coeff_sign;
dqcoeff_ptr[rc] = qcoeff_ptr[rc] * dequant_ptr[rc != 0] / 2;
if (tmp)
eob = iscan[idx_arr[i]] > eob ? iscan[idx_arr[i]] : eob;
}
}
*eob_ptr = eob + 1;
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,349 @@
/*
* Copyright (c) 2014 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 "./vpx_config.h"
#include "vp9/common/vp9_common.h"
#include "vp9/encoder/vp9_variance.h"
#include "vpx_ports/mem.h"
#define DECL(w, opt) \
int vp9_highbd_sub_pixel_variance##w##xh_##opt(const uint16_t *src, \
ptrdiff_t src_stride, \
int x_offset, int y_offset, \
const uint16_t *dst, \
ptrdiff_t dst_stride, \
int height, unsigned int *sse);
#define DECLS(opt1, opt2) \
DECL(8, opt1); \
DECL(16, opt1)
DECLS(sse2, sse);
// DECLS(ssse3, ssse3);
#undef DECLS
#undef DECL
#define FN(w, h, wf, wlog2, hlog2, opt, cast) \
uint32_t vp9_highbd_sub_pixel_variance##w##x##h##_##opt(const uint8_t *src8, \
int src_stride, \
int x_offset, \
int y_offset, \
const uint8_t *dst8, \
int dst_stride, \
uint32_t *sse_ptr) { \
uint32_t sse; \
uint16_t *src = CONVERT_TO_SHORTPTR(src8); \
uint16_t *dst = CONVERT_TO_SHORTPTR(dst8); \
int se = vp9_highbd_sub_pixel_variance##wf##xh_##opt(src, src_stride, \
x_offset, y_offset, \
dst, dst_stride, h, \
&sse); \
if (w > wf) { \
unsigned int sse2; \
int se2 = vp9_highbd_sub_pixel_variance##wf##xh_##opt(src + 16, \
src_stride, \
x_offset, y_offset, \
dst + 16, \
dst_stride, \
h, &sse2); \
se += se2; \
sse += sse2; \
if (w > wf * 2) { \
se2 = vp9_highbd_sub_pixel_variance##wf##xh_##opt(src + 32, src_stride, \
x_offset, y_offset, \
dst + 32, dst_stride, \
h, &sse2); \
se += se2; \
sse += sse2; \
se2 = vp9_highbd_sub_pixel_variance##wf##xh_##opt( \
src + 48, src_stride, x_offset, y_offset, \
dst + 48, dst_stride, h, &sse2); \
se += se2; \
sse += sse2; \
} \
} \
*sse_ptr = sse; \
return sse - ((cast se * se) >> (wlog2 + hlog2)); \
} \
\
uint32_t vp9_highbd_10_sub_pixel_variance##w##x##h##_##opt( \
const uint8_t *src8, int src_stride, int x_offset, int y_offset, \
const uint8_t *dst8, int dst_stride, uint32_t *sse_ptr) { \
uint32_t sse; \
uint16_t *src = CONVERT_TO_SHORTPTR(src8); \
uint16_t *dst = CONVERT_TO_SHORTPTR(dst8); \
int se = vp9_highbd_sub_pixel_variance##wf##xh_##opt(src, src_stride, \
x_offset, y_offset, \
dst, dst_stride, \
h, &sse); \
if (w > wf) { \
uint32_t sse2; \
int se2 = vp9_highbd_sub_pixel_variance##wf##xh_##opt(src + 16, \
src_stride, \
x_offset, y_offset, \
dst + 16, \
dst_stride, \
h, &sse2); \
se += se2; \
sse += sse2; \
if (w > wf * 2) { \
se2 = vp9_highbd_sub_pixel_variance##wf##xh_##opt(src + 32, src_stride, \
x_offset, y_offset, \
dst + 32, dst_stride, \
h, &sse2); \
se += se2; \
sse += sse2; \
se2 = vp9_highbd_sub_pixel_variance##wf##xh_##opt(src + 48, src_stride, \
x_offset, y_offset, \
dst + 48, dst_stride, \
h, &sse2); \
se += se2; \
sse += sse2; \
} \
} \
se = ROUND_POWER_OF_TWO(se, 2); \
sse = ROUND_POWER_OF_TWO(sse, 4); \
*sse_ptr = sse; \
return sse - ((cast se * se) >> (wlog2 + hlog2)); \
} \
\
uint32_t vp9_highbd_12_sub_pixel_variance##w##x##h##_##opt( \
const uint8_t *src8, int src_stride, int x_offset, int y_offset, \
const uint8_t *dst8, int dst_stride, uint32_t *sse_ptr) { \
int start_row; \
uint32_t sse; \
int se = 0; \
uint64_t long_sse = 0; \
uint16_t *src = CONVERT_TO_SHORTPTR(src8); \
uint16_t *dst = CONVERT_TO_SHORTPTR(dst8); \
for (start_row = 0; start_row < h; start_row +=16) { \
uint32_t sse2; \
int height = h - start_row < 16 ? h - start_row : 16; \
int se2 = vp9_highbd_sub_pixel_variance##wf##xh_##opt( \
src + (start_row * src_stride), src_stride, \
x_offset, y_offset, dst + (start_row * dst_stride), \
dst_stride, height, &sse2); \
se += se2; \
long_sse += sse2; \
if (w > wf) { \
se2 = vp9_highbd_sub_pixel_variance##wf##xh_##opt( \
src + 16 + (start_row * src_stride), src_stride, \
x_offset, y_offset, dst + 16 + (start_row * dst_stride), \
dst_stride, height, &sse2); \
se += se2; \
long_sse += sse2; \
if (w > wf * 2) { \
se2 = vp9_highbd_sub_pixel_variance##wf##xh_##opt( \
src + 32 + (start_row * src_stride), src_stride, \
x_offset, y_offset, dst + 32 + (start_row * dst_stride), \
dst_stride, height, &sse2); \
se += se2; \
long_sse += sse2; \
se2 = vp9_highbd_sub_pixel_variance##wf##xh_##opt( \
src + 48 + (start_row * src_stride), src_stride, \
x_offset, y_offset, dst + 48 + (start_row * dst_stride), \
dst_stride, height, &sse2); \
se += se2; \
long_sse += sse2; \
}\
} \
} \
se = ROUND_POWER_OF_TWO(se, 4); \
sse = ROUND_POWER_OF_TWO(long_sse, 8); \
*sse_ptr = sse; \
return sse - ((cast se * se) >> (wlog2 + hlog2)); \
}
#define FNS(opt1, opt2) \
FN(64, 64, 16, 6, 6, opt1, (int64_t)); \
FN(64, 32, 16, 6, 5, opt1, (int64_t)); \
FN(32, 64, 16, 5, 6, opt1, (int64_t)); \
FN(32, 32, 16, 5, 5, opt1, (int64_t)); \
FN(32, 16, 16, 5, 4, opt1, (int64_t)); \
FN(16, 32, 16, 4, 5, opt1, (int64_t)); \
FN(16, 16, 16, 4, 4, opt1, (int64_t)); \
FN(16, 8, 16, 4, 3, opt1, (int64_t)); \
FN(8, 16, 8, 3, 4, opt1, (int64_t)); \
FN(8, 8, 8, 3, 3, opt1, (int64_t)); \
FN(8, 4, 8, 3, 2, opt1, (int64_t));
FNS(sse2, sse);
#undef FNS
#undef FN
#define DECL(w, opt) \
int vp9_highbd_sub_pixel_avg_variance##w##xh_##opt(const uint16_t *src, \
ptrdiff_t src_stride, \
int x_offset, int y_offset, \
const uint16_t *dst, \
ptrdiff_t dst_stride, \
const uint16_t *sec, \
ptrdiff_t sec_stride, \
int height, \
unsigned int *sse);
#define DECLS(opt1) \
DECL(16, opt1) \
DECL(8, opt1)
DECLS(sse2);
#undef DECL
#undef DECLS
#define FN(w, h, wf, wlog2, hlog2, opt, cast) \
uint32_t vp9_highbd_sub_pixel_avg_variance##w##x##h##_##opt( \
const uint8_t *src8, int src_stride, int x_offset, int y_offset, \
const uint8_t *dst8, int dst_stride, uint32_t *sse_ptr, \
const uint8_t *sec8) { \
uint32_t sse; \
uint16_t *src = CONVERT_TO_SHORTPTR(src8); \
uint16_t *dst = CONVERT_TO_SHORTPTR(dst8); \
uint16_t *sec = CONVERT_TO_SHORTPTR(sec8); \
int se = vp9_highbd_sub_pixel_avg_variance##wf##xh_##opt( \
src, src_stride, x_offset, \
y_offset, dst, dst_stride, sec, w, h, &sse); \
if (w > wf) { \
uint32_t sse2; \
int se2 = vp9_highbd_sub_pixel_avg_variance##wf##xh_##opt( \
src + 16, src_stride, x_offset, y_offset, \
dst + 16, dst_stride, sec + 16, w, h, &sse2); \
se += se2; \
sse += sse2; \
if (w > wf * 2) { \
se2 = vp9_highbd_sub_pixel_avg_variance##wf##xh_##opt( \
src + 32, src_stride, x_offset, y_offset, \
dst + 32, dst_stride, sec + 32, w, h, &sse2); \
se += se2; \
sse += sse2; \
se2 = vp9_highbd_sub_pixel_avg_variance##wf##xh_##opt( \
src + 48, src_stride, x_offset, y_offset, \
dst + 48, dst_stride, sec + 48, w, h, &sse2); \
se += se2; \
sse += sse2; \
} \
} \
*sse_ptr = sse; \
return sse - ((cast se * se) >> (wlog2 + hlog2)); \
} \
\
uint32_t vp9_highbd_10_sub_pixel_avg_variance##w##x##h##_##opt( \
const uint8_t *src8, int src_stride, int x_offset, int y_offset, \
const uint8_t *dst8, int dst_stride, uint32_t *sse_ptr, \
const uint8_t *sec8) { \
uint32_t sse; \
uint16_t *src = CONVERT_TO_SHORTPTR(src8); \
uint16_t *dst = CONVERT_TO_SHORTPTR(dst8); \
uint16_t *sec = CONVERT_TO_SHORTPTR(sec8); \
int se = vp9_highbd_sub_pixel_avg_variance##wf##xh_##opt( \
src, src_stride, x_offset, \
y_offset, dst, dst_stride, \
sec, w, h, &sse); \
if (w > wf) { \
uint32_t sse2; \
int se2 = vp9_highbd_sub_pixel_avg_variance##wf##xh_##opt( \
src + 16, src_stride, \
x_offset, y_offset, \
dst + 16, dst_stride, \
sec + 16, w, h, &sse2); \
se += se2; \
sse += sse2; \
if (w > wf * 2) { \
se2 = vp9_highbd_sub_pixel_avg_variance##wf##xh_##opt( \
src + 32, src_stride, \
x_offset, y_offset, \
dst + 32, dst_stride, \
sec + 32, w, h, &sse2); \
se += se2; \
sse += sse2; \
se2 = vp9_highbd_sub_pixel_avg_variance##wf##xh_##opt( \
src + 48, src_stride, \
x_offset, y_offset, \
dst + 48, dst_stride, \
sec + 48, w, h, &sse2); \
se += se2; \
sse += sse2; \
} \
} \
se = ROUND_POWER_OF_TWO(se, 2); \
sse = ROUND_POWER_OF_TWO(sse, 4); \
*sse_ptr = sse; \
return sse - ((cast se * se) >> (wlog2 + hlog2)); \
} \
\
uint32_t vp9_highbd_12_sub_pixel_avg_variance##w##x##h##_##opt( \
const uint8_t *src8, int src_stride, int x_offset, int y_offset, \
const uint8_t *dst8, int dst_stride, uint32_t *sse_ptr, \
const uint8_t *sec8) { \
int start_row; \
uint32_t sse; \
int se = 0; \
uint64_t long_sse = 0; \
uint16_t *src = CONVERT_TO_SHORTPTR(src8); \
uint16_t *dst = CONVERT_TO_SHORTPTR(dst8); \
uint16_t *sec = CONVERT_TO_SHORTPTR(sec8); \
for (start_row = 0; start_row < h; start_row +=16) { \
uint32_t sse2; \
int height = h - start_row < 16 ? h - start_row : 16; \
int se2 = vp9_highbd_sub_pixel_avg_variance##wf##xh_##opt( \
src + (start_row * src_stride), src_stride, x_offset, \
y_offset, dst + (start_row * dst_stride), dst_stride, \
sec + (start_row * w), w, height, &sse2); \
se += se2; \
long_sse += sse2; \
if (w > wf) { \
se2 = vp9_highbd_sub_pixel_avg_variance##wf##xh_##opt( \
src + 16 + (start_row * src_stride), src_stride, \
x_offset, y_offset, \
dst + 16 + (start_row * dst_stride), dst_stride, \
sec + 16 + (start_row * w), w, height, &sse2); \
se += se2; \
long_sse += sse2; \
if (w > wf * 2) { \
se2 = vp9_highbd_sub_pixel_avg_variance##wf##xh_##opt( \
src + 32 + (start_row * src_stride), src_stride, \
x_offset, y_offset, \
dst + 32 + (start_row * dst_stride), dst_stride, \
sec + 32 + (start_row * w), w, height, &sse2); \
se += se2; \
long_sse += sse2; \
se2 = vp9_highbd_sub_pixel_avg_variance##wf##xh_##opt( \
src + 48 + (start_row * src_stride), src_stride, \
x_offset, y_offset, \
dst + 48 + (start_row * dst_stride), dst_stride, \
sec + 48 + (start_row * w), w, height, &sse2); \
se += se2; \
long_sse += sse2; \
} \
} \
} \
se = ROUND_POWER_OF_TWO(se, 4); \
sse = ROUND_POWER_OF_TWO(long_sse, 8); \
*sse_ptr = sse; \
return sse - ((cast se * se) >> (wlog2 + hlog2)); \
}
#define FNS(opt1) \
FN(64, 64, 16, 6, 6, opt1, (int64_t)); \
FN(64, 32, 16, 6, 5, opt1, (int64_t)); \
FN(32, 64, 16, 5, 6, opt1, (int64_t)); \
FN(32, 32, 16, 5, 5, opt1, (int64_t)); \
FN(32, 16, 16, 5, 4, opt1, (int64_t)); \
FN(16, 32, 16, 4, 5, opt1, (int64_t)); \
FN(16, 16, 16, 4, 4, opt1, (int64_t)); \
FN(16, 8, 16, 4, 3, opt1, (int64_t)); \
FN(8, 16, 8, 4, 3, opt1, (int64_t)); \
FN(8, 8, 8, 3, 3, opt1, (int64_t)); \
FN(8, 4, 8, 3, 2, opt1, (int64_t));
FNS(sse2);
#undef FNS
#undef FN

Some files were not shown because too many files have changed in this diff Show more