mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-23 23:57:31 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
241
media/libvpx/vp9/encoder/arm/neon/vp9_dct_neon.c
Normal file
241
media/libvpx/vp9/encoder/arm/neon/vp9_dct_neon.c
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
118
media/libvpx/vp9/encoder/arm/neon/vp9_quantize_neon.c
Normal file
118
media/libvpx/vp9/encoder/arm/neon/vp9_quantize_neon.c
Normal 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;
|
||||
}
|
||||
}
|
||||
81
media/libvpx/vp9/encoder/arm/neon/vp9_subtract_neon.c
Normal file
81
media/libvpx/vp9/encoder/arm/neon/vp9_subtract_neon.c
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
153
media/libvpx/vp9/encoder/arm/neon/vp9_variance_neon.c
Normal file
153
media/libvpx/vp9/encoder/arm/neon/vp9_variance_neon.c
Normal 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);
|
||||
}
|
||||
49
media/libvpx/vp9/encoder/arm/neon/vp9enc_avg_neon.c
Normal file
49
media/libvpx/vp9/encoder/arm/neon/vp9enc_avg_neon.c
Normal 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;
|
||||
}
|
||||
163
media/libvpx/vp9/encoder/vp9_aq_complexity.c
Normal file
163
media/libvpx/vp9/encoder/vp9_aq_complexity.c
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
37
media/libvpx/vp9/encoder/vp9_aq_complexity.h
Normal file
37
media/libvpx/vp9/encoder/vp9_aq_complexity.h
Normal 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_
|
||||
519
media/libvpx/vp9/encoder/vp9_aq_cyclicrefresh.c
Normal file
519
media/libvpx/vp9/encoder/vp9_aq_cyclicrefresh.c
Normal 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;
|
||||
}
|
||||
99
media/libvpx/vp9/encoder/vp9_aq_cyclicrefresh.h
Normal file
99
media/libvpx/vp9/encoder/vp9_aq_cyclicrefresh.h
Normal 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_
|
||||
207
media/libvpx/vp9/encoder/vp9_aq_variance.c
Normal file
207
media/libvpx/vp9/encoder/vp9_aq_variance.c
Normal 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);
|
||||
}
|
||||
31
media/libvpx/vp9/encoder/vp9_aq_variance.h
Normal file
31
media/libvpx/vp9/encoder/vp9_aq_variance.h
Normal 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_
|
||||
211
media/libvpx/vp9/encoder/vp9_avg.c
Normal file
211
media/libvpx/vp9/encoder/vp9_avg.c
Normal 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
|
||||
|
||||
|
||||
1246
media/libvpx/vp9/encoder/vp9_bitstream.c
Normal file
1246
media/libvpx/vp9/encoder/vp9_bitstream.c
Normal file
File diff suppressed because it is too large
Load diff
37
media/libvpx/vp9/encoder/vp9_bitstream.h
Normal file
37
media/libvpx/vp9/encoder/vp9_bitstream.h
Normal 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_
|
||||
137
media/libvpx/vp9/encoder/vp9_block.h
Normal file
137
media/libvpx/vp9/encoder/vp9_block.h
Normal 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_
|
||||
138
media/libvpx/vp9/encoder/vp9_blockiness.c
Normal file
138
media/libvpx/vp9/encoder/vp9_blockiness.c
Normal 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;
|
||||
}
|
||||
158
media/libvpx/vp9/encoder/vp9_context_tree.c
Normal file
158
media/libvpx/vp9/encoder/vp9_context_tree.c
Normal 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;
|
||||
}
|
||||
86
media/libvpx/vp9/encoder/vp9_context_tree.h
Normal file
86
media/libvpx/vp9/encoder/vp9_context_tree.h
Normal 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_ */
|
||||
62
media/libvpx/vp9/encoder/vp9_cost.c
Normal file
62
media/libvpx/vp9/encoder/vp9_cost.c
Normal 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);
|
||||
}
|
||||
55
media/libvpx/vp9/encoder/vp9_cost.h
Normal file
55
media/libvpx/vp9/encoder/vp9_cost.h
Normal 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_
|
||||
1592
media/libvpx/vp9/encoder/vp9_dct.c
Normal file
1592
media/libvpx/vp9/encoder/vp9_dct.c
Normal file
File diff suppressed because it is too large
Load diff
61
media/libvpx/vp9/encoder/vp9_dct.h
Normal file
61
media/libvpx/vp9/encoder/vp9_dct.h
Normal 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_
|
||||
498
media/libvpx/vp9/encoder/vp9_denoiser.c
Normal file
498
media/libvpx/vp9/encoder/vp9_denoiser.c
Normal 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
|
||||
69
media/libvpx/vp9/encoder/vp9_denoiser.h
Normal file
69
media/libvpx/vp9/encoder/vp9_denoiser.h
Normal 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_
|
||||
4236
media/libvpx/vp9/encoder/vp9_encodeframe.c
Normal file
4236
media/libvpx/vp9/encoder/vp9_encodeframe.c
Normal file
File diff suppressed because it is too large
Load diff
49
media/libvpx/vp9/encoder/vp9_encodeframe.h
Normal file
49
media/libvpx/vp9/encoder/vp9_encodeframe.h
Normal 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_
|
||||
1046
media/libvpx/vp9/encoder/vp9_encodemb.c
Normal file
1046
media/libvpx/vp9/encoder/vp9_encodemb.c
Normal file
File diff suppressed because it is too large
Load diff
46
media/libvpx/vp9/encoder/vp9_encodemb.h
Normal file
46
media/libvpx/vp9/encoder/vp9_encodemb.h
Normal 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_
|
||||
266
media/libvpx/vp9/encoder/vp9_encodemv.c
Normal file
266
media/libvpx/vp9/encoder/vp9_encodemv.c
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
38
media/libvpx/vp9/encoder/vp9_encodemv.h
Normal file
38
media/libvpx/vp9/encoder/vp9_encodemv.h
Normal 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_
|
||||
4578
media/libvpx/vp9/encoder/vp9_encoder.c
Normal file
4578
media/libvpx/vp9/encoder/vp9_encoder.c
Normal file
File diff suppressed because it is too large
Load diff
654
media/libvpx/vp9/encoder/vp9_encoder.h
Normal file
654
media/libvpx/vp9/encoder/vp9_encoder.h
Normal 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_
|
||||
179
media/libvpx/vp9/encoder/vp9_ethread.c
Normal file
179
media/libvpx/vp9/encoder/vp9_ethread.c
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
25
media/libvpx/vp9/encoder/vp9_ethread.h
Normal file
25
media/libvpx/vp9/encoder/vp9_ethread.h
Normal 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_
|
||||
198
media/libvpx/vp9/encoder/vp9_extend.c
Normal file
198
media/libvpx/vp9/encoder/vp9_extend.c
Normal 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);
|
||||
}
|
||||
33
media/libvpx/vp9/encoder/vp9_extend.h
Normal file
33
media/libvpx/vp9/encoder/vp9_extend.h
Normal 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_
|
||||
465
media/libvpx/vp9/encoder/vp9_fastssim.c
Normal file
465
media/libvpx/vp9/encoder/vp9_fastssim.c
Normal 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);
|
||||
}
|
||||
2749
media/libvpx/vp9/encoder/vp9_firstpass.c
Normal file
2749
media/libvpx/vp9/encoder/vp9_firstpass.c
Normal file
File diff suppressed because it is too large
Load diff
154
media/libvpx/vp9/encoder/vp9_firstpass.h
Normal file
154
media/libvpx/vp9/encoder/vp9_firstpass.h
Normal 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_
|
||||
245
media/libvpx/vp9/encoder/vp9_lookahead.c
Normal file
245
media/libvpx/vp9/encoder/vp9_lookahead.c
Normal 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;
|
||||
}
|
||||
124
media/libvpx/vp9/encoder/vp9_lookahead.h
Normal file
124
media/libvpx/vp9/encoder/vp9_lookahead.h
Normal 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_
|
||||
416
media/libvpx/vp9/encoder/vp9_mbgraph.c
Normal file
416
media/libvpx/vp9/encoder/vp9_mbgraph.c
Normal 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);
|
||||
}
|
||||
40
media/libvpx/vp9/encoder/vp9_mbgraph.h
Normal file
40
media/libvpx/vp9/encoder/vp9_mbgraph.h
Normal 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_
|
||||
2357
media/libvpx/vp9/encoder/vp9_mcomp.c
Normal file
2357
media/libvpx/vp9/encoder/vp9_mcomp.c
Normal file
File diff suppressed because it is too large
Load diff
165
media/libvpx/vp9/encoder/vp9_mcomp.h
Normal file
165
media/libvpx/vp9/encoder/vp9_mcomp.h
Normal 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_
|
||||
192
media/libvpx/vp9/encoder/vp9_picklpf.c
Normal file
192
media/libvpx/vp9/encoder/vp9_picklpf.c
Normal 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);
|
||||
}
|
||||
}
|
||||
30
media/libvpx/vp9/encoder/vp9_picklpf.h
Normal file
30
media/libvpx/vp9/encoder/vp9_picklpf.h
Normal 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_
|
||||
1885
media/libvpx/vp9/encoder/vp9_pickmode.c
Normal file
1885
media/libvpx/vp9/encoder/vp9_pickmode.c
Normal file
File diff suppressed because it is too large
Load diff
39
media/libvpx/vp9/encoder/vp9_pickmode.h
Normal file
39
media/libvpx/vp9/encoder/vp9_pickmode.h
Normal 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_
|
||||
223
media/libvpx/vp9/encoder/vp9_psnrhvs.c
Normal file
223
media/libvpx/vp9/encoder/vp9_psnrhvs.c
Normal 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);
|
||||
}
|
||||
728
media/libvpx/vp9/encoder/vp9_quantize.c
Normal file
728
media/libvpx/vp9/encoder/vp9_quantize.c
Normal 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;
|
||||
}
|
||||
87
media/libvpx/vp9/encoder/vp9_quantize.h
Normal file
87
media/libvpx/vp9/encoder/vp9_quantize.h
Normal 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_
|
||||
1758
media/libvpx/vp9/encoder/vp9_ratectrl.c
Normal file
1758
media/libvpx/vp9/encoder/vp9_ratectrl.c
Normal file
File diff suppressed because it is too large
Load diff
252
media/libvpx/vp9/encoder/vp9_ratectrl.h
Normal file
252
media/libvpx/vp9/encoder/vp9_ratectrl.h
Normal 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_
|
||||
664
media/libvpx/vp9/encoder/vp9_rd.c
Normal file
664
media/libvpx/vp9/encoder/vp9_rd.c
Normal 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
|
||||
}
|
||||
|
||||
190
media/libvpx/vp9/encoder/vp9_rd.h
Normal file
190
media/libvpx/vp9/encoder/vp9_rd.h
Normal 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_
|
||||
4313
media/libvpx/vp9/encoder/vp9_rdopt.c
Normal file
4313
media/libvpx/vp9/encoder/vp9_rdopt.c
Normal file
File diff suppressed because it is too large
Load diff
68
media/libvpx/vp9/encoder/vp9_rdopt.h
Normal file
68
media/libvpx/vp9/encoder/vp9_rdopt.h
Normal 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_
|
||||
925
media/libvpx/vp9/encoder/vp9_resize.c
Normal file
925
media/libvpx/vp9/encoder/vp9_resize.c
Normal 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
|
||||
124
media/libvpx/vp9/encoder/vp9_resize.h
Normal file
124
media/libvpx/vp9/encoder/vp9_resize.h
Normal 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_
|
||||
281
media/libvpx/vp9/encoder/vp9_segmentation.c
Normal file
281
media/libvpx/vp9/encoder/vp9_segmentation.c
Normal 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);
|
||||
}
|
||||
53
media/libvpx/vp9/encoder/vp9_segmentation.h
Normal file
53
media/libvpx/vp9/encoder/vp9_segmentation.h
Normal 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_
|
||||
104
media/libvpx/vp9/encoder/vp9_skin_detection.c
Normal file
104
media/libvpx/vp9/encoder/vp9_skin_detection.c
Normal 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
|
||||
35
media/libvpx/vp9/encoder/vp9_skin_detection.h
Normal file
35
media/libvpx/vp9/encoder/vp9_skin_detection.h
Normal 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_
|
||||
531
media/libvpx/vp9/encoder/vp9_speed_features.c
Normal file
531
media/libvpx/vp9/encoder/vp9_speed_features.c
Normal 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;
|
||||
}
|
||||
}
|
||||
429
media/libvpx/vp9/encoder/vp9_speed_features.h
Normal file
429
media/libvpx/vp9/encoder/vp9_speed_features.h
Normal 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_
|
||||
96
media/libvpx/vp9/encoder/vp9_ssim.h
Normal file
96
media/libvpx/vp9/encoder/vp9_ssim.h
Normal 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_
|
||||
214
media/libvpx/vp9/encoder/vp9_subexp.c
Normal file
214
media/libvpx/vp9/encoder/vp9_subexp.c
Normal 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);
|
||||
}
|
||||
}
|
||||
44
media/libvpx/vp9/encoder/vp9_subexp.h
Normal file
44
media/libvpx/vp9/encoder/vp9_subexp.h
Normal 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_
|
||||
646
media/libvpx/vp9/encoder/vp9_svc_layercontext.c
Normal file
646
media/libvpx/vp9/encoder/vp9_svc_layercontext.c
Normal 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;
|
||||
}
|
||||
122
media/libvpx/vp9/encoder/vp9_svc_layercontext.h
Normal file
122
media/libvpx/vp9/encoder/vp9_svc_layercontext.h
Normal 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_
|
||||
750
media/libvpx/vp9/encoder/vp9_temporal_filter.c
Normal file
750
media/libvpx/vp9/encoder/vp9_temporal_filter.c
Normal 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);
|
||||
}
|
||||
25
media/libvpx/vp9/encoder/vp9_temporal_filter.h
Normal file
25
media/libvpx/vp9/encoder/vp9_temporal_filter.h
Normal 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_
|
||||
634
media/libvpx/vp9/encoder/vp9_tokenize.c
Normal file
634
media/libvpx/vp9/encoder/vp9_tokenize.c
Normal 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);
|
||||
}
|
||||
}
|
||||
112
media/libvpx/vp9/encoder/vp9_tokenize.h
Normal file
112
media/libvpx/vp9/encoder/vp9_tokenize.h
Normal 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_
|
||||
58
media/libvpx/vp9/encoder/vp9_treewriter.c
Normal file
58
media/libvpx/vp9/encoder/vp9_treewriter.c
Normal 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);
|
||||
}
|
||||
51
media/libvpx/vp9/encoder/vp9_treewriter.h
Normal file
51
media/libvpx/vp9/encoder/vp9_treewriter.h
Normal 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_
|
||||
380
media/libvpx/vp9/encoder/vp9_variance.c
Normal file
380
media/libvpx/vp9/encoder/vp9_variance.c
Normal 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
|
||||
81
media/libvpx/vp9/encoder/vp9_variance.h
Normal file
81
media/libvpx/vp9/encoder/vp9_variance.h
Normal 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_
|
||||
35
media/libvpx/vp9/encoder/vp9_write_bit_buffer.c
Normal file
35
media/libvpx/vp9/encoder/vp9_write_bit_buffer.c
Normal 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);
|
||||
}
|
||||
36
media/libvpx/vp9/encoder/vp9_write_bit_buffer.h
Normal file
36
media/libvpx/vp9/encoder/vp9_write_bit_buffer.h
Normal 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_
|
||||
34
media/libvpx/vp9/encoder/vp9_writer.c
Normal file
34
media/libvpx/vp9/encoder/vp9_writer.c
Normal 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;
|
||||
}
|
||||
|
||||
98
media/libvpx/vp9/encoder/vp9_writer.h
Normal file
98
media/libvpx/vp9/encoder/vp9_writer.h
Normal 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_
|
||||
423
media/libvpx/vp9/encoder/x86/vp9_avg_intrin_sse2.c
Normal file
423
media/libvpx/vp9/encoder/x86/vp9_avg_intrin_sse2.c
Normal 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));
|
||||
}
|
||||
2713
media/libvpx/vp9/encoder/x86/vp9_dct32x32_avx2_impl.h
Normal file
2713
media/libvpx/vp9/encoder/x86/vp9_dct32x32_avx2_impl.h
Normal file
File diff suppressed because it is too large
Load diff
3151
media/libvpx/vp9/encoder/x86/vp9_dct32x32_sse2_impl.h
Normal file
3151
media/libvpx/vp9/encoder/x86/vp9_dct32x32_sse2_impl.h
Normal file
File diff suppressed because it is too large
Load diff
26
media/libvpx/vp9/encoder/x86/vp9_dct_avx2.c
Normal file
26
media/libvpx/vp9/encoder/x86/vp9_dct_avx2.c
Normal 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
|
||||
101
media/libvpx/vp9/encoder/x86/vp9_dct_mmx.asm
Normal file
101
media/libvpx/vp9/encoder/x86/vp9_dct_mmx.asm
Normal 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
|
||||
2429
media/libvpx/vp9/encoder/x86/vp9_dct_sse2.c
Normal file
2429
media/libvpx/vp9/encoder/x86/vp9_dct_sse2.c
Normal file
File diff suppressed because it is too large
Load diff
464
media/libvpx/vp9/encoder/x86/vp9_dct_sse2.h
Normal file
464
media/libvpx/vp9/encoder/x86/vp9_dct_sse2.h
Normal 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_
|
||||
1024
media/libvpx/vp9/encoder/x86/vp9_dct_sse2_impl.h
Normal file
1024
media/libvpx/vp9/encoder/x86/vp9_dct_sse2_impl.h
Normal file
File diff suppressed because it is too large
Load diff
471
media/libvpx/vp9/encoder/x86/vp9_dct_ssse3.c
Normal file
471
media/libvpx/vp9/encoder/x86/vp9_dct_ssse3.c
Normal 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;
|
||||
}
|
||||
}
|
||||
255
media/libvpx/vp9/encoder/x86/vp9_dct_ssse3_x86_64.asm
Normal file
255
media/libvpx/vp9/encoder/x86/vp9_dct_ssse3_x86_64.asm
Normal 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
|
||||
375
media/libvpx/vp9/encoder/x86/vp9_denoiser_sse2.c
Normal file
375
media/libvpx/vp9/encoder/x86/vp9_denoiser_sse2.c
Normal 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;
|
||||
}
|
||||
}
|
||||
73
media/libvpx/vp9/encoder/x86/vp9_error_intrin_avx2.c
Normal file
73
media/libvpx/vp9/encoder/x86/vp9_error_intrin_avx2.c
Normal 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;
|
||||
}
|
||||
120
media/libvpx/vp9/encoder/x86/vp9_error_sse2.asm
Normal file
120
media/libvpx/vp9/encoder/x86/vp9_error_sse2.asm
Normal 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
|
||||
|
|
@ -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;
|
||||
}
|
||||
181
media/libvpx/vp9/encoder/x86/vp9_highbd_quantize_intrin_sse2.c
Normal file
181
media/libvpx/vp9/encoder/x86/vp9_highbd_quantize_intrin_sse2.c
Normal 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
|
||||
1039
media/libvpx/vp9/encoder/x86/vp9_highbd_subpel_variance.asm
Normal file
1039
media/libvpx/vp9/encoder/x86/vp9_highbd_subpel_variance.asm
Normal file
File diff suppressed because it is too large
Load diff
349
media/libvpx/vp9/encoder/x86/vp9_highbd_variance_sse2.c
Normal file
349
media/libvpx/vp9/encoder/x86/vp9_highbd_variance_sse2.c
Normal 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
Loading…
Add table
Add a link
Reference in a new issue