(61d00a474) v0.9.7.1
This commit is contained in:
+446
@@ -0,0 +1,446 @@
|
||||
/*
|
||||
* Copyright (c) 2018 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 "./vpx_dsp_rtcd.h"
|
||||
#include "vp9/common/vp9_enums.h"
|
||||
#include "vp9/common/arm/neon/vp9_iht_neon.h"
|
||||
#include "vpx_dsp/arm/highbd_idct_neon.h"
|
||||
#include "vpx_dsp/arm/idct_neon.h"
|
||||
#include "vpx_dsp/arm/transpose_neon.h"
|
||||
#include "vpx_dsp/inv_txfm.h"
|
||||
|
||||
// Use macros to make sure argument lane is passed in as an constant integer.
|
||||
|
||||
#define vmull_lane_s32_dual(in, c, lane, out) \
|
||||
do { \
|
||||
out[0].val[0] = vmull_lane_s32(vget_low_s32(in.val[0]), c, lane); \
|
||||
out[0].val[1] = vmull_lane_s32(vget_low_s32(in.val[1]), c, lane); \
|
||||
out[1].val[0] = vmull_lane_s32(vget_high_s32(in.val[0]), c, lane); \
|
||||
out[1].val[1] = vmull_lane_s32(vget_high_s32(in.val[1]), c, lane); \
|
||||
} while (0)
|
||||
|
||||
#define vmlal_lane_s32_dual(in, c, lane, out) \
|
||||
do { \
|
||||
out[0].val[0] = \
|
||||
vmlal_lane_s32(out[0].val[0], vget_low_s32(in.val[0]), c, lane); \
|
||||
out[0].val[1] = \
|
||||
vmlal_lane_s32(out[0].val[1], vget_low_s32(in.val[1]), c, lane); \
|
||||
out[1].val[0] = \
|
||||
vmlal_lane_s32(out[1].val[0], vget_high_s32(in.val[0]), c, lane); \
|
||||
out[1].val[1] = \
|
||||
vmlal_lane_s32(out[1].val[1], vget_high_s32(in.val[1]), c, lane); \
|
||||
} while (0)
|
||||
|
||||
#define vmlsl_lane_s32_dual(in, c, lane, out) \
|
||||
do { \
|
||||
out[0].val[0] = \
|
||||
vmlsl_lane_s32(out[0].val[0], vget_low_s32(in.val[0]), c, lane); \
|
||||
out[0].val[1] = \
|
||||
vmlsl_lane_s32(out[0].val[1], vget_low_s32(in.val[1]), c, lane); \
|
||||
out[1].val[0] = \
|
||||
vmlsl_lane_s32(out[1].val[0], vget_high_s32(in.val[0]), c, lane); \
|
||||
out[1].val[1] = \
|
||||
vmlsl_lane_s32(out[1].val[1], vget_high_s32(in.val[1]), c, lane); \
|
||||
} while (0)
|
||||
|
||||
static INLINE int32x4x2_t
|
||||
highbd_dct_const_round_shift_low_8(const int64x2x2_t *const in) {
|
||||
int32x4x2_t out;
|
||||
out.val[0] = vcombine_s32(vrshrn_n_s64(in[0].val[0], DCT_CONST_BITS),
|
||||
vrshrn_n_s64(in[1].val[0], DCT_CONST_BITS));
|
||||
out.val[1] = vcombine_s32(vrshrn_n_s64(in[0].val[1], DCT_CONST_BITS),
|
||||
vrshrn_n_s64(in[1].val[1], DCT_CONST_BITS));
|
||||
return out;
|
||||
}
|
||||
|
||||
#define highbd_iadst_half_butterfly(in, c, lane, out) \
|
||||
do { \
|
||||
int64x2x2_t t[2]; \
|
||||
vmull_lane_s32_dual(in, c, lane, t); \
|
||||
out = highbd_dct_const_round_shift_low_8(t); \
|
||||
} while (0)
|
||||
|
||||
#define highbd_iadst_butterfly(in0, in1, c, lane0, lane1, s0, s1) \
|
||||
do { \
|
||||
vmull_lane_s32_dual(in0, c, lane0, s0); \
|
||||
vmull_lane_s32_dual(in0, c, lane1, s1); \
|
||||
vmlal_lane_s32_dual(in1, c, lane1, s0); \
|
||||
vmlsl_lane_s32_dual(in1, c, lane0, s1); \
|
||||
} while (0)
|
||||
|
||||
static INLINE int32x4x2_t vaddq_s32_dual(const int32x4x2_t in0,
|
||||
const int32x4x2_t in1) {
|
||||
int32x4x2_t out;
|
||||
out.val[0] = vaddq_s32(in0.val[0], in1.val[0]);
|
||||
out.val[1] = vaddq_s32(in0.val[1], in1.val[1]);
|
||||
return out;
|
||||
}
|
||||
|
||||
static INLINE int64x2x2_t vaddq_s64_dual(const int64x2x2_t in0,
|
||||
const int64x2x2_t in1) {
|
||||
int64x2x2_t out;
|
||||
out.val[0] = vaddq_s64(in0.val[0], in1.val[0]);
|
||||
out.val[1] = vaddq_s64(in0.val[1], in1.val[1]);
|
||||
return out;
|
||||
}
|
||||
|
||||
static INLINE int32x4x2_t vsubq_s32_dual(const int32x4x2_t in0,
|
||||
const int32x4x2_t in1) {
|
||||
int32x4x2_t out;
|
||||
out.val[0] = vsubq_s32(in0.val[0], in1.val[0]);
|
||||
out.val[1] = vsubq_s32(in0.val[1], in1.val[1]);
|
||||
return out;
|
||||
}
|
||||
|
||||
static INLINE int64x2x2_t vsubq_s64_dual(const int64x2x2_t in0,
|
||||
const int64x2x2_t in1) {
|
||||
int64x2x2_t out;
|
||||
out.val[0] = vsubq_s64(in0.val[0], in1.val[0]);
|
||||
out.val[1] = vsubq_s64(in0.val[1], in1.val[1]);
|
||||
return out;
|
||||
}
|
||||
|
||||
static INLINE int32x4x2_t vcombine_s32_dual(const int32x2x2_t in0,
|
||||
const int32x2x2_t in1) {
|
||||
int32x4x2_t out;
|
||||
out.val[0] = vcombine_s32(in0.val[0], in1.val[0]);
|
||||
out.val[1] = vcombine_s32(in0.val[1], in1.val[1]);
|
||||
return out;
|
||||
}
|
||||
|
||||
static INLINE int32x4x2_t highbd_add_dct_const_round_shift_low_8(
|
||||
const int64x2x2_t *const in0, const int64x2x2_t *const in1) {
|
||||
const int64x2x2_t sum_lo = vaddq_s64_dual(in0[0], in1[0]);
|
||||
const int64x2x2_t sum_hi = vaddq_s64_dual(in0[1], in1[1]);
|
||||
int32x2x2_t out_lo, out_hi;
|
||||
|
||||
out_lo.val[0] = vrshrn_n_s64(sum_lo.val[0], DCT_CONST_BITS);
|
||||
out_lo.val[1] = vrshrn_n_s64(sum_lo.val[1], DCT_CONST_BITS);
|
||||
out_hi.val[0] = vrshrn_n_s64(sum_hi.val[0], DCT_CONST_BITS);
|
||||
out_hi.val[1] = vrshrn_n_s64(sum_hi.val[1], DCT_CONST_BITS);
|
||||
return vcombine_s32_dual(out_lo, out_hi);
|
||||
}
|
||||
|
||||
static INLINE int32x4x2_t highbd_sub_dct_const_round_shift_low_8(
|
||||
const int64x2x2_t *const in0, const int64x2x2_t *const in1) {
|
||||
const int64x2x2_t sub_lo = vsubq_s64_dual(in0[0], in1[0]);
|
||||
const int64x2x2_t sub_hi = vsubq_s64_dual(in0[1], in1[1]);
|
||||
int32x2x2_t out_lo, out_hi;
|
||||
|
||||
out_lo.val[0] = vrshrn_n_s64(sub_lo.val[0], DCT_CONST_BITS);
|
||||
out_lo.val[1] = vrshrn_n_s64(sub_lo.val[1], DCT_CONST_BITS);
|
||||
out_hi.val[0] = vrshrn_n_s64(sub_hi.val[0], DCT_CONST_BITS);
|
||||
out_hi.val[1] = vrshrn_n_s64(sub_hi.val[1], DCT_CONST_BITS);
|
||||
return vcombine_s32_dual(out_lo, out_hi);
|
||||
}
|
||||
|
||||
static INLINE int32x4x2_t vnegq_s32_dual(const int32x4x2_t in) {
|
||||
int32x4x2_t out;
|
||||
out.val[0] = vnegq_s32(in.val[0]);
|
||||
out.val[1] = vnegq_s32(in.val[1]);
|
||||
return out;
|
||||
}
|
||||
|
||||
static void highbd_iadst16_neon(const int32_t *input, int32_t *output,
|
||||
uint16_t *dest, const int stride,
|
||||
const int bd) {
|
||||
const int32x4_t c_1_31_5_27 =
|
||||
create_s32x4_neon(cospi_1_64, cospi_31_64, cospi_5_64, cospi_27_64);
|
||||
const int32x4_t c_9_23_13_19 =
|
||||
create_s32x4_neon(cospi_9_64, cospi_23_64, cospi_13_64, cospi_19_64);
|
||||
const int32x4_t c_17_15_21_11 =
|
||||
create_s32x4_neon(cospi_17_64, cospi_15_64, cospi_21_64, cospi_11_64);
|
||||
const int32x4_t c_25_7_29_3 =
|
||||
create_s32x4_neon(cospi_25_64, cospi_7_64, cospi_29_64, cospi_3_64);
|
||||
const int32x4_t c_4_28_20_12 =
|
||||
create_s32x4_neon(cospi_4_64, cospi_28_64, cospi_20_64, cospi_12_64);
|
||||
const int32x4_t c_16_n16_8_24 =
|
||||
create_s32x4_neon(cospi_16_64, -cospi_16_64, cospi_8_64, cospi_24_64);
|
||||
int32x4x2_t in[16], out[16];
|
||||
int32x4x2_t x[16], t[12];
|
||||
int64x2x2_t s0[2], s1[2], s2[2], s3[2], s4[2], s5[2], s6[2], s7[2];
|
||||
int64x2x2_t s8[2], s9[2], s10[2], s11[2], s12[2], s13[2], s14[2], s15[2];
|
||||
|
||||
// Load input (16x8)
|
||||
in[0].val[0] = vld1q_s32(input);
|
||||
in[0].val[1] = vld1q_s32(input + 4);
|
||||
input += 8;
|
||||
in[8].val[0] = vld1q_s32(input);
|
||||
in[8].val[1] = vld1q_s32(input + 4);
|
||||
input += 8;
|
||||
in[1].val[0] = vld1q_s32(input);
|
||||
in[1].val[1] = vld1q_s32(input + 4);
|
||||
input += 8;
|
||||
in[9].val[0] = vld1q_s32(input);
|
||||
in[9].val[1] = vld1q_s32(input + 4);
|
||||
input += 8;
|
||||
in[2].val[0] = vld1q_s32(input);
|
||||
in[2].val[1] = vld1q_s32(input + 4);
|
||||
input += 8;
|
||||
in[10].val[0] = vld1q_s32(input);
|
||||
in[10].val[1] = vld1q_s32(input + 4);
|
||||
input += 8;
|
||||
in[3].val[0] = vld1q_s32(input);
|
||||
in[3].val[1] = vld1q_s32(input + 4);
|
||||
input += 8;
|
||||
in[11].val[0] = vld1q_s32(input);
|
||||
in[11].val[1] = vld1q_s32(input + 4);
|
||||
input += 8;
|
||||
in[4].val[0] = vld1q_s32(input);
|
||||
in[4].val[1] = vld1q_s32(input + 4);
|
||||
input += 8;
|
||||
in[12].val[0] = vld1q_s32(input);
|
||||
in[12].val[1] = vld1q_s32(input + 4);
|
||||
input += 8;
|
||||
in[5].val[0] = vld1q_s32(input);
|
||||
in[5].val[1] = vld1q_s32(input + 4);
|
||||
input += 8;
|
||||
in[13].val[0] = vld1q_s32(input);
|
||||
in[13].val[1] = vld1q_s32(input + 4);
|
||||
input += 8;
|
||||
in[6].val[0] = vld1q_s32(input);
|
||||
in[6].val[1] = vld1q_s32(input + 4);
|
||||
input += 8;
|
||||
in[14].val[0] = vld1q_s32(input);
|
||||
in[14].val[1] = vld1q_s32(input + 4);
|
||||
input += 8;
|
||||
in[7].val[0] = vld1q_s32(input);
|
||||
in[7].val[1] = vld1q_s32(input + 4);
|
||||
input += 8;
|
||||
in[15].val[0] = vld1q_s32(input);
|
||||
in[15].val[1] = vld1q_s32(input + 4);
|
||||
|
||||
// Transpose
|
||||
transpose_s32_8x8(&in[0], &in[1], &in[2], &in[3], &in[4], &in[5], &in[6],
|
||||
&in[7]);
|
||||
transpose_s32_8x8(&in[8], &in[9], &in[10], &in[11], &in[12], &in[13], &in[14],
|
||||
&in[15]);
|
||||
|
||||
x[0] = in[15];
|
||||
x[1] = in[0];
|
||||
x[2] = in[13];
|
||||
x[3] = in[2];
|
||||
x[4] = in[11];
|
||||
x[5] = in[4];
|
||||
x[6] = in[9];
|
||||
x[7] = in[6];
|
||||
x[8] = in[7];
|
||||
x[9] = in[8];
|
||||
x[10] = in[5];
|
||||
x[11] = in[10];
|
||||
x[12] = in[3];
|
||||
x[13] = in[12];
|
||||
x[14] = in[1];
|
||||
x[15] = in[14];
|
||||
|
||||
// stage 1
|
||||
highbd_iadst_butterfly(x[0], x[1], vget_low_s32(c_1_31_5_27), 0, 1, s0, s1);
|
||||
highbd_iadst_butterfly(x[2], x[3], vget_high_s32(c_1_31_5_27), 0, 1, s2, s3);
|
||||
highbd_iadst_butterfly(x[4], x[5], vget_low_s32(c_9_23_13_19), 0, 1, s4, s5);
|
||||
highbd_iadst_butterfly(x[6], x[7], vget_high_s32(c_9_23_13_19), 0, 1, s6, s7);
|
||||
highbd_iadst_butterfly(x[8], x[9], vget_low_s32(c_17_15_21_11), 0, 1, s8, s9);
|
||||
highbd_iadst_butterfly(x[10], x[11], vget_high_s32(c_17_15_21_11), 0, 1, s10,
|
||||
s11);
|
||||
highbd_iadst_butterfly(x[12], x[13], vget_low_s32(c_25_7_29_3), 0, 1, s12,
|
||||
s13);
|
||||
highbd_iadst_butterfly(x[14], x[15], vget_high_s32(c_25_7_29_3), 0, 1, s14,
|
||||
s15);
|
||||
|
||||
x[0] = highbd_add_dct_const_round_shift_low_8(s0, s8);
|
||||
x[1] = highbd_add_dct_const_round_shift_low_8(s1, s9);
|
||||
x[2] = highbd_add_dct_const_round_shift_low_8(s2, s10);
|
||||
x[3] = highbd_add_dct_const_round_shift_low_8(s3, s11);
|
||||
x[4] = highbd_add_dct_const_round_shift_low_8(s4, s12);
|
||||
x[5] = highbd_add_dct_const_round_shift_low_8(s5, s13);
|
||||
x[6] = highbd_add_dct_const_round_shift_low_8(s6, s14);
|
||||
x[7] = highbd_add_dct_const_round_shift_low_8(s7, s15);
|
||||
x[8] = highbd_sub_dct_const_round_shift_low_8(s0, s8);
|
||||
x[9] = highbd_sub_dct_const_round_shift_low_8(s1, s9);
|
||||
x[10] = highbd_sub_dct_const_round_shift_low_8(s2, s10);
|
||||
x[11] = highbd_sub_dct_const_round_shift_low_8(s3, s11);
|
||||
x[12] = highbd_sub_dct_const_round_shift_low_8(s4, s12);
|
||||
x[13] = highbd_sub_dct_const_round_shift_low_8(s5, s13);
|
||||
x[14] = highbd_sub_dct_const_round_shift_low_8(s6, s14);
|
||||
x[15] = highbd_sub_dct_const_round_shift_low_8(s7, s15);
|
||||
|
||||
// stage 2
|
||||
t[0] = x[0];
|
||||
t[1] = x[1];
|
||||
t[2] = x[2];
|
||||
t[3] = x[3];
|
||||
t[4] = x[4];
|
||||
t[5] = x[5];
|
||||
t[6] = x[6];
|
||||
t[7] = x[7];
|
||||
highbd_iadst_butterfly(x[8], x[9], vget_low_s32(c_4_28_20_12), 0, 1, s8, s9);
|
||||
highbd_iadst_butterfly(x[10], x[11], vget_high_s32(c_4_28_20_12), 0, 1, s10,
|
||||
s11);
|
||||
highbd_iadst_butterfly(x[13], x[12], vget_low_s32(c_4_28_20_12), 1, 0, s13,
|
||||
s12);
|
||||
highbd_iadst_butterfly(x[15], x[14], vget_high_s32(c_4_28_20_12), 1, 0, s15,
|
||||
s14);
|
||||
|
||||
x[0] = vaddq_s32_dual(t[0], t[4]);
|
||||
x[1] = vaddq_s32_dual(t[1], t[5]);
|
||||
x[2] = vaddq_s32_dual(t[2], t[6]);
|
||||
x[3] = vaddq_s32_dual(t[3], t[7]);
|
||||
x[4] = vsubq_s32_dual(t[0], t[4]);
|
||||
x[5] = vsubq_s32_dual(t[1], t[5]);
|
||||
x[6] = vsubq_s32_dual(t[2], t[6]);
|
||||
x[7] = vsubq_s32_dual(t[3], t[7]);
|
||||
x[8] = highbd_add_dct_const_round_shift_low_8(s8, s12);
|
||||
x[9] = highbd_add_dct_const_round_shift_low_8(s9, s13);
|
||||
x[10] = highbd_add_dct_const_round_shift_low_8(s10, s14);
|
||||
x[11] = highbd_add_dct_const_round_shift_low_8(s11, s15);
|
||||
x[12] = highbd_sub_dct_const_round_shift_low_8(s8, s12);
|
||||
x[13] = highbd_sub_dct_const_round_shift_low_8(s9, s13);
|
||||
x[14] = highbd_sub_dct_const_round_shift_low_8(s10, s14);
|
||||
x[15] = highbd_sub_dct_const_round_shift_low_8(s11, s15);
|
||||
|
||||
// stage 3
|
||||
t[0] = x[0];
|
||||
t[1] = x[1];
|
||||
t[2] = x[2];
|
||||
t[3] = x[3];
|
||||
highbd_iadst_butterfly(x[4], x[5], vget_high_s32(c_16_n16_8_24), 0, 1, s4,
|
||||
s5);
|
||||
highbd_iadst_butterfly(x[7], x[6], vget_high_s32(c_16_n16_8_24), 1, 0, s7,
|
||||
s6);
|
||||
t[8] = x[8];
|
||||
t[9] = x[9];
|
||||
t[10] = x[10];
|
||||
t[11] = x[11];
|
||||
highbd_iadst_butterfly(x[12], x[13], vget_high_s32(c_16_n16_8_24), 0, 1, s12,
|
||||
s13);
|
||||
highbd_iadst_butterfly(x[15], x[14], vget_high_s32(c_16_n16_8_24), 1, 0, s15,
|
||||
s14);
|
||||
|
||||
x[0] = vaddq_s32_dual(t[0], t[2]);
|
||||
x[1] = vaddq_s32_dual(t[1], t[3]);
|
||||
x[2] = vsubq_s32_dual(t[0], t[2]);
|
||||
x[3] = vsubq_s32_dual(t[1], t[3]);
|
||||
x[4] = highbd_add_dct_const_round_shift_low_8(s4, s6);
|
||||
x[5] = highbd_add_dct_const_round_shift_low_8(s5, s7);
|
||||
x[6] = highbd_sub_dct_const_round_shift_low_8(s4, s6);
|
||||
x[7] = highbd_sub_dct_const_round_shift_low_8(s5, s7);
|
||||
x[8] = vaddq_s32_dual(t[8], t[10]);
|
||||
x[9] = vaddq_s32_dual(t[9], t[11]);
|
||||
x[10] = vsubq_s32_dual(t[8], t[10]);
|
||||
x[11] = vsubq_s32_dual(t[9], t[11]);
|
||||
x[12] = highbd_add_dct_const_round_shift_low_8(s12, s14);
|
||||
x[13] = highbd_add_dct_const_round_shift_low_8(s13, s15);
|
||||
x[14] = highbd_sub_dct_const_round_shift_low_8(s12, s14);
|
||||
x[15] = highbd_sub_dct_const_round_shift_low_8(s13, s15);
|
||||
|
||||
// stage 4
|
||||
{
|
||||
const int32x4x2_t sum = vaddq_s32_dual(x[2], x[3]);
|
||||
const int32x4x2_t sub = vsubq_s32_dual(x[2], x[3]);
|
||||
highbd_iadst_half_butterfly(sum, vget_low_s32(c_16_n16_8_24), 1, x[2]);
|
||||
highbd_iadst_half_butterfly(sub, vget_low_s32(c_16_n16_8_24), 0, x[3]);
|
||||
}
|
||||
{
|
||||
const int32x4x2_t sum = vaddq_s32_dual(x[7], x[6]);
|
||||
const int32x4x2_t sub = vsubq_s32_dual(x[7], x[6]);
|
||||
highbd_iadst_half_butterfly(sum, vget_low_s32(c_16_n16_8_24), 0, x[6]);
|
||||
highbd_iadst_half_butterfly(sub, vget_low_s32(c_16_n16_8_24), 0, x[7]);
|
||||
}
|
||||
{
|
||||
const int32x4x2_t sum = vaddq_s32_dual(x[11], x[10]);
|
||||
const int32x4x2_t sub = vsubq_s32_dual(x[11], x[10]);
|
||||
highbd_iadst_half_butterfly(sum, vget_low_s32(c_16_n16_8_24), 0, x[10]);
|
||||
highbd_iadst_half_butterfly(sub, vget_low_s32(c_16_n16_8_24), 0, x[11]);
|
||||
}
|
||||
{
|
||||
const int32x4x2_t sum = vaddq_s32_dual(x[14], x[15]);
|
||||
const int32x4x2_t sub = vsubq_s32_dual(x[14], x[15]);
|
||||
highbd_iadst_half_butterfly(sum, vget_low_s32(c_16_n16_8_24), 1, x[14]);
|
||||
highbd_iadst_half_butterfly(sub, vget_low_s32(c_16_n16_8_24), 0, x[15]);
|
||||
}
|
||||
|
||||
out[0] = x[0];
|
||||
out[1] = vnegq_s32_dual(x[8]);
|
||||
out[2] = x[12];
|
||||
out[3] = vnegq_s32_dual(x[4]);
|
||||
out[4] = x[6];
|
||||
out[5] = x[14];
|
||||
out[6] = x[10];
|
||||
out[7] = x[2];
|
||||
out[8] = x[3];
|
||||
out[9] = x[11];
|
||||
out[10] = x[15];
|
||||
out[11] = x[7];
|
||||
out[12] = x[5];
|
||||
out[13] = vnegq_s32_dual(x[13]);
|
||||
out[14] = x[9];
|
||||
out[15] = vnegq_s32_dual(x[1]);
|
||||
|
||||
if (output) {
|
||||
highbd_idct16x16_store_pass1(out, output);
|
||||
} else {
|
||||
highbd_idct16x16_add_store(out, dest, stride, bd);
|
||||
}
|
||||
}
|
||||
|
||||
typedef void (*highbd_iht_1d)(const int32_t *input, int32_t *output,
|
||||
uint16_t *dest, const int stride, const int bd);
|
||||
|
||||
typedef struct {
|
||||
highbd_iht_1d cols, rows; // vertical and horizontal
|
||||
} highbd_iht_2d;
|
||||
|
||||
void vp9_highbd_iht16x16_256_add_neon(const tran_low_t *input, uint16_t *dest,
|
||||
int stride, int tx_type, int bd) {
|
||||
if (bd == 8) {
|
||||
static const iht_2d IHT_16[] = {
|
||||
{ vpx_idct16x16_256_add_half1d,
|
||||
vpx_idct16x16_256_add_half1d }, // DCT_DCT = 0
|
||||
{ vpx_iadst16x16_256_add_half1d,
|
||||
vpx_idct16x16_256_add_half1d }, // ADST_DCT = 1
|
||||
{ vpx_idct16x16_256_add_half1d,
|
||||
vpx_iadst16x16_256_add_half1d }, // DCT_ADST = 2
|
||||
{ vpx_iadst16x16_256_add_half1d,
|
||||
vpx_iadst16x16_256_add_half1d } // ADST_ADST = 3
|
||||
};
|
||||
const iht_2d ht = IHT_16[tx_type];
|
||||
int16_t row_output[16 * 16];
|
||||
|
||||
// pass 1
|
||||
ht.rows(input, row_output, dest, stride, 1); // upper 8 rows
|
||||
ht.rows(input + 8 * 16, row_output + 8, dest, stride, 1); // lower 8 rows
|
||||
|
||||
// pass 2
|
||||
ht.cols(row_output, NULL, dest, stride, 1); // left 8 columns
|
||||
ht.cols(row_output + 16 * 8, NULL, dest + 8, stride, 1); // right 8 columns
|
||||
} else {
|
||||
static const highbd_iht_2d IHT_16[] = {
|
||||
{ vpx_highbd_idct16x16_256_add_half1d,
|
||||
vpx_highbd_idct16x16_256_add_half1d }, // DCT_DCT = 0
|
||||
{ highbd_iadst16_neon,
|
||||
vpx_highbd_idct16x16_256_add_half1d }, // ADST_DCT = 1
|
||||
{ vpx_highbd_idct16x16_256_add_half1d,
|
||||
highbd_iadst16_neon }, // DCT_ADST = 2
|
||||
{ highbd_iadst16_neon, highbd_iadst16_neon } // ADST_ADST = 3
|
||||
};
|
||||
const highbd_iht_2d ht = IHT_16[tx_type];
|
||||
int32_t row_output[16 * 16];
|
||||
|
||||
// pass 1
|
||||
ht.rows(input, row_output, dest, stride, bd); // upper 8 rows
|
||||
ht.rows(input + 8 * 16, row_output + 8, dest, stride, bd); // lower 8 rows
|
||||
|
||||
// pass 2
|
||||
ht.cols(row_output, NULL, dest, stride, bd); // left 8 columns
|
||||
ht.cols(row_output + 8 * 16, NULL, dest + 8, stride,
|
||||
bd); // right 8 columns
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
* Copyright (c) 2018 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 <assert.h>
|
||||
|
||||
#include "./vp9_rtcd.h"
|
||||
#include "./vpx_config.h"
|
||||
#include "vp9/common/vp9_common.h"
|
||||
#include "vp9/common/arm/neon/vp9_iht_neon.h"
|
||||
#include "vpx_dsp/arm/highbd_idct_neon.h"
|
||||
#include "vpx_dsp/arm/idct_neon.h"
|
||||
#include "vpx_dsp/arm/mem_neon.h"
|
||||
#include "vpx_dsp/txfm_common.h"
|
||||
|
||||
static INLINE void highbd_iadst4(int32x4_t *const io) {
|
||||
const int32_t sinpis[4] = { sinpi_1_9, sinpi_2_9, sinpi_3_9, sinpi_4_9 };
|
||||
const int32x4_t sinpi = vld1q_s32(sinpis);
|
||||
int64x2x2_t s[7], t[4];
|
||||
int32x4_t s7;
|
||||
|
||||
s[0].val[0] = vmull_lane_s32(vget_low_s32(io[0]), vget_low_s32(sinpi), 0);
|
||||
s[0].val[1] = vmull_lane_s32(vget_high_s32(io[0]), vget_low_s32(sinpi), 0);
|
||||
s[1].val[0] = vmull_lane_s32(vget_low_s32(io[0]), vget_low_s32(sinpi), 1);
|
||||
s[1].val[1] = vmull_lane_s32(vget_high_s32(io[0]), vget_low_s32(sinpi), 1);
|
||||
s[2].val[0] = vmull_lane_s32(vget_low_s32(io[1]), vget_high_s32(sinpi), 0);
|
||||
s[2].val[1] = vmull_lane_s32(vget_high_s32(io[1]), vget_high_s32(sinpi), 0);
|
||||
s[3].val[0] = vmull_lane_s32(vget_low_s32(io[2]), vget_high_s32(sinpi), 1);
|
||||
s[3].val[1] = vmull_lane_s32(vget_high_s32(io[2]), vget_high_s32(sinpi), 1);
|
||||
s[4].val[0] = vmull_lane_s32(vget_low_s32(io[2]), vget_low_s32(sinpi), 0);
|
||||
s[4].val[1] = vmull_lane_s32(vget_high_s32(io[2]), vget_low_s32(sinpi), 0);
|
||||
s[5].val[0] = vmull_lane_s32(vget_low_s32(io[3]), vget_low_s32(sinpi), 1);
|
||||
s[5].val[1] = vmull_lane_s32(vget_high_s32(io[3]), vget_low_s32(sinpi), 1);
|
||||
s[6].val[0] = vmull_lane_s32(vget_low_s32(io[3]), vget_high_s32(sinpi), 1);
|
||||
s[6].val[1] = vmull_lane_s32(vget_high_s32(io[3]), vget_high_s32(sinpi), 1);
|
||||
s7 = vsubq_s32(io[0], io[2]);
|
||||
s7 = vaddq_s32(s7, io[3]);
|
||||
|
||||
s[0].val[0] = vaddq_s64(s[0].val[0], s[3].val[0]);
|
||||
s[0].val[1] = vaddq_s64(s[0].val[1], s[3].val[1]);
|
||||
s[0].val[0] = vaddq_s64(s[0].val[0], s[5].val[0]);
|
||||
s[0].val[1] = vaddq_s64(s[0].val[1], s[5].val[1]);
|
||||
s[1].val[0] = vsubq_s64(s[1].val[0], s[4].val[0]);
|
||||
s[1].val[1] = vsubq_s64(s[1].val[1], s[4].val[1]);
|
||||
s[1].val[0] = vsubq_s64(s[1].val[0], s[6].val[0]);
|
||||
s[1].val[1] = vsubq_s64(s[1].val[1], s[6].val[1]);
|
||||
s[3] = s[2];
|
||||
s[2].val[0] = vmull_lane_s32(vget_low_s32(s7), vget_high_s32(sinpi), 0);
|
||||
s[2].val[1] = vmull_lane_s32(vget_high_s32(s7), vget_high_s32(sinpi), 0);
|
||||
|
||||
t[0].val[0] = vaddq_s64(s[0].val[0], s[3].val[0]);
|
||||
t[0].val[1] = vaddq_s64(s[0].val[1], s[3].val[1]);
|
||||
t[1].val[0] = vaddq_s64(s[1].val[0], s[3].val[0]);
|
||||
t[1].val[1] = vaddq_s64(s[1].val[1], s[3].val[1]);
|
||||
t[2] = s[2];
|
||||
t[3].val[0] = vaddq_s64(s[0].val[0], s[1].val[0]);
|
||||
t[3].val[1] = vaddq_s64(s[0].val[1], s[1].val[1]);
|
||||
t[3].val[0] = vsubq_s64(t[3].val[0], s[3].val[0]);
|
||||
t[3].val[1] = vsubq_s64(t[3].val[1], s[3].val[1]);
|
||||
io[0] = vcombine_s32(vrshrn_n_s64(t[0].val[0], DCT_CONST_BITS),
|
||||
vrshrn_n_s64(t[0].val[1], DCT_CONST_BITS));
|
||||
io[1] = vcombine_s32(vrshrn_n_s64(t[1].val[0], DCT_CONST_BITS),
|
||||
vrshrn_n_s64(t[1].val[1], DCT_CONST_BITS));
|
||||
io[2] = vcombine_s32(vrshrn_n_s64(t[2].val[0], DCT_CONST_BITS),
|
||||
vrshrn_n_s64(t[2].val[1], DCT_CONST_BITS));
|
||||
io[3] = vcombine_s32(vrshrn_n_s64(t[3].val[0], DCT_CONST_BITS),
|
||||
vrshrn_n_s64(t[3].val[1], DCT_CONST_BITS));
|
||||
}
|
||||
|
||||
void vp9_highbd_iht4x4_16_add_neon(const tran_low_t *input, uint16_t *dest,
|
||||
int stride, int tx_type, int bd) {
|
||||
const int16x8_t max = vdupq_n_s16((1 << bd) - 1);
|
||||
int16x8_t a[2];
|
||||
int32x4_t c[4];
|
||||
|
||||
c[0] = vld1q_s32(input);
|
||||
c[1] = vld1q_s32(input + 4);
|
||||
c[2] = vld1q_s32(input + 8);
|
||||
c[3] = vld1q_s32(input + 12);
|
||||
|
||||
if (bd == 8) {
|
||||
a[0] = vcombine_s16(vmovn_s32(c[0]), vmovn_s32(c[1]));
|
||||
a[1] = vcombine_s16(vmovn_s32(c[2]), vmovn_s32(c[3]));
|
||||
transpose_s16_4x4q(&a[0], &a[1]);
|
||||
|
||||
switch (tx_type) {
|
||||
case DCT_DCT:
|
||||
idct4x4_16_kernel_bd8(a);
|
||||
a[1] = vcombine_s16(vget_high_s16(a[1]), vget_low_s16(a[1]));
|
||||
transpose_s16_4x4q(&a[0], &a[1]);
|
||||
idct4x4_16_kernel_bd8(a);
|
||||
a[1] = vcombine_s16(vget_high_s16(a[1]), vget_low_s16(a[1]));
|
||||
break;
|
||||
|
||||
case ADST_DCT:
|
||||
idct4x4_16_kernel_bd8(a);
|
||||
a[1] = vcombine_s16(vget_high_s16(a[1]), vget_low_s16(a[1]));
|
||||
transpose_s16_4x4q(&a[0], &a[1]);
|
||||
iadst4(a);
|
||||
break;
|
||||
|
||||
case DCT_ADST:
|
||||
iadst4(a);
|
||||
transpose_s16_4x4q(&a[0], &a[1]);
|
||||
idct4x4_16_kernel_bd8(a);
|
||||
a[1] = vcombine_s16(vget_high_s16(a[1]), vget_low_s16(a[1]));
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(tx_type == ADST_ADST);
|
||||
iadst4(a);
|
||||
transpose_s16_4x4q(&a[0], &a[1]);
|
||||
iadst4(a);
|
||||
break;
|
||||
}
|
||||
a[0] = vrshrq_n_s16(a[0], 4);
|
||||
a[1] = vrshrq_n_s16(a[1], 4);
|
||||
} else {
|
||||
switch (tx_type) {
|
||||
case DCT_DCT: {
|
||||
const int32x4_t cospis = vld1q_s32(kCospi32);
|
||||
|
||||
if (bd == 10) {
|
||||
idct4x4_16_kernel_bd10(cospis, c);
|
||||
idct4x4_16_kernel_bd10(cospis, c);
|
||||
} else {
|
||||
idct4x4_16_kernel_bd12(cospis, c);
|
||||
idct4x4_16_kernel_bd12(cospis, c);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ADST_DCT: {
|
||||
const int32x4_t cospis = vld1q_s32(kCospi32);
|
||||
|
||||
if (bd == 10) {
|
||||
idct4x4_16_kernel_bd10(cospis, c);
|
||||
} else {
|
||||
idct4x4_16_kernel_bd12(cospis, c);
|
||||
}
|
||||
transpose_s32_4x4(&c[0], &c[1], &c[2], &c[3]);
|
||||
highbd_iadst4(c);
|
||||
break;
|
||||
}
|
||||
|
||||
case DCT_ADST: {
|
||||
const int32x4_t cospis = vld1q_s32(kCospi32);
|
||||
|
||||
transpose_s32_4x4(&c[0], &c[1], &c[2], &c[3]);
|
||||
highbd_iadst4(c);
|
||||
if (bd == 10) {
|
||||
idct4x4_16_kernel_bd10(cospis, c);
|
||||
} else {
|
||||
idct4x4_16_kernel_bd12(cospis, c);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
assert(tx_type == ADST_ADST);
|
||||
transpose_s32_4x4(&c[0], &c[1], &c[2], &c[3]);
|
||||
highbd_iadst4(c);
|
||||
transpose_s32_4x4(&c[0], &c[1], &c[2], &c[3]);
|
||||
highbd_iadst4(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
a[0] = vcombine_s16(vqrshrn_n_s32(c[0], 4), vqrshrn_n_s32(c[1], 4));
|
||||
a[1] = vcombine_s16(vqrshrn_n_s32(c[2], 4), vqrshrn_n_s32(c[3], 4));
|
||||
}
|
||||
|
||||
highbd_idct4x4_1_add_kernel1(&dest, stride, a[0], max);
|
||||
highbd_idct4x4_1_add_kernel1(&dest, stride, a[1], max);
|
||||
}
|
||||
@@ -0,0 +1,345 @@
|
||||
/*
|
||||
* Copyright (c) 2018 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 "./vpx_dsp_rtcd.h"
|
||||
#include "vp9/common/vp9_enums.h"
|
||||
#include "vp9/common/arm/neon/vp9_iht_neon.h"
|
||||
#include "vpx_dsp/arm/highbd_idct_neon.h"
|
||||
#include "vpx_dsp/arm/idct_neon.h"
|
||||
#include "vpx_dsp/arm/transpose_neon.h"
|
||||
#include "vpx_dsp/inv_txfm.h"
|
||||
|
||||
static INLINE void highbd_iadst_half_butterfly_neon(int32x4_t *const x,
|
||||
const int32x2_t c) {
|
||||
const int32x4_t sum = vaddq_s32(x[0], x[1]);
|
||||
const int32x4_t sub = vsubq_s32(x[0], x[1]);
|
||||
const int64x2_t t0_lo = vmull_lane_s32(vget_low_s32(sum), c, 0);
|
||||
const int64x2_t t1_lo = vmull_lane_s32(vget_low_s32(sub), c, 0);
|
||||
const int64x2_t t0_hi = vmull_lane_s32(vget_high_s32(sum), c, 0);
|
||||
const int64x2_t t1_hi = vmull_lane_s32(vget_high_s32(sub), c, 0);
|
||||
const int32x2_t out0_lo = vrshrn_n_s64(t0_lo, DCT_CONST_BITS);
|
||||
const int32x2_t out1_lo = vrshrn_n_s64(t1_lo, DCT_CONST_BITS);
|
||||
const int32x2_t out0_hi = vrshrn_n_s64(t0_hi, DCT_CONST_BITS);
|
||||
const int32x2_t out1_hi = vrshrn_n_s64(t1_hi, DCT_CONST_BITS);
|
||||
|
||||
x[0] = vcombine_s32(out0_lo, out0_hi);
|
||||
x[1] = vcombine_s32(out1_lo, out1_hi);
|
||||
}
|
||||
|
||||
static INLINE void highbd_iadst_butterfly_lane_0_1_neon(const int32x4_t in0,
|
||||
const int32x4_t in1,
|
||||
const int32x2_t c,
|
||||
int64x2_t *const s0,
|
||||
int64x2_t *const s1) {
|
||||
const int64x2_t t0_lo = vmull_lane_s32(vget_low_s32(in0), c, 0);
|
||||
const int64x2_t t1_lo = vmull_lane_s32(vget_low_s32(in0), c, 1);
|
||||
const int64x2_t t0_hi = vmull_lane_s32(vget_high_s32(in0), c, 0);
|
||||
const int64x2_t t1_hi = vmull_lane_s32(vget_high_s32(in0), c, 1);
|
||||
|
||||
s0[0] = vmlal_lane_s32(t0_lo, vget_low_s32(in1), c, 1);
|
||||
s1[0] = vmlsl_lane_s32(t1_lo, vget_low_s32(in1), c, 0);
|
||||
s0[1] = vmlal_lane_s32(t0_hi, vget_high_s32(in1), c, 1);
|
||||
s1[1] = vmlsl_lane_s32(t1_hi, vget_high_s32(in1), c, 0);
|
||||
}
|
||||
|
||||
static INLINE void highbd_iadst_butterfly_lane_1_0_neon(const int32x4_t in0,
|
||||
const int32x4_t in1,
|
||||
const int32x2_t c,
|
||||
int64x2_t *const s0,
|
||||
int64x2_t *const s1) {
|
||||
const int64x2_t t0_lo = vmull_lane_s32(vget_low_s32(in0), c, 1);
|
||||
const int64x2_t t1_lo = vmull_lane_s32(vget_low_s32(in0), c, 0);
|
||||
const int64x2_t t0_hi = vmull_lane_s32(vget_high_s32(in0), c, 1);
|
||||
const int64x2_t t1_hi = vmull_lane_s32(vget_high_s32(in0), c, 0);
|
||||
|
||||
s0[0] = vmlal_lane_s32(t0_lo, vget_low_s32(in1), c, 0);
|
||||
s1[0] = vmlsl_lane_s32(t1_lo, vget_low_s32(in1), c, 1);
|
||||
s0[1] = vmlal_lane_s32(t0_hi, vget_high_s32(in1), c, 0);
|
||||
s1[1] = vmlsl_lane_s32(t1_hi, vget_high_s32(in1), c, 1);
|
||||
}
|
||||
|
||||
static INLINE int32x4_t highbd_add_dct_const_round_shift_low_8(
|
||||
const int64x2_t *const in0, const int64x2_t *const in1) {
|
||||
const int64x2_t sum_lo = vaddq_s64(in0[0], in1[0]);
|
||||
const int64x2_t sum_hi = vaddq_s64(in0[1], in1[1]);
|
||||
const int32x2_t out_lo = vrshrn_n_s64(sum_lo, DCT_CONST_BITS);
|
||||
const int32x2_t out_hi = vrshrn_n_s64(sum_hi, DCT_CONST_BITS);
|
||||
return vcombine_s32(out_lo, out_hi);
|
||||
}
|
||||
|
||||
static INLINE int32x4_t highbd_sub_dct_const_round_shift_low_8(
|
||||
const int64x2_t *const in0, const int64x2_t *const in1) {
|
||||
const int64x2_t sub_lo = vsubq_s64(in0[0], in1[0]);
|
||||
const int64x2_t sub_hi = vsubq_s64(in0[1], in1[1]);
|
||||
const int32x2_t out_lo = vrshrn_n_s64(sub_lo, DCT_CONST_BITS);
|
||||
const int32x2_t out_hi = vrshrn_n_s64(sub_hi, DCT_CONST_BITS);
|
||||
return vcombine_s32(out_lo, out_hi);
|
||||
}
|
||||
|
||||
static INLINE void highbd_iadst8(int32x4_t *const io0, int32x4_t *const io1,
|
||||
int32x4_t *const io2, int32x4_t *const io3,
|
||||
int32x4_t *const io4, int32x4_t *const io5,
|
||||
int32x4_t *const io6, int32x4_t *const io7) {
|
||||
const int32x4_t c0 =
|
||||
create_s32x4_neon(cospi_2_64, cospi_30_64, cospi_10_64, cospi_22_64);
|
||||
const int32x4_t c1 =
|
||||
create_s32x4_neon(cospi_18_64, cospi_14_64, cospi_26_64, cospi_6_64);
|
||||
const int32x4_t c2 =
|
||||
create_s32x4_neon(cospi_16_64, 0, cospi_8_64, cospi_24_64);
|
||||
int32x4_t x[8], t[4];
|
||||
int64x2_t s[8][2];
|
||||
|
||||
x[0] = *io7;
|
||||
x[1] = *io0;
|
||||
x[2] = *io5;
|
||||
x[3] = *io2;
|
||||
x[4] = *io3;
|
||||
x[5] = *io4;
|
||||
x[6] = *io1;
|
||||
x[7] = *io6;
|
||||
|
||||
// stage 1
|
||||
highbd_iadst_butterfly_lane_0_1_neon(x[0], x[1], vget_low_s32(c0), s[0],
|
||||
s[1]);
|
||||
highbd_iadst_butterfly_lane_0_1_neon(x[2], x[3], vget_high_s32(c0), s[2],
|
||||
s[3]);
|
||||
highbd_iadst_butterfly_lane_0_1_neon(x[4], x[5], vget_low_s32(c1), s[4],
|
||||
s[5]);
|
||||
highbd_iadst_butterfly_lane_0_1_neon(x[6], x[7], vget_high_s32(c1), s[6],
|
||||
s[7]);
|
||||
|
||||
x[0] = highbd_add_dct_const_round_shift_low_8(s[0], s[4]);
|
||||
x[1] = highbd_add_dct_const_round_shift_low_8(s[1], s[5]);
|
||||
x[2] = highbd_add_dct_const_round_shift_low_8(s[2], s[6]);
|
||||
x[3] = highbd_add_dct_const_round_shift_low_8(s[3], s[7]);
|
||||
x[4] = highbd_sub_dct_const_round_shift_low_8(s[0], s[4]);
|
||||
x[5] = highbd_sub_dct_const_round_shift_low_8(s[1], s[5]);
|
||||
x[6] = highbd_sub_dct_const_round_shift_low_8(s[2], s[6]);
|
||||
x[7] = highbd_sub_dct_const_round_shift_low_8(s[3], s[7]);
|
||||
|
||||
// stage 2
|
||||
t[0] = x[0];
|
||||
t[1] = x[1];
|
||||
t[2] = x[2];
|
||||
t[3] = x[3];
|
||||
highbd_iadst_butterfly_lane_0_1_neon(x[4], x[5], vget_high_s32(c2), s[4],
|
||||
s[5]);
|
||||
highbd_iadst_butterfly_lane_1_0_neon(x[7], x[6], vget_high_s32(c2), s[7],
|
||||
s[6]);
|
||||
|
||||
x[0] = vaddq_s32(t[0], t[2]);
|
||||
x[1] = vaddq_s32(t[1], t[3]);
|
||||
x[2] = vsubq_s32(t[0], t[2]);
|
||||
x[3] = vsubq_s32(t[1], t[3]);
|
||||
x[4] = highbd_add_dct_const_round_shift_low_8(s[4], s[6]);
|
||||
x[5] = highbd_add_dct_const_round_shift_low_8(s[5], s[7]);
|
||||
x[6] = highbd_sub_dct_const_round_shift_low_8(s[4], s[6]);
|
||||
x[7] = highbd_sub_dct_const_round_shift_low_8(s[5], s[7]);
|
||||
|
||||
// stage 3
|
||||
highbd_iadst_half_butterfly_neon(x + 2, vget_low_s32(c2));
|
||||
highbd_iadst_half_butterfly_neon(x + 6, vget_low_s32(c2));
|
||||
|
||||
*io0 = x[0];
|
||||
*io1 = vnegq_s32(x[4]);
|
||||
*io2 = x[6];
|
||||
*io3 = vnegq_s32(x[2]);
|
||||
*io4 = x[3];
|
||||
*io5 = vnegq_s32(x[7]);
|
||||
*io6 = x[5];
|
||||
*io7 = vnegq_s32(x[1]);
|
||||
}
|
||||
|
||||
void vp9_highbd_iht8x8_64_add_neon(const tran_low_t *input, uint16_t *dest,
|
||||
int stride, int tx_type, int bd) {
|
||||
int32x4_t a[16];
|
||||
int16x8_t c[8];
|
||||
|
||||
a[0] = vld1q_s32(input);
|
||||
a[1] = vld1q_s32(input + 4);
|
||||
a[2] = vld1q_s32(input + 8);
|
||||
a[3] = vld1q_s32(input + 12);
|
||||
a[4] = vld1q_s32(input + 16);
|
||||
a[5] = vld1q_s32(input + 20);
|
||||
a[6] = vld1q_s32(input + 24);
|
||||
a[7] = vld1q_s32(input + 28);
|
||||
a[8] = vld1q_s32(input + 32);
|
||||
a[9] = vld1q_s32(input + 36);
|
||||
a[10] = vld1q_s32(input + 40);
|
||||
a[11] = vld1q_s32(input + 44);
|
||||
a[12] = vld1q_s32(input + 48);
|
||||
a[13] = vld1q_s32(input + 52);
|
||||
a[14] = vld1q_s32(input + 56);
|
||||
a[15] = vld1q_s32(input + 60);
|
||||
|
||||
if (bd == 8) {
|
||||
c[0] = vcombine_s16(vmovn_s32(a[0]), vmovn_s32(a[1]));
|
||||
c[1] = vcombine_s16(vmovn_s32(a[2]), vmovn_s32(a[3]));
|
||||
c[2] = vcombine_s16(vmovn_s32(a[4]), vmovn_s32(a[5]));
|
||||
c[3] = vcombine_s16(vmovn_s32(a[6]), vmovn_s32(a[7]));
|
||||
c[4] = vcombine_s16(vmovn_s32(a[8]), vmovn_s32(a[9]));
|
||||
c[5] = vcombine_s16(vmovn_s32(a[10]), vmovn_s32(a[11]));
|
||||
c[6] = vcombine_s16(vmovn_s32(a[12]), vmovn_s32(a[13]));
|
||||
c[7] = vcombine_s16(vmovn_s32(a[14]), vmovn_s32(a[15]));
|
||||
|
||||
switch (tx_type) {
|
||||
case DCT_DCT: {
|
||||
const int16x8_t cospis = vld1q_s16(kCospi);
|
||||
const int16x4_t cospis0 = vget_low_s16(cospis); // cospi 0, 8, 16, 24
|
||||
const int16x4_t cospis1 = vget_high_s16(cospis); // cospi 4, 12, 20, 28
|
||||
|
||||
idct8x8_64_1d_bd8(cospis0, cospis1, c);
|
||||
idct8x8_64_1d_bd8(cospis0, cospis1, c);
|
||||
break;
|
||||
}
|
||||
|
||||
case ADST_DCT: {
|
||||
const int16x8_t cospis = vld1q_s16(kCospi);
|
||||
const int16x4_t cospis0 = vget_low_s16(cospis); // cospi 0, 8, 16, 24
|
||||
const int16x4_t cospis1 = vget_high_s16(cospis); // cospi 4, 12, 20, 28
|
||||
|
||||
idct8x8_64_1d_bd8(cospis0, cospis1, c);
|
||||
transpose_s16_8x8(&c[0], &c[1], &c[2], &c[3], &c[4], &c[5], &c[6],
|
||||
&c[7]);
|
||||
iadst8(c);
|
||||
break;
|
||||
}
|
||||
|
||||
case DCT_ADST: {
|
||||
const int16x8_t cospis = vld1q_s16(kCospi);
|
||||
const int16x4_t cospis0 = vget_low_s16(cospis); // cospi 0, 8, 16, 24
|
||||
const int16x4_t cospis1 = vget_high_s16(cospis); // cospi 4, 12, 20, 28
|
||||
|
||||
transpose_s16_8x8(&c[0], &c[1], &c[2], &c[3], &c[4], &c[5], &c[6],
|
||||
&c[7]);
|
||||
iadst8(c);
|
||||
idct8x8_64_1d_bd8(cospis0, cospis1, c);
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
transpose_s16_8x8(&c[0], &c[1], &c[2], &c[3], &c[4], &c[5], &c[6],
|
||||
&c[7]);
|
||||
iadst8(c);
|
||||
transpose_s16_8x8(&c[0], &c[1], &c[2], &c[3], &c[4], &c[5], &c[6],
|
||||
&c[7]);
|
||||
iadst8(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
c[0] = vrshrq_n_s16(c[0], 5);
|
||||
c[1] = vrshrq_n_s16(c[1], 5);
|
||||
c[2] = vrshrq_n_s16(c[2], 5);
|
||||
c[3] = vrshrq_n_s16(c[3], 5);
|
||||
c[4] = vrshrq_n_s16(c[4], 5);
|
||||
c[5] = vrshrq_n_s16(c[5], 5);
|
||||
c[6] = vrshrq_n_s16(c[6], 5);
|
||||
c[7] = vrshrq_n_s16(c[7], 5);
|
||||
} else {
|
||||
switch (tx_type) {
|
||||
case DCT_DCT: {
|
||||
const int32x4_t cospis0 = vld1q_s32(kCospi32); // cospi 0, 8, 16, 24
|
||||
const int32x4_t cospis1 =
|
||||
vld1q_s32(kCospi32 + 4); // cospi 4, 12, 20, 28
|
||||
|
||||
if (bd == 10) {
|
||||
idct8x8_64_half1d_bd10(cospis0, cospis1, &a[0], &a[1], &a[2], &a[3],
|
||||
&a[4], &a[5], &a[6], &a[7]);
|
||||
idct8x8_64_half1d_bd10(cospis0, cospis1, &a[8], &a[9], &a[10], &a[11],
|
||||
&a[12], &a[13], &a[14], &a[15]);
|
||||
idct8x8_64_half1d_bd10(cospis0, cospis1, &a[0], &a[8], &a[1], &a[9],
|
||||
&a[2], &a[10], &a[3], &a[11]);
|
||||
idct8x8_64_half1d_bd10(cospis0, cospis1, &a[4], &a[12], &a[5], &a[13],
|
||||
&a[6], &a[14], &a[7], &a[15]);
|
||||
} else {
|
||||
idct8x8_64_half1d_bd12(cospis0, cospis1, &a[0], &a[1], &a[2], &a[3],
|
||||
&a[4], &a[5], &a[6], &a[7]);
|
||||
idct8x8_64_half1d_bd12(cospis0, cospis1, &a[8], &a[9], &a[10], &a[11],
|
||||
&a[12], &a[13], &a[14], &a[15]);
|
||||
idct8x8_64_half1d_bd12(cospis0, cospis1, &a[0], &a[8], &a[1], &a[9],
|
||||
&a[2], &a[10], &a[3], &a[11]);
|
||||
idct8x8_64_half1d_bd12(cospis0, cospis1, &a[4], &a[12], &a[5], &a[13],
|
||||
&a[6], &a[14], &a[7], &a[15]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ADST_DCT: {
|
||||
const int32x4_t cospis0 = vld1q_s32(kCospi32); // cospi 0, 8, 16, 24
|
||||
const int32x4_t cospis1 =
|
||||
vld1q_s32(kCospi32 + 4); // cospi 4, 12, 20, 28
|
||||
|
||||
idct8x8_64_half1d_bd12(cospis0, cospis1, &a[0], &a[1], &a[2], &a[3],
|
||||
&a[4], &a[5], &a[6], &a[7]);
|
||||
idct8x8_64_half1d_bd12(cospis0, cospis1, &a[8], &a[9], &a[10], &a[11],
|
||||
&a[12], &a[13], &a[14], &a[15]);
|
||||
transpose_s32_8x4(&a[0], &a[8], &a[1], &a[9], &a[2], &a[10], &a[3],
|
||||
&a[11]);
|
||||
highbd_iadst8(&a[0], &a[8], &a[1], &a[9], &a[2], &a[10], &a[3], &a[11]);
|
||||
transpose_s32_8x4(&a[4], &a[12], &a[5], &a[13], &a[6], &a[14], &a[7],
|
||||
&a[15]);
|
||||
highbd_iadst8(&a[4], &a[12], &a[5], &a[13], &a[6], &a[14], &a[7],
|
||||
&a[15]);
|
||||
break;
|
||||
}
|
||||
|
||||
case DCT_ADST: {
|
||||
const int32x4_t cospis0 = vld1q_s32(kCospi32); // cospi 0, 8, 16, 24
|
||||
const int32x4_t cospis1 =
|
||||
vld1q_s32(kCospi32 + 4); // cospi 4, 12, 20, 28
|
||||
|
||||
transpose_s32_8x4(&a[0], &a[1], &a[2], &a[3], &a[4], &a[5], &a[6],
|
||||
&a[7]);
|
||||
highbd_iadst8(&a[0], &a[1], &a[2], &a[3], &a[4], &a[5], &a[6], &a[7]);
|
||||
transpose_s32_8x4(&a[8], &a[9], &a[10], &a[11], &a[12], &a[13], &a[14],
|
||||
&a[15]);
|
||||
highbd_iadst8(&a[8], &a[9], &a[10], &a[11], &a[12], &a[13], &a[14],
|
||||
&a[15]);
|
||||
idct8x8_64_half1d_bd12(cospis0, cospis1, &a[0], &a[8], &a[1], &a[9],
|
||||
&a[2], &a[10], &a[3], &a[11]);
|
||||
idct8x8_64_half1d_bd12(cospis0, cospis1, &a[4], &a[12], &a[5], &a[13],
|
||||
&a[6], &a[14], &a[7], &a[15]);
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
assert(tx_type == ADST_ADST);
|
||||
transpose_s32_8x4(&a[0], &a[1], &a[2], &a[3], &a[4], &a[5], &a[6],
|
||||
&a[7]);
|
||||
highbd_iadst8(&a[0], &a[1], &a[2], &a[3], &a[4], &a[5], &a[6], &a[7]);
|
||||
transpose_s32_8x4(&a[8], &a[9], &a[10], &a[11], &a[12], &a[13], &a[14],
|
||||
&a[15]);
|
||||
highbd_iadst8(&a[8], &a[9], &a[10], &a[11], &a[12], &a[13], &a[14],
|
||||
&a[15]);
|
||||
transpose_s32_8x4(&a[0], &a[8], &a[1], &a[9], &a[2], &a[10], &a[3],
|
||||
&a[11]);
|
||||
highbd_iadst8(&a[0], &a[8], &a[1], &a[9], &a[2], &a[10], &a[3], &a[11]);
|
||||
transpose_s32_8x4(&a[4], &a[12], &a[5], &a[13], &a[6], &a[14], &a[7],
|
||||
&a[15]);
|
||||
highbd_iadst8(&a[4], &a[12], &a[5], &a[13], &a[6], &a[14], &a[7],
|
||||
&a[15]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
c[0] = vcombine_s16(vrshrn_n_s32(a[0], 5), vrshrn_n_s32(a[4], 5));
|
||||
c[1] = vcombine_s16(vrshrn_n_s32(a[8], 5), vrshrn_n_s32(a[12], 5));
|
||||
c[2] = vcombine_s16(vrshrn_n_s32(a[1], 5), vrshrn_n_s32(a[5], 5));
|
||||
c[3] = vcombine_s16(vrshrn_n_s32(a[9], 5), vrshrn_n_s32(a[13], 5));
|
||||
c[4] = vcombine_s16(vrshrn_n_s32(a[2], 5), vrshrn_n_s32(a[6], 5));
|
||||
c[5] = vcombine_s16(vrshrn_n_s32(a[10], 5), vrshrn_n_s32(a[14], 5));
|
||||
c[6] = vcombine_s16(vrshrn_n_s32(a[3], 5), vrshrn_n_s32(a[7], 5));
|
||||
c[7] = vcombine_s16(vrshrn_n_s32(a[11], 5), vrshrn_n_s32(a[15], 5));
|
||||
}
|
||||
highbd_add8x8(c, dest, stride, bd);
|
||||
}
|
||||
@@ -0,0 +1,279 @@
|
||||
/*
|
||||
* Copyright (c) 2018 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 <assert.h>
|
||||
|
||||
#include "./vp9_rtcd.h"
|
||||
#include "./vpx_config.h"
|
||||
#include "vp9/common/vp9_common.h"
|
||||
#include "vp9/common/arm/neon/vp9_iht_neon.h"
|
||||
#include "vpx_dsp/arm/idct_neon.h"
|
||||
#include "vpx_dsp/arm/mem_neon.h"
|
||||
#include "vpx_dsp/arm/transpose_neon.h"
|
||||
|
||||
void vpx_iadst16x16_256_add_half1d(const void *const input, int16_t *output,
|
||||
void *const dest, const int stride,
|
||||
const int highbd_flag) {
|
||||
int16x8_t in[16], out[16];
|
||||
const int16x4_t c_1_31_5_27 =
|
||||
create_s16x4_neon(cospi_1_64, cospi_31_64, cospi_5_64, cospi_27_64);
|
||||
const int16x4_t c_9_23_13_19 =
|
||||
create_s16x4_neon(cospi_9_64, cospi_23_64, cospi_13_64, cospi_19_64);
|
||||
const int16x4_t c_17_15_21_11 =
|
||||
create_s16x4_neon(cospi_17_64, cospi_15_64, cospi_21_64, cospi_11_64);
|
||||
const int16x4_t c_25_7_29_3 =
|
||||
create_s16x4_neon(cospi_25_64, cospi_7_64, cospi_29_64, cospi_3_64);
|
||||
const int16x4_t c_4_28_20_12 =
|
||||
create_s16x4_neon(cospi_4_64, cospi_28_64, cospi_20_64, cospi_12_64);
|
||||
const int16x4_t c_16_n16_8_24 =
|
||||
create_s16x4_neon(cospi_16_64, -cospi_16_64, cospi_8_64, cospi_24_64);
|
||||
int16x8_t x[16], t[12];
|
||||
int32x4_t s0[2], s1[2], s2[2], s3[2], s4[2], s5[2], s6[2], s7[2];
|
||||
int32x4_t s8[2], s9[2], s10[2], s11[2], s12[2], s13[2], s14[2], s15[2];
|
||||
|
||||
// Load input (16x8)
|
||||
if (output) {
|
||||
const tran_low_t *inputT = (const tran_low_t *)input;
|
||||
in[0] = load_tran_low_to_s16q(inputT);
|
||||
inputT += 8;
|
||||
in[8] = load_tran_low_to_s16q(inputT);
|
||||
inputT += 8;
|
||||
in[1] = load_tran_low_to_s16q(inputT);
|
||||
inputT += 8;
|
||||
in[9] = load_tran_low_to_s16q(inputT);
|
||||
inputT += 8;
|
||||
in[2] = load_tran_low_to_s16q(inputT);
|
||||
inputT += 8;
|
||||
in[10] = load_tran_low_to_s16q(inputT);
|
||||
inputT += 8;
|
||||
in[3] = load_tran_low_to_s16q(inputT);
|
||||
inputT += 8;
|
||||
in[11] = load_tran_low_to_s16q(inputT);
|
||||
inputT += 8;
|
||||
in[4] = load_tran_low_to_s16q(inputT);
|
||||
inputT += 8;
|
||||
in[12] = load_tran_low_to_s16q(inputT);
|
||||
inputT += 8;
|
||||
in[5] = load_tran_low_to_s16q(inputT);
|
||||
inputT += 8;
|
||||
in[13] = load_tran_low_to_s16q(inputT);
|
||||
inputT += 8;
|
||||
in[6] = load_tran_low_to_s16q(inputT);
|
||||
inputT += 8;
|
||||
in[14] = load_tran_low_to_s16q(inputT);
|
||||
inputT += 8;
|
||||
in[7] = load_tran_low_to_s16q(inputT);
|
||||
inputT += 8;
|
||||
in[15] = load_tran_low_to_s16q(inputT);
|
||||
} else {
|
||||
const int16_t *inputT = (const int16_t *)input;
|
||||
in[0] = vld1q_s16(inputT);
|
||||
inputT += 8;
|
||||
in[8] = vld1q_s16(inputT);
|
||||
inputT += 8;
|
||||
in[1] = vld1q_s16(inputT);
|
||||
inputT += 8;
|
||||
in[9] = vld1q_s16(inputT);
|
||||
inputT += 8;
|
||||
in[2] = vld1q_s16(inputT);
|
||||
inputT += 8;
|
||||
in[10] = vld1q_s16(inputT);
|
||||
inputT += 8;
|
||||
in[3] = vld1q_s16(inputT);
|
||||
inputT += 8;
|
||||
in[11] = vld1q_s16(inputT);
|
||||
inputT += 8;
|
||||
in[4] = vld1q_s16(inputT);
|
||||
inputT += 8;
|
||||
in[12] = vld1q_s16(inputT);
|
||||
inputT += 8;
|
||||
in[5] = vld1q_s16(inputT);
|
||||
inputT += 8;
|
||||
in[13] = vld1q_s16(inputT);
|
||||
inputT += 8;
|
||||
in[6] = vld1q_s16(inputT);
|
||||
inputT += 8;
|
||||
in[14] = vld1q_s16(inputT);
|
||||
inputT += 8;
|
||||
in[7] = vld1q_s16(inputT);
|
||||
inputT += 8;
|
||||
in[15] = vld1q_s16(inputT);
|
||||
}
|
||||
|
||||
// Transpose
|
||||
transpose_s16_8x8(&in[0], &in[1], &in[2], &in[3], &in[4], &in[5], &in[6],
|
||||
&in[7]);
|
||||
transpose_s16_8x8(&in[8], &in[9], &in[10], &in[11], &in[12], &in[13], &in[14],
|
||||
&in[15]);
|
||||
|
||||
x[0] = in[15];
|
||||
x[1] = in[0];
|
||||
x[2] = in[13];
|
||||
x[3] = in[2];
|
||||
x[4] = in[11];
|
||||
x[5] = in[4];
|
||||
x[6] = in[9];
|
||||
x[7] = in[6];
|
||||
x[8] = in[7];
|
||||
x[9] = in[8];
|
||||
x[10] = in[5];
|
||||
x[11] = in[10];
|
||||
x[12] = in[3];
|
||||
x[13] = in[12];
|
||||
x[14] = in[1];
|
||||
x[15] = in[14];
|
||||
|
||||
// stage 1
|
||||
iadst_butterfly_lane_0_1_neon(x[0], x[1], c_1_31_5_27, s0, s1);
|
||||
iadst_butterfly_lane_2_3_neon(x[2], x[3], c_1_31_5_27, s2, s3);
|
||||
iadst_butterfly_lane_0_1_neon(x[4], x[5], c_9_23_13_19, s4, s5);
|
||||
iadst_butterfly_lane_2_3_neon(x[6], x[7], c_9_23_13_19, s6, s7);
|
||||
iadst_butterfly_lane_0_1_neon(x[8], x[9], c_17_15_21_11, s8, s9);
|
||||
iadst_butterfly_lane_2_3_neon(x[10], x[11], c_17_15_21_11, s10, s11);
|
||||
iadst_butterfly_lane_0_1_neon(x[12], x[13], c_25_7_29_3, s12, s13);
|
||||
iadst_butterfly_lane_2_3_neon(x[14], x[15], c_25_7_29_3, s14, s15);
|
||||
|
||||
x[0] = add_dct_const_round_shift_low_8(s0, s8);
|
||||
x[1] = add_dct_const_round_shift_low_8(s1, s9);
|
||||
x[2] = add_dct_const_round_shift_low_8(s2, s10);
|
||||
x[3] = add_dct_const_round_shift_low_8(s3, s11);
|
||||
x[4] = add_dct_const_round_shift_low_8(s4, s12);
|
||||
x[5] = add_dct_const_round_shift_low_8(s5, s13);
|
||||
x[6] = add_dct_const_round_shift_low_8(s6, s14);
|
||||
x[7] = add_dct_const_round_shift_low_8(s7, s15);
|
||||
x[8] = sub_dct_const_round_shift_low_8(s0, s8);
|
||||
x[9] = sub_dct_const_round_shift_low_8(s1, s9);
|
||||
x[10] = sub_dct_const_round_shift_low_8(s2, s10);
|
||||
x[11] = sub_dct_const_round_shift_low_8(s3, s11);
|
||||
x[12] = sub_dct_const_round_shift_low_8(s4, s12);
|
||||
x[13] = sub_dct_const_round_shift_low_8(s5, s13);
|
||||
x[14] = sub_dct_const_round_shift_low_8(s6, s14);
|
||||
x[15] = sub_dct_const_round_shift_low_8(s7, s15);
|
||||
|
||||
// stage 2
|
||||
t[0] = x[0];
|
||||
t[1] = x[1];
|
||||
t[2] = x[2];
|
||||
t[3] = x[3];
|
||||
t[4] = x[4];
|
||||
t[5] = x[5];
|
||||
t[6] = x[6];
|
||||
t[7] = x[7];
|
||||
iadst_butterfly_lane_0_1_neon(x[8], x[9], c_4_28_20_12, s8, s9);
|
||||
iadst_butterfly_lane_2_3_neon(x[10], x[11], c_4_28_20_12, s10, s11);
|
||||
iadst_butterfly_lane_1_0_neon(x[13], x[12], c_4_28_20_12, s13, s12);
|
||||
iadst_butterfly_lane_3_2_neon(x[15], x[14], c_4_28_20_12, s15, s14);
|
||||
|
||||
x[0] = vaddq_s16(t[0], t[4]);
|
||||
x[1] = vaddq_s16(t[1], t[5]);
|
||||
x[2] = vaddq_s16(t[2], t[6]);
|
||||
x[3] = vaddq_s16(t[3], t[7]);
|
||||
x[4] = vsubq_s16(t[0], t[4]);
|
||||
x[5] = vsubq_s16(t[1], t[5]);
|
||||
x[6] = vsubq_s16(t[2], t[6]);
|
||||
x[7] = vsubq_s16(t[3], t[7]);
|
||||
x[8] = add_dct_const_round_shift_low_8(s8, s12);
|
||||
x[9] = add_dct_const_round_shift_low_8(s9, s13);
|
||||
x[10] = add_dct_const_round_shift_low_8(s10, s14);
|
||||
x[11] = add_dct_const_round_shift_low_8(s11, s15);
|
||||
x[12] = sub_dct_const_round_shift_low_8(s8, s12);
|
||||
x[13] = sub_dct_const_round_shift_low_8(s9, s13);
|
||||
x[14] = sub_dct_const_round_shift_low_8(s10, s14);
|
||||
x[15] = sub_dct_const_round_shift_low_8(s11, s15);
|
||||
|
||||
// stage 3
|
||||
t[0] = x[0];
|
||||
t[1] = x[1];
|
||||
t[2] = x[2];
|
||||
t[3] = x[3];
|
||||
iadst_butterfly_lane_2_3_neon(x[4], x[5], c_16_n16_8_24, s4, s5);
|
||||
iadst_butterfly_lane_3_2_neon(x[7], x[6], c_16_n16_8_24, s7, s6);
|
||||
t[8] = x[8];
|
||||
t[9] = x[9];
|
||||
t[10] = x[10];
|
||||
t[11] = x[11];
|
||||
iadst_butterfly_lane_2_3_neon(x[12], x[13], c_16_n16_8_24, s12, s13);
|
||||
iadst_butterfly_lane_3_2_neon(x[15], x[14], c_16_n16_8_24, s15, s14);
|
||||
|
||||
x[0] = vaddq_s16(t[0], t[2]);
|
||||
x[1] = vaddq_s16(t[1], t[3]);
|
||||
x[2] = vsubq_s16(t[0], t[2]);
|
||||
x[3] = vsubq_s16(t[1], t[3]);
|
||||
x[4] = add_dct_const_round_shift_low_8(s4, s6);
|
||||
x[5] = add_dct_const_round_shift_low_8(s5, s7);
|
||||
x[6] = sub_dct_const_round_shift_low_8(s4, s6);
|
||||
x[7] = sub_dct_const_round_shift_low_8(s5, s7);
|
||||
x[8] = vaddq_s16(t[8], t[10]);
|
||||
x[9] = vaddq_s16(t[9], t[11]);
|
||||
x[10] = vsubq_s16(t[8], t[10]);
|
||||
x[11] = vsubq_s16(t[9], t[11]);
|
||||
x[12] = add_dct_const_round_shift_low_8(s12, s14);
|
||||
x[13] = add_dct_const_round_shift_low_8(s13, s15);
|
||||
x[14] = sub_dct_const_round_shift_low_8(s12, s14);
|
||||
x[15] = sub_dct_const_round_shift_low_8(s13, s15);
|
||||
|
||||
// stage 4
|
||||
iadst_half_butterfly_neg_neon(&x[3], &x[2], c_16_n16_8_24);
|
||||
iadst_half_butterfly_pos_neon(&x[7], &x[6], c_16_n16_8_24);
|
||||
iadst_half_butterfly_pos_neon(&x[11], &x[10], c_16_n16_8_24);
|
||||
iadst_half_butterfly_neg_neon(&x[15], &x[14], c_16_n16_8_24);
|
||||
|
||||
out[0] = x[0];
|
||||
out[1] = vnegq_s16(x[8]);
|
||||
out[2] = x[12];
|
||||
out[3] = vnegq_s16(x[4]);
|
||||
out[4] = x[6];
|
||||
out[5] = x[14];
|
||||
out[6] = x[10];
|
||||
out[7] = x[2];
|
||||
out[8] = x[3];
|
||||
out[9] = x[11];
|
||||
out[10] = x[15];
|
||||
out[11] = x[7];
|
||||
out[12] = x[5];
|
||||
out[13] = vnegq_s16(x[13]);
|
||||
out[14] = x[9];
|
||||
out[15] = vnegq_s16(x[1]);
|
||||
|
||||
if (output) {
|
||||
idct16x16_store_pass1(out, output);
|
||||
} else {
|
||||
if (highbd_flag) {
|
||||
idct16x16_add_store_bd8(out, dest, stride);
|
||||
} else {
|
||||
idct16x16_add_store(out, dest, stride);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_iht16x16_256_add_neon(const tran_low_t *input, uint8_t *dest,
|
||||
int stride, int tx_type) {
|
||||
static const iht_2d IHT_16[] = {
|
||||
{ vpx_idct16x16_256_add_half1d,
|
||||
vpx_idct16x16_256_add_half1d }, // DCT_DCT = 0
|
||||
{ vpx_iadst16x16_256_add_half1d,
|
||||
vpx_idct16x16_256_add_half1d }, // ADST_DCT = 1
|
||||
{ vpx_idct16x16_256_add_half1d,
|
||||
vpx_iadst16x16_256_add_half1d }, // DCT_ADST = 2
|
||||
{ vpx_iadst16x16_256_add_half1d,
|
||||
vpx_iadst16x16_256_add_half1d } // ADST_ADST = 3
|
||||
};
|
||||
const iht_2d ht = IHT_16[tx_type];
|
||||
int16_t row_output[16 * 16];
|
||||
|
||||
// pass 1
|
||||
ht.rows(input, row_output, dest, stride, 0); // upper 8 rows
|
||||
ht.rows(input + 8 * 16, row_output + 8, dest, stride, 0); // lower 8 rows
|
||||
|
||||
// pass 2
|
||||
ht.cols(row_output, NULL, dest, stride, 0); // left 8 columns
|
||||
ht.cols(row_output + 16 * 8, NULL, dest + 8, stride, 0); // right 8 columns
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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 <assert.h>
|
||||
|
||||
#include "./vp9_rtcd.h"
|
||||
#include "./vpx_config.h"
|
||||
#include "vp9/common/vp9_common.h"
|
||||
#include "vp9/common/arm/neon/vp9_iht_neon.h"
|
||||
#include "vpx_dsp/arm/idct_neon.h"
|
||||
#include "vpx_dsp/arm/mem_neon.h"
|
||||
#include "vpx_dsp/txfm_common.h"
|
||||
|
||||
void vp9_iht4x4_16_add_neon(const tran_low_t *input, uint8_t *dest, int stride,
|
||||
int tx_type) {
|
||||
int16x8_t a[2];
|
||||
uint8x8_t s[2], d[2];
|
||||
uint16x8_t sum[2];
|
||||
|
||||
assert(!((intptr_t)dest % sizeof(uint32_t)));
|
||||
assert(!(stride % sizeof(uint32_t)));
|
||||
|
||||
a[0] = load_tran_low_to_s16q(input);
|
||||
a[1] = load_tran_low_to_s16q(input + 8);
|
||||
transpose_s16_4x4q(&a[0], &a[1]);
|
||||
|
||||
switch (tx_type) {
|
||||
case DCT_DCT:
|
||||
idct4x4_16_kernel_bd8(a);
|
||||
a[1] = vcombine_s16(vget_high_s16(a[1]), vget_low_s16(a[1]));
|
||||
transpose_s16_4x4q(&a[0], &a[1]);
|
||||
idct4x4_16_kernel_bd8(a);
|
||||
a[1] = vcombine_s16(vget_high_s16(a[1]), vget_low_s16(a[1]));
|
||||
break;
|
||||
|
||||
case ADST_DCT:
|
||||
idct4x4_16_kernel_bd8(a);
|
||||
a[1] = vcombine_s16(vget_high_s16(a[1]), vget_low_s16(a[1]));
|
||||
transpose_s16_4x4q(&a[0], &a[1]);
|
||||
iadst4(a);
|
||||
break;
|
||||
|
||||
case DCT_ADST:
|
||||
iadst4(a);
|
||||
transpose_s16_4x4q(&a[0], &a[1]);
|
||||
idct4x4_16_kernel_bd8(a);
|
||||
a[1] = vcombine_s16(vget_high_s16(a[1]), vget_low_s16(a[1]));
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(tx_type == ADST_ADST);
|
||||
iadst4(a);
|
||||
transpose_s16_4x4q(&a[0], &a[1]);
|
||||
iadst4(a);
|
||||
break;
|
||||
}
|
||||
|
||||
a[0] = vrshrq_n_s16(a[0], 4);
|
||||
a[1] = vrshrq_n_s16(a[1], 4);
|
||||
s[0] = load_u8(dest, stride);
|
||||
s[1] = load_u8(dest + 2 * stride, stride);
|
||||
sum[0] = vaddw_u8(vreinterpretq_u16_s16(a[0]), s[0]);
|
||||
sum[1] = vaddw_u8(vreinterpretq_u16_s16(a[1]), s[1]);
|
||||
d[0] = vqmovun_s16(vreinterpretq_s16_u16(sum[0]));
|
||||
d[1] = vqmovun_s16(vreinterpretq_s16_u16(sum[1]));
|
||||
store_u8(dest, stride, d[0]);
|
||||
store_u8(dest + 2 * stride, stride, d[1]);
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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 <assert.h>
|
||||
|
||||
#include "./vp9_rtcd.h"
|
||||
#include "./vpx_config.h"
|
||||
#include "vp9/common/vp9_common.h"
|
||||
#include "vp9/common/arm/neon/vp9_iht_neon.h"
|
||||
#include "vpx_dsp/arm/idct_neon.h"
|
||||
#include "vpx_dsp/arm/mem_neon.h"
|
||||
#include "vpx_dsp/arm/transpose_neon.h"
|
||||
|
||||
void vp9_iht8x8_64_add_neon(const tran_low_t *input, uint8_t *dest, int stride,
|
||||
int tx_type) {
|
||||
const int16x8_t cospis = vld1q_s16(kCospi);
|
||||
const int16x4_t cospis0 = vget_low_s16(cospis); // cospi 0, 8, 16, 24
|
||||
const int16x4_t cospis1 = vget_high_s16(cospis); // cospi 4, 12, 20, 28
|
||||
int16x8_t a[8];
|
||||
|
||||
a[0] = load_tran_low_to_s16q(input + 0 * 8);
|
||||
a[1] = load_tran_low_to_s16q(input + 1 * 8);
|
||||
a[2] = load_tran_low_to_s16q(input + 2 * 8);
|
||||
a[3] = load_tran_low_to_s16q(input + 3 * 8);
|
||||
a[4] = load_tran_low_to_s16q(input + 4 * 8);
|
||||
a[5] = load_tran_low_to_s16q(input + 5 * 8);
|
||||
a[6] = load_tran_low_to_s16q(input + 6 * 8);
|
||||
a[7] = load_tran_low_to_s16q(input + 7 * 8);
|
||||
|
||||
transpose_s16_8x8(&a[0], &a[1], &a[2], &a[3], &a[4], &a[5], &a[6], &a[7]);
|
||||
|
||||
switch (tx_type) {
|
||||
case DCT_DCT:
|
||||
idct8x8_64_1d_bd8_kernel(cospis0, cospis1, a);
|
||||
transpose_s16_8x8(&a[0], &a[1], &a[2], &a[3], &a[4], &a[5], &a[6], &a[7]);
|
||||
idct8x8_64_1d_bd8_kernel(cospis0, cospis1, a);
|
||||
break;
|
||||
|
||||
case ADST_DCT:
|
||||
idct8x8_64_1d_bd8_kernel(cospis0, cospis1, a);
|
||||
transpose_s16_8x8(&a[0], &a[1], &a[2], &a[3], &a[4], &a[5], &a[6], &a[7]);
|
||||
iadst8(a);
|
||||
break;
|
||||
|
||||
case DCT_ADST:
|
||||
iadst8(a);
|
||||
transpose_s16_8x8(&a[0], &a[1], &a[2], &a[3], &a[4], &a[5], &a[6], &a[7]);
|
||||
idct8x8_64_1d_bd8_kernel(cospis0, cospis1, a);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(tx_type == ADST_ADST);
|
||||
iadst8(a);
|
||||
transpose_s16_8x8(&a[0], &a[1], &a[2], &a[3], &a[4], &a[5], &a[6], &a[7]);
|
||||
iadst8(a);
|
||||
break;
|
||||
}
|
||||
|
||||
idct8x8_add8x8_neon(a, dest, stride);
|
||||
}
|
||||
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
* Copyright (c) 2018 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 VPX_VP9_COMMON_ARM_NEON_VP9_IHT_NEON_H_
|
||||
#define VPX_VP9_COMMON_ARM_NEON_VP9_IHT_NEON_H_
|
||||
|
||||
#include <arm_neon.h>
|
||||
|
||||
#include "./vp9_rtcd.h"
|
||||
#include "./vpx_config.h"
|
||||
#include "vp9/common/vp9_common.h"
|
||||
#include "vpx_dsp/arm/idct_neon.h"
|
||||
#include "vpx_dsp/arm/mem_neon.h"
|
||||
#include "vpx_dsp/txfm_common.h"
|
||||
|
||||
static INLINE void iadst4(int16x8_t *const io) {
|
||||
const int32x4_t c3 = vdupq_n_s32(sinpi_3_9);
|
||||
int16x4_t x[4];
|
||||
int32x4_t s[8], output[4];
|
||||
const int16x4_t c =
|
||||
create_s16x4_neon(sinpi_1_9, sinpi_2_9, sinpi_3_9, sinpi_4_9);
|
||||
|
||||
x[0] = vget_low_s16(io[0]);
|
||||
x[1] = vget_low_s16(io[1]);
|
||||
x[2] = vget_high_s16(io[0]);
|
||||
x[3] = vget_high_s16(io[1]);
|
||||
|
||||
s[0] = vmull_lane_s16(x[0], c, 0);
|
||||
s[1] = vmull_lane_s16(x[0], c, 1);
|
||||
s[2] = vmull_lane_s16(x[1], c, 2);
|
||||
s[3] = vmull_lane_s16(x[2], c, 3);
|
||||
s[4] = vmull_lane_s16(x[2], c, 0);
|
||||
s[5] = vmull_lane_s16(x[3], c, 1);
|
||||
s[6] = vmull_lane_s16(x[3], c, 3);
|
||||
s[7] = vaddl_s16(x[0], x[3]);
|
||||
s[7] = vsubw_s16(s[7], x[2]);
|
||||
|
||||
s[0] = vaddq_s32(s[0], s[3]);
|
||||
s[0] = vaddq_s32(s[0], s[5]);
|
||||
s[1] = vsubq_s32(s[1], s[4]);
|
||||
s[1] = vsubq_s32(s[1], s[6]);
|
||||
s[3] = s[2];
|
||||
s[2] = vmulq_s32(c3, s[7]);
|
||||
|
||||
output[0] = vaddq_s32(s[0], s[3]);
|
||||
output[1] = vaddq_s32(s[1], s[3]);
|
||||
output[2] = s[2];
|
||||
output[3] = vaddq_s32(s[0], s[1]);
|
||||
output[3] = vsubq_s32(output[3], s[3]);
|
||||
dct_const_round_shift_low_8_dual(output, &io[0], &io[1]);
|
||||
}
|
||||
|
||||
static INLINE void iadst_half_butterfly_neon(int16x8_t *const x,
|
||||
const int16x4_t c) {
|
||||
// Don't add/sub before multiply, which will overflow in iadst8.
|
||||
const int32x4_t x0_lo = vmull_lane_s16(vget_low_s16(x[0]), c, 0);
|
||||
const int32x4_t x0_hi = vmull_lane_s16(vget_high_s16(x[0]), c, 0);
|
||||
const int32x4_t x1_lo = vmull_lane_s16(vget_low_s16(x[1]), c, 0);
|
||||
const int32x4_t x1_hi = vmull_lane_s16(vget_high_s16(x[1]), c, 0);
|
||||
int32x4_t t0[2], t1[2];
|
||||
|
||||
t0[0] = vaddq_s32(x0_lo, x1_lo);
|
||||
t0[1] = vaddq_s32(x0_hi, x1_hi);
|
||||
t1[0] = vsubq_s32(x0_lo, x1_lo);
|
||||
t1[1] = vsubq_s32(x0_hi, x1_hi);
|
||||
x[0] = dct_const_round_shift_low_8(t0);
|
||||
x[1] = dct_const_round_shift_low_8(t1);
|
||||
}
|
||||
|
||||
static INLINE void iadst_half_butterfly_neg_neon(int16x8_t *const x0,
|
||||
int16x8_t *const x1,
|
||||
const int16x4_t c) {
|
||||
// Don't add/sub before multiply, which will overflow in iadst8.
|
||||
const int32x4_t x0_lo = vmull_lane_s16(vget_low_s16(*x0), c, 1);
|
||||
const int32x4_t x0_hi = vmull_lane_s16(vget_high_s16(*x0), c, 1);
|
||||
const int32x4_t x1_lo = vmull_lane_s16(vget_low_s16(*x1), c, 1);
|
||||
const int32x4_t x1_hi = vmull_lane_s16(vget_high_s16(*x1), c, 1);
|
||||
int32x4_t t0[2], t1[2];
|
||||
|
||||
t0[0] = vaddq_s32(x0_lo, x1_lo);
|
||||
t0[1] = vaddq_s32(x0_hi, x1_hi);
|
||||
t1[0] = vsubq_s32(x0_lo, x1_lo);
|
||||
t1[1] = vsubq_s32(x0_hi, x1_hi);
|
||||
*x1 = dct_const_round_shift_low_8(t0);
|
||||
*x0 = dct_const_round_shift_low_8(t1);
|
||||
}
|
||||
|
||||
static INLINE void iadst_half_butterfly_pos_neon(int16x8_t *const x0,
|
||||
int16x8_t *const x1,
|
||||
const int16x4_t c) {
|
||||
// Don't add/sub before multiply, which will overflow in iadst8.
|
||||
const int32x4_t x0_lo = vmull_lane_s16(vget_low_s16(*x0), c, 0);
|
||||
const int32x4_t x0_hi = vmull_lane_s16(vget_high_s16(*x0), c, 0);
|
||||
const int32x4_t x1_lo = vmull_lane_s16(vget_low_s16(*x1), c, 0);
|
||||
const int32x4_t x1_hi = vmull_lane_s16(vget_high_s16(*x1), c, 0);
|
||||
int32x4_t t0[2], t1[2];
|
||||
|
||||
t0[0] = vaddq_s32(x0_lo, x1_lo);
|
||||
t0[1] = vaddq_s32(x0_hi, x1_hi);
|
||||
t1[0] = vsubq_s32(x0_lo, x1_lo);
|
||||
t1[1] = vsubq_s32(x0_hi, x1_hi);
|
||||
*x1 = dct_const_round_shift_low_8(t0);
|
||||
*x0 = dct_const_round_shift_low_8(t1);
|
||||
}
|
||||
|
||||
static INLINE void iadst_butterfly_lane_0_1_neon(const int16x8_t in0,
|
||||
const int16x8_t in1,
|
||||
const int16x4_t c,
|
||||
int32x4_t *const s0,
|
||||
int32x4_t *const s1) {
|
||||
s0[0] = vmull_lane_s16(vget_low_s16(in0), c, 0);
|
||||
s0[1] = vmull_lane_s16(vget_high_s16(in0), c, 0);
|
||||
s1[0] = vmull_lane_s16(vget_low_s16(in0), c, 1);
|
||||
s1[1] = vmull_lane_s16(vget_high_s16(in0), c, 1);
|
||||
|
||||
s0[0] = vmlal_lane_s16(s0[0], vget_low_s16(in1), c, 1);
|
||||
s0[1] = vmlal_lane_s16(s0[1], vget_high_s16(in1), c, 1);
|
||||
s1[0] = vmlsl_lane_s16(s1[0], vget_low_s16(in1), c, 0);
|
||||
s1[1] = vmlsl_lane_s16(s1[1], vget_high_s16(in1), c, 0);
|
||||
}
|
||||
|
||||
static INLINE void iadst_butterfly_lane_2_3_neon(const int16x8_t in0,
|
||||
const int16x8_t in1,
|
||||
const int16x4_t c,
|
||||
int32x4_t *const s0,
|
||||
int32x4_t *const s1) {
|
||||
s0[0] = vmull_lane_s16(vget_low_s16(in0), c, 2);
|
||||
s0[1] = vmull_lane_s16(vget_high_s16(in0), c, 2);
|
||||
s1[0] = vmull_lane_s16(vget_low_s16(in0), c, 3);
|
||||
s1[1] = vmull_lane_s16(vget_high_s16(in0), c, 3);
|
||||
|
||||
s0[0] = vmlal_lane_s16(s0[0], vget_low_s16(in1), c, 3);
|
||||
s0[1] = vmlal_lane_s16(s0[1], vget_high_s16(in1), c, 3);
|
||||
s1[0] = vmlsl_lane_s16(s1[0], vget_low_s16(in1), c, 2);
|
||||
s1[1] = vmlsl_lane_s16(s1[1], vget_high_s16(in1), c, 2);
|
||||
}
|
||||
|
||||
static INLINE void iadst_butterfly_lane_1_0_neon(const int16x8_t in0,
|
||||
const int16x8_t in1,
|
||||
const int16x4_t c,
|
||||
int32x4_t *const s0,
|
||||
int32x4_t *const s1) {
|
||||
s0[0] = vmull_lane_s16(vget_low_s16(in0), c, 1);
|
||||
s0[1] = vmull_lane_s16(vget_high_s16(in0), c, 1);
|
||||
s1[0] = vmull_lane_s16(vget_low_s16(in0), c, 0);
|
||||
s1[1] = vmull_lane_s16(vget_high_s16(in0), c, 0);
|
||||
|
||||
s0[0] = vmlal_lane_s16(s0[0], vget_low_s16(in1), c, 0);
|
||||
s0[1] = vmlal_lane_s16(s0[1], vget_high_s16(in1), c, 0);
|
||||
s1[0] = vmlsl_lane_s16(s1[0], vget_low_s16(in1), c, 1);
|
||||
s1[1] = vmlsl_lane_s16(s1[1], vget_high_s16(in1), c, 1);
|
||||
}
|
||||
|
||||
static INLINE void iadst_butterfly_lane_3_2_neon(const int16x8_t in0,
|
||||
const int16x8_t in1,
|
||||
const int16x4_t c,
|
||||
int32x4_t *const s0,
|
||||
int32x4_t *const s1) {
|
||||
s0[0] = vmull_lane_s16(vget_low_s16(in0), c, 3);
|
||||
s0[1] = vmull_lane_s16(vget_high_s16(in0), c, 3);
|
||||
s1[0] = vmull_lane_s16(vget_low_s16(in0), c, 2);
|
||||
s1[1] = vmull_lane_s16(vget_high_s16(in0), c, 2);
|
||||
|
||||
s0[0] = vmlal_lane_s16(s0[0], vget_low_s16(in1), c, 2);
|
||||
s0[1] = vmlal_lane_s16(s0[1], vget_high_s16(in1), c, 2);
|
||||
s1[0] = vmlsl_lane_s16(s1[0], vget_low_s16(in1), c, 3);
|
||||
s1[1] = vmlsl_lane_s16(s1[1], vget_high_s16(in1), c, 3);
|
||||
}
|
||||
|
||||
static INLINE int16x8_t add_dct_const_round_shift_low_8(
|
||||
const int32x4_t *const in0, const int32x4_t *const in1) {
|
||||
int32x4_t sum[2];
|
||||
|
||||
sum[0] = vaddq_s32(in0[0], in1[0]);
|
||||
sum[1] = vaddq_s32(in0[1], in1[1]);
|
||||
return dct_const_round_shift_low_8(sum);
|
||||
}
|
||||
|
||||
static INLINE int16x8_t sub_dct_const_round_shift_low_8(
|
||||
const int32x4_t *const in0, const int32x4_t *const in1) {
|
||||
int32x4_t sum[2];
|
||||
|
||||
sum[0] = vsubq_s32(in0[0], in1[0]);
|
||||
sum[1] = vsubq_s32(in0[1], in1[1]);
|
||||
return dct_const_round_shift_low_8(sum);
|
||||
}
|
||||
|
||||
static INLINE void iadst8(int16x8_t *const io) {
|
||||
const int16x4_t c0 =
|
||||
create_s16x4_neon(cospi_2_64, cospi_30_64, cospi_10_64, cospi_22_64);
|
||||
const int16x4_t c1 =
|
||||
create_s16x4_neon(cospi_18_64, cospi_14_64, cospi_26_64, cospi_6_64);
|
||||
const int16x4_t c2 =
|
||||
create_s16x4_neon(cospi_16_64, 0, cospi_8_64, cospi_24_64);
|
||||
int16x8_t x[8], t[4];
|
||||
int32x4_t s0[2], s1[2], s2[2], s3[2], s4[2], s5[2], s6[2], s7[2];
|
||||
|
||||
x[0] = io[7];
|
||||
x[1] = io[0];
|
||||
x[2] = io[5];
|
||||
x[3] = io[2];
|
||||
x[4] = io[3];
|
||||
x[5] = io[4];
|
||||
x[6] = io[1];
|
||||
x[7] = io[6];
|
||||
|
||||
// stage 1
|
||||
iadst_butterfly_lane_0_1_neon(x[0], x[1], c0, s0, s1);
|
||||
iadst_butterfly_lane_2_3_neon(x[2], x[3], c0, s2, s3);
|
||||
iadst_butterfly_lane_0_1_neon(x[4], x[5], c1, s4, s5);
|
||||
iadst_butterfly_lane_2_3_neon(x[6], x[7], c1, s6, s7);
|
||||
|
||||
x[0] = add_dct_const_round_shift_low_8(s0, s4);
|
||||
x[1] = add_dct_const_round_shift_low_8(s1, s5);
|
||||
x[2] = add_dct_const_round_shift_low_8(s2, s6);
|
||||
x[3] = add_dct_const_round_shift_low_8(s3, s7);
|
||||
x[4] = sub_dct_const_round_shift_low_8(s0, s4);
|
||||
x[5] = sub_dct_const_round_shift_low_8(s1, s5);
|
||||
x[6] = sub_dct_const_round_shift_low_8(s2, s6);
|
||||
x[7] = sub_dct_const_round_shift_low_8(s3, s7);
|
||||
|
||||
// stage 2
|
||||
t[0] = x[0];
|
||||
t[1] = x[1];
|
||||
t[2] = x[2];
|
||||
t[3] = x[3];
|
||||
iadst_butterfly_lane_2_3_neon(x[4], x[5], c2, s4, s5);
|
||||
iadst_butterfly_lane_3_2_neon(x[7], x[6], c2, s7, s6);
|
||||
|
||||
x[0] = vaddq_s16(t[0], t[2]);
|
||||
x[1] = vaddq_s16(t[1], t[3]);
|
||||
x[2] = vsubq_s16(t[0], t[2]);
|
||||
x[3] = vsubq_s16(t[1], t[3]);
|
||||
x[4] = add_dct_const_round_shift_low_8(s4, s6);
|
||||
x[5] = add_dct_const_round_shift_low_8(s5, s7);
|
||||
x[6] = sub_dct_const_round_shift_low_8(s4, s6);
|
||||
x[7] = sub_dct_const_round_shift_low_8(s5, s7);
|
||||
|
||||
// stage 3
|
||||
iadst_half_butterfly_neon(x + 2, c2);
|
||||
iadst_half_butterfly_neon(x + 6, c2);
|
||||
|
||||
io[0] = x[0];
|
||||
io[1] = vnegq_s16(x[4]);
|
||||
io[2] = x[6];
|
||||
io[3] = vnegq_s16(x[2]);
|
||||
io[4] = x[3];
|
||||
io[5] = vnegq_s16(x[7]);
|
||||
io[6] = x[5];
|
||||
io[7] = vnegq_s16(x[1]);
|
||||
}
|
||||
|
||||
void vpx_iadst16x16_256_add_half1d(const void *const input, int16_t *output,
|
||||
void *const dest, const int stride,
|
||||
const int highbd_flag);
|
||||
|
||||
typedef void (*iht_1d)(const void *const input, int16_t *output,
|
||||
void *const dest, const int stride,
|
||||
const int highbd_flag);
|
||||
|
||||
typedef struct {
|
||||
iht_1d cols, rows; // vertical and horizontal
|
||||
} iht_2d;
|
||||
|
||||
#endif // VPX_VP9_COMMON_ARM_NEON_VP9_IHT_NEON_H_
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* 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 <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "./vpx_config.h"
|
||||
#include "./vp9_rtcd.h"
|
||||
#include "vp9/common/vp9_common.h"
|
||||
#include "vp9/common/vp9_blockd.h"
|
||||
#include "vp9/common/vp9_idct.h"
|
||||
#include "vpx_dsp/mips/inv_txfm_dspr2.h"
|
||||
#include "vpx_dsp/txfm_common.h"
|
||||
#include "vpx_ports/mem.h"
|
||||
|
||||
#if HAVE_DSPR2
|
||||
void vp9_iht16x16_256_add_dspr2(const int16_t *input, uint8_t *dest, int pitch,
|
||||
int tx_type) {
|
||||
int i, j;
|
||||
DECLARE_ALIGNED(32, int16_t, out[16 * 16]);
|
||||
int16_t *outptr = out;
|
||||
int16_t temp_out[16];
|
||||
uint32_t pos = 45;
|
||||
|
||||
/* bit positon for extract from acc */
|
||||
__asm__ __volatile__("wrdsp %[pos], 1 \n\t" : : [pos] "r"(pos));
|
||||
|
||||
switch (tx_type) {
|
||||
case DCT_DCT: // DCT in both horizontal and vertical
|
||||
idct16_rows_dspr2(input, outptr, 16);
|
||||
idct16_cols_add_blk_dspr2(out, dest, pitch);
|
||||
break;
|
||||
case ADST_DCT: // ADST in vertical, DCT in horizontal
|
||||
idct16_rows_dspr2(input, outptr, 16);
|
||||
|
||||
outptr = out;
|
||||
|
||||
for (i = 0; i < 16; ++i) {
|
||||
iadst16_dspr2(outptr, temp_out);
|
||||
|
||||
for (j = 0; j < 16; ++j)
|
||||
dest[j * pitch + i] = clip_pixel(ROUND_POWER_OF_TWO(temp_out[j], 6) +
|
||||
dest[j * pitch + i]);
|
||||
outptr += 16;
|
||||
}
|
||||
break;
|
||||
case DCT_ADST: // DCT in vertical, ADST in horizontal
|
||||
{
|
||||
int16_t temp_in[16 * 16];
|
||||
|
||||
for (i = 0; i < 16; ++i) {
|
||||
/* prefetch row */
|
||||
prefetch_load((const uint8_t *)(input + 16));
|
||||
|
||||
iadst16_dspr2(input, outptr);
|
||||
input += 16;
|
||||
outptr += 16;
|
||||
}
|
||||
|
||||
for (i = 0; i < 16; ++i)
|
||||
for (j = 0; j < 16; ++j) temp_in[j * 16 + i] = out[i * 16 + j];
|
||||
|
||||
idct16_cols_add_blk_dspr2(temp_in, dest, pitch);
|
||||
break;
|
||||
}
|
||||
case ADST_ADST: // ADST in both directions
|
||||
{
|
||||
int16_t temp_in[16];
|
||||
|
||||
for (i = 0; i < 16; ++i) {
|
||||
/* prefetch row */
|
||||
prefetch_load((const uint8_t *)(input + 16));
|
||||
|
||||
iadst16_dspr2(input, outptr);
|
||||
input += 16;
|
||||
outptr += 16;
|
||||
}
|
||||
|
||||
for (i = 0; i < 16; ++i) {
|
||||
for (j = 0; j < 16; ++j) temp_in[j] = out[j * 16 + i];
|
||||
iadst16_dspr2(temp_in, temp_out);
|
||||
for (j = 0; j < 16; ++j)
|
||||
dest[j * pitch + i] = clip_pixel(ROUND_POWER_OF_TWO(temp_out[j], 6) +
|
||||
dest[j * pitch + i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: printf("vp9_short_iht16x16_add_dspr2 : Invalid tx_type\n"); break;
|
||||
}
|
||||
}
|
||||
#endif // #if HAVE_DSPR2
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* 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 <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "./vpx_config.h"
|
||||
#include "./vp9_rtcd.h"
|
||||
#include "vp9/common/vp9_common.h"
|
||||
#include "vp9/common/vp9_blockd.h"
|
||||
#include "vp9/common/vp9_idct.h"
|
||||
#include "vpx_dsp/mips/inv_txfm_dspr2.h"
|
||||
#include "vpx_dsp/txfm_common.h"
|
||||
#include "vpx_ports/mem.h"
|
||||
|
||||
#if HAVE_DSPR2
|
||||
void vp9_iht4x4_16_add_dspr2(const int16_t *input, uint8_t *dest, int stride,
|
||||
int tx_type) {
|
||||
int i, j;
|
||||
DECLARE_ALIGNED(32, int16_t, out[4 * 4]);
|
||||
int16_t *outptr = out;
|
||||
int16_t temp_in[4 * 4], temp_out[4];
|
||||
uint32_t pos = 45;
|
||||
|
||||
/* bit positon for extract from acc */
|
||||
__asm__ __volatile__("wrdsp %[pos], 1 \n\t"
|
||||
:
|
||||
: [pos] "r"(pos));
|
||||
|
||||
switch (tx_type) {
|
||||
case DCT_DCT: // DCT in both horizontal and vertical
|
||||
vpx_idct4_rows_dspr2(input, outptr);
|
||||
vpx_idct4_columns_add_blk_dspr2(&out[0], dest, stride);
|
||||
break;
|
||||
case ADST_DCT: // ADST in vertical, DCT in horizontal
|
||||
vpx_idct4_rows_dspr2(input, outptr);
|
||||
|
||||
outptr = out;
|
||||
|
||||
for (i = 0; i < 4; ++i) {
|
||||
iadst4_dspr2(outptr, temp_out);
|
||||
|
||||
for (j = 0; j < 4; ++j)
|
||||
dest[j * stride + i] = clip_pixel(ROUND_POWER_OF_TWO(temp_out[j], 4) +
|
||||
dest[j * stride + i]);
|
||||
|
||||
outptr += 4;
|
||||
}
|
||||
break;
|
||||
case DCT_ADST: // DCT in vertical, ADST in horizontal
|
||||
for (i = 0; i < 4; ++i) {
|
||||
iadst4_dspr2(input, outptr);
|
||||
input += 4;
|
||||
outptr += 4;
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; ++i) {
|
||||
for (j = 0; j < 4; ++j) {
|
||||
temp_in[i * 4 + j] = out[j * 4 + i];
|
||||
}
|
||||
}
|
||||
vpx_idct4_columns_add_blk_dspr2(&temp_in[0], dest, stride);
|
||||
break;
|
||||
case ADST_ADST: // ADST in both directions
|
||||
for (i = 0; i < 4; ++i) {
|
||||
iadst4_dspr2(input, outptr);
|
||||
input += 4;
|
||||
outptr += 4;
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; ++i) {
|
||||
for (j = 0; j < 4; ++j) temp_in[j] = out[j * 4 + i];
|
||||
iadst4_dspr2(temp_in, temp_out);
|
||||
|
||||
for (j = 0; j < 4; ++j)
|
||||
dest[j * stride + i] = clip_pixel(ROUND_POWER_OF_TWO(temp_out[j], 4) +
|
||||
dest[j * stride + i]);
|
||||
}
|
||||
break;
|
||||
default: printf("vp9_short_iht4x4_add_dspr2 : Invalid tx_type\n"); break;
|
||||
}
|
||||
}
|
||||
#endif // #if HAVE_DSPR2
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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 <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "./vpx_config.h"
|
||||
#include "./vp9_rtcd.h"
|
||||
#include "vp9/common/vp9_common.h"
|
||||
#include "vp9/common/vp9_blockd.h"
|
||||
#include "vpx_dsp/mips/inv_txfm_dspr2.h"
|
||||
#include "vpx_dsp/txfm_common.h"
|
||||
#include "vpx_ports/mem.h"
|
||||
|
||||
#if HAVE_DSPR2
|
||||
void vp9_iht8x8_64_add_dspr2(const int16_t *input, uint8_t *dest, int stride,
|
||||
int tx_type) {
|
||||
int i, j;
|
||||
DECLARE_ALIGNED(32, int16_t, out[8 * 8]);
|
||||
int16_t *outptr = out;
|
||||
int16_t temp_in[8 * 8], temp_out[8];
|
||||
uint32_t pos = 45;
|
||||
|
||||
/* bit positon for extract from acc */
|
||||
__asm__ __volatile__("wrdsp %[pos], 1 \n\t" : : [pos] "r"(pos));
|
||||
|
||||
switch (tx_type) {
|
||||
case DCT_DCT: // DCT in both horizontal and vertical
|
||||
idct8_rows_dspr2(input, outptr, 8);
|
||||
idct8_columns_add_blk_dspr2(&out[0], dest, stride);
|
||||
break;
|
||||
case ADST_DCT: // ADST in vertical, DCT in horizontal
|
||||
idct8_rows_dspr2(input, outptr, 8);
|
||||
|
||||
for (i = 0; i < 8; ++i) {
|
||||
iadst8_dspr2(&out[i * 8], temp_out);
|
||||
|
||||
for (j = 0; j < 8; ++j)
|
||||
dest[j * stride + i] = clip_pixel(ROUND_POWER_OF_TWO(temp_out[j], 5) +
|
||||
dest[j * stride + i]);
|
||||
}
|
||||
break;
|
||||
case DCT_ADST: // DCT in vertical, ADST in horizontal
|
||||
for (i = 0; i < 8; ++i) {
|
||||
iadst8_dspr2(input, outptr);
|
||||
input += 8;
|
||||
outptr += 8;
|
||||
}
|
||||
|
||||
for (i = 0; i < 8; ++i) {
|
||||
for (j = 0; j < 8; ++j) {
|
||||
temp_in[i * 8 + j] = out[j * 8 + i];
|
||||
}
|
||||
}
|
||||
idct8_columns_add_blk_dspr2(&temp_in[0], dest, stride);
|
||||
break;
|
||||
case ADST_ADST: // ADST in both directions
|
||||
for (i = 0; i < 8; ++i) {
|
||||
iadst8_dspr2(input, outptr);
|
||||
input += 8;
|
||||
outptr += 8;
|
||||
}
|
||||
|
||||
for (i = 0; i < 8; ++i) {
|
||||
for (j = 0; j < 8; ++j) temp_in[j] = out[j * 8 + i];
|
||||
|
||||
iadst8_dspr2(temp_in, temp_out);
|
||||
|
||||
for (j = 0; j < 8; ++j)
|
||||
dest[j * stride + i] = clip_pixel(ROUND_POWER_OF_TWO(temp_out[j], 5) +
|
||||
dest[j * stride + i]);
|
||||
}
|
||||
break;
|
||||
default: printf("vp9_short_iht8x8_add_dspr2 : Invalid tx_type\n"); break;
|
||||
}
|
||||
}
|
||||
#endif // #if HAVE_DSPR2
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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 <assert.h>
|
||||
|
||||
#include "./vp9_rtcd.h"
|
||||
#include "vp9/common/vp9_enums.h"
|
||||
#include "vpx_dsp/mips/inv_txfm_msa.h"
|
||||
|
||||
void vp9_iht16x16_256_add_msa(const int16_t *input, uint8_t *dst,
|
||||
int32_t dst_stride, int32_t tx_type) {
|
||||
int32_t i;
|
||||
DECLARE_ALIGNED(32, int16_t, out[16 * 16]);
|
||||
int16_t *out_ptr = &out[0];
|
||||
|
||||
switch (tx_type) {
|
||||
case DCT_DCT:
|
||||
/* transform rows */
|
||||
for (i = 0; i < 2; ++i) {
|
||||
/* process 16 * 8 block */
|
||||
vpx_idct16_1d_rows_msa((input + (i << 7)), (out_ptr + (i << 7)));
|
||||
}
|
||||
|
||||
/* transform columns */
|
||||
for (i = 0; i < 2; ++i) {
|
||||
/* process 8 * 16 block */
|
||||
vpx_idct16_1d_columns_addblk_msa((out_ptr + (i << 3)), (dst + (i << 3)),
|
||||
dst_stride);
|
||||
}
|
||||
break;
|
||||
case ADST_DCT:
|
||||
/* transform rows */
|
||||
for (i = 0; i < 2; ++i) {
|
||||
/* process 16 * 8 block */
|
||||
vpx_idct16_1d_rows_msa((input + (i << 7)), (out_ptr + (i << 7)));
|
||||
}
|
||||
|
||||
/* transform columns */
|
||||
for (i = 0; i < 2; ++i) {
|
||||
vpx_iadst16_1d_columns_addblk_msa((out_ptr + (i << 3)),
|
||||
(dst + (i << 3)), dst_stride);
|
||||
}
|
||||
break;
|
||||
case DCT_ADST:
|
||||
/* transform rows */
|
||||
for (i = 0; i < 2; ++i) {
|
||||
/* process 16 * 8 block */
|
||||
vpx_iadst16_1d_rows_msa((input + (i << 7)), (out_ptr + (i << 7)));
|
||||
}
|
||||
|
||||
/* transform columns */
|
||||
for (i = 0; i < 2; ++i) {
|
||||
/* process 8 * 16 block */
|
||||
vpx_idct16_1d_columns_addblk_msa((out_ptr + (i << 3)), (dst + (i << 3)),
|
||||
dst_stride);
|
||||
}
|
||||
break;
|
||||
case ADST_ADST:
|
||||
/* transform rows */
|
||||
for (i = 0; i < 2; ++i) {
|
||||
/* process 16 * 8 block */
|
||||
vpx_iadst16_1d_rows_msa((input + (i << 7)), (out_ptr + (i << 7)));
|
||||
}
|
||||
|
||||
/* transform columns */
|
||||
for (i = 0; i < 2; ++i) {
|
||||
vpx_iadst16_1d_columns_addblk_msa((out_ptr + (i << 3)),
|
||||
(dst + (i << 3)), dst_stride);
|
||||
}
|
||||
break;
|
||||
default: assert(0); break;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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 <assert.h>
|
||||
|
||||
#include "./vp9_rtcd.h"
|
||||
#include "vp9/common/vp9_enums.h"
|
||||
#include "vpx_dsp/mips/inv_txfm_msa.h"
|
||||
|
||||
void vp9_iht4x4_16_add_msa(const int16_t *input, uint8_t *dst,
|
||||
int32_t dst_stride, int32_t tx_type) {
|
||||
v8i16 in0, in1, in2, in3;
|
||||
|
||||
/* load vector elements of 4x4 block */
|
||||
LD4x4_SH(input, in0, in1, in2, in3);
|
||||
TRANSPOSE4x4_SH_SH(in0, in1, in2, in3, in0, in1, in2, in3);
|
||||
|
||||
switch (tx_type) {
|
||||
case DCT_DCT:
|
||||
/* DCT in horizontal */
|
||||
VP9_IDCT4x4(in0, in1, in2, in3, in0, in1, in2, in3);
|
||||
/* DCT in vertical */
|
||||
TRANSPOSE4x4_SH_SH(in0, in1, in2, in3, in0, in1, in2, in3);
|
||||
VP9_IDCT4x4(in0, in1, in2, in3, in0, in1, in2, in3);
|
||||
break;
|
||||
case ADST_DCT:
|
||||
/* DCT in horizontal */
|
||||
VP9_IDCT4x4(in0, in1, in2, in3, in0, in1, in2, in3);
|
||||
/* ADST in vertical */
|
||||
TRANSPOSE4x4_SH_SH(in0, in1, in2, in3, in0, in1, in2, in3);
|
||||
VP9_IADST4x4(in0, in1, in2, in3, in0, in1, in2, in3);
|
||||
break;
|
||||
case DCT_ADST:
|
||||
/* ADST in horizontal */
|
||||
VP9_IADST4x4(in0, in1, in2, in3, in0, in1, in2, in3);
|
||||
/* DCT in vertical */
|
||||
TRANSPOSE4x4_SH_SH(in0, in1, in2, in3, in0, in1, in2, in3);
|
||||
VP9_IDCT4x4(in0, in1, in2, in3, in0, in1, in2, in3);
|
||||
break;
|
||||
case ADST_ADST:
|
||||
/* ADST in horizontal */
|
||||
VP9_IADST4x4(in0, in1, in2, in3, in0, in1, in2, in3);
|
||||
/* ADST in vertical */
|
||||
TRANSPOSE4x4_SH_SH(in0, in1, in2, in3, in0, in1, in2, in3);
|
||||
VP9_IADST4x4(in0, in1, in2, in3, in0, in1, in2, in3);
|
||||
break;
|
||||
default: assert(0); break;
|
||||
}
|
||||
|
||||
/* final rounding (add 2^3, divide by 2^4) and shift */
|
||||
SRARI_H4_SH(in0, in1, in2, in3, 4);
|
||||
/* add block and store 4x4 */
|
||||
ADDBLK_ST4x4_UB(in0, in1, in2, in3, dst, dst_stride);
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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 <assert.h>
|
||||
|
||||
#include "./vp9_rtcd.h"
|
||||
#include "vp9/common/vp9_enums.h"
|
||||
#include "vpx_dsp/mips/inv_txfm_msa.h"
|
||||
|
||||
void vp9_iht8x8_64_add_msa(const int16_t *input, uint8_t *dst,
|
||||
int32_t dst_stride, int32_t tx_type) {
|
||||
v8i16 in0, in1, in2, in3, in4, in5, in6, in7;
|
||||
|
||||
/* load vector elements of 8x8 block */
|
||||
LD_SH8(input, 8, in0, in1, in2, in3, in4, in5, in6, in7);
|
||||
|
||||
TRANSPOSE8x8_SH_SH(in0, in1, in2, in3, in4, in5, in6, in7, in0, in1, in2, in3,
|
||||
in4, in5, in6, in7);
|
||||
|
||||
switch (tx_type) {
|
||||
case DCT_DCT:
|
||||
/* DCT in horizontal */
|
||||
VP9_IDCT8x8_1D(in0, in1, in2, in3, in4, in5, in6, in7, in0, in1, in2, in3,
|
||||
in4, in5, in6, in7);
|
||||
/* DCT in vertical */
|
||||
TRANSPOSE8x8_SH_SH(in0, in1, in2, in3, in4, in5, in6, in7, in0, in1, in2,
|
||||
in3, in4, in5, in6, in7);
|
||||
VP9_IDCT8x8_1D(in0, in1, in2, in3, in4, in5, in6, in7, in0, in1, in2, in3,
|
||||
in4, in5, in6, in7);
|
||||
break;
|
||||
case ADST_DCT:
|
||||
/* DCT in horizontal */
|
||||
VP9_IDCT8x8_1D(in0, in1, in2, in3, in4, in5, in6, in7, in0, in1, in2, in3,
|
||||
in4, in5, in6, in7);
|
||||
/* ADST in vertical */
|
||||
TRANSPOSE8x8_SH_SH(in0, in1, in2, in3, in4, in5, in6, in7, in0, in1, in2,
|
||||
in3, in4, in5, in6, in7);
|
||||
VP9_ADST8(in0, in1, in2, in3, in4, in5, in6, in7, in0, in1, in2, in3, in4,
|
||||
in5, in6, in7);
|
||||
break;
|
||||
case DCT_ADST:
|
||||
/* ADST in horizontal */
|
||||
VP9_ADST8(in0, in1, in2, in3, in4, in5, in6, in7, in0, in1, in2, in3, in4,
|
||||
in5, in6, in7);
|
||||
/* DCT in vertical */
|
||||
TRANSPOSE8x8_SH_SH(in0, in1, in2, in3, in4, in5, in6, in7, in0, in1, in2,
|
||||
in3, in4, in5, in6, in7);
|
||||
VP9_IDCT8x8_1D(in0, in1, in2, in3, in4, in5, in6, in7, in0, in1, in2, in3,
|
||||
in4, in5, in6, in7);
|
||||
break;
|
||||
case ADST_ADST:
|
||||
/* ADST in horizontal */
|
||||
VP9_ADST8(in0, in1, in2, in3, in4, in5, in6, in7, in0, in1, in2, in3, in4,
|
||||
in5, in6, in7);
|
||||
/* ADST in vertical */
|
||||
TRANSPOSE8x8_SH_SH(in0, in1, in2, in3, in4, in5, in6, in7, in0, in1, in2,
|
||||
in3, in4, in5, in6, in7);
|
||||
VP9_ADST8(in0, in1, in2, in3, in4, in5, in6, in7, in0, in1, in2, in3, in4,
|
||||
in5, in6, in7);
|
||||
break;
|
||||
default: assert(0); break;
|
||||
}
|
||||
|
||||
/* final rounding (add 2^4, divide by 2^5) and shift */
|
||||
SRARI_H4_SH(in0, in1, in2, in3, 5);
|
||||
SRARI_H4_SH(in4, in5, in6, in7, 5);
|
||||
|
||||
/* add block and store 8x8 */
|
||||
VP9_ADDBLK_ST8x4_UB(dst, dst_stride, in0, in1, in2, in3);
|
||||
dst += (4 * dst_stride);
|
||||
VP9_ADDBLK_ST8x4_UB(dst, dst_stride, in4, in5, in6, in7);
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* 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 "./vp9_rtcd.h"
|
||||
#include "vp9/common/vp9_onyxc_int.h"
|
||||
#include "vpx_dsp/mips/macros_msa.h"
|
||||
|
||||
static void filter_by_weight8x8_msa(const uint8_t *src_ptr, int32_t src_stride,
|
||||
uint8_t *dst_ptr, int32_t dst_stride,
|
||||
int32_t src_weight) {
|
||||
int32_t dst_weight = (1 << MFQE_PRECISION) - src_weight;
|
||||
int32_t row;
|
||||
uint64_t src0_d, src1_d, dst0_d, dst1_d;
|
||||
v16i8 src0 = { 0 };
|
||||
v16i8 src1 = { 0 };
|
||||
v16i8 dst0 = { 0 };
|
||||
v16i8 dst1 = { 0 };
|
||||
v8i16 src_wt, dst_wt, res_h_r, res_h_l, src_r, src_l, dst_r, dst_l;
|
||||
|
||||
src_wt = __msa_fill_h(src_weight);
|
||||
dst_wt = __msa_fill_h(dst_weight);
|
||||
|
||||
for (row = 2; row--;) {
|
||||
LD2(src_ptr, src_stride, src0_d, src1_d);
|
||||
src_ptr += (2 * src_stride);
|
||||
LD2(dst_ptr, dst_stride, dst0_d, dst1_d);
|
||||
INSERT_D2_SB(src0_d, src1_d, src0);
|
||||
INSERT_D2_SB(dst0_d, dst1_d, dst0);
|
||||
|
||||
LD2(src_ptr, src_stride, src0_d, src1_d);
|
||||
src_ptr += (2 * src_stride);
|
||||
LD2((dst_ptr + 2 * dst_stride), dst_stride, dst0_d, dst1_d);
|
||||
INSERT_D2_SB(src0_d, src1_d, src1);
|
||||
INSERT_D2_SB(dst0_d, dst1_d, dst1);
|
||||
|
||||
UNPCK_UB_SH(src0, src_r, src_l);
|
||||
UNPCK_UB_SH(dst0, dst_r, dst_l);
|
||||
res_h_r = (src_r * src_wt);
|
||||
res_h_r += (dst_r * dst_wt);
|
||||
res_h_l = (src_l * src_wt);
|
||||
res_h_l += (dst_l * dst_wt);
|
||||
SRARI_H2_SH(res_h_r, res_h_l, MFQE_PRECISION);
|
||||
dst0 = (v16i8)__msa_pckev_b((v16i8)res_h_l, (v16i8)res_h_r);
|
||||
ST8x2_UB(dst0, dst_ptr, dst_stride);
|
||||
dst_ptr += (2 * dst_stride);
|
||||
|
||||
UNPCK_UB_SH(src1, src_r, src_l);
|
||||
UNPCK_UB_SH(dst1, dst_r, dst_l);
|
||||
res_h_r = (src_r * src_wt);
|
||||
res_h_r += (dst_r * dst_wt);
|
||||
res_h_l = (src_l * src_wt);
|
||||
res_h_l += (dst_l * dst_wt);
|
||||
SRARI_H2_SH(res_h_r, res_h_l, MFQE_PRECISION);
|
||||
dst1 = (v16i8)__msa_pckev_b((v16i8)res_h_l, (v16i8)res_h_r);
|
||||
ST8x2_UB(dst1, dst_ptr, dst_stride);
|
||||
dst_ptr += (2 * dst_stride);
|
||||
}
|
||||
}
|
||||
|
||||
static void filter_by_weight16x16_msa(const uint8_t *src_ptr,
|
||||
int32_t src_stride, uint8_t *dst_ptr,
|
||||
int32_t dst_stride, int32_t src_weight) {
|
||||
int32_t dst_weight = (1 << MFQE_PRECISION) - src_weight;
|
||||
int32_t row;
|
||||
v16i8 src0, src1, src2, src3, dst0, dst1, dst2, dst3;
|
||||
v8i16 src_wt, dst_wt, res_h_r, res_h_l, src_r, src_l, dst_r, dst_l;
|
||||
|
||||
src_wt = __msa_fill_h(src_weight);
|
||||
dst_wt = __msa_fill_h(dst_weight);
|
||||
|
||||
for (row = 4; row--;) {
|
||||
LD_SB4(src_ptr, src_stride, src0, src1, src2, src3);
|
||||
src_ptr += (4 * src_stride);
|
||||
LD_SB4(dst_ptr, dst_stride, dst0, dst1, dst2, dst3);
|
||||
|
||||
UNPCK_UB_SH(src0, src_r, src_l);
|
||||
UNPCK_UB_SH(dst0, dst_r, dst_l);
|
||||
res_h_r = (src_r * src_wt);
|
||||
res_h_r += (dst_r * dst_wt);
|
||||
res_h_l = (src_l * src_wt);
|
||||
res_h_l += (dst_l * dst_wt);
|
||||
SRARI_H2_SH(res_h_r, res_h_l, MFQE_PRECISION);
|
||||
PCKEV_ST_SB(res_h_r, res_h_l, dst_ptr);
|
||||
dst_ptr += dst_stride;
|
||||
|
||||
UNPCK_UB_SH(src1, src_r, src_l);
|
||||
UNPCK_UB_SH(dst1, dst_r, dst_l);
|
||||
res_h_r = (src_r * src_wt);
|
||||
res_h_r += (dst_r * dst_wt);
|
||||
res_h_l = (src_l * src_wt);
|
||||
res_h_l += (dst_l * dst_wt);
|
||||
SRARI_H2_SH(res_h_r, res_h_l, MFQE_PRECISION);
|
||||
PCKEV_ST_SB(res_h_r, res_h_l, dst_ptr);
|
||||
dst_ptr += dst_stride;
|
||||
|
||||
UNPCK_UB_SH(src2, src_r, src_l);
|
||||
UNPCK_UB_SH(dst2, dst_r, dst_l);
|
||||
res_h_r = (src_r * src_wt);
|
||||
res_h_r += (dst_r * dst_wt);
|
||||
res_h_l = (src_l * src_wt);
|
||||
res_h_l += (dst_l * dst_wt);
|
||||
SRARI_H2_SH(res_h_r, res_h_l, MFQE_PRECISION);
|
||||
PCKEV_ST_SB(res_h_r, res_h_l, dst_ptr);
|
||||
dst_ptr += dst_stride;
|
||||
|
||||
UNPCK_UB_SH(src3, src_r, src_l);
|
||||
UNPCK_UB_SH(dst3, dst_r, dst_l);
|
||||
res_h_r = (src_r * src_wt);
|
||||
res_h_r += (dst_r * dst_wt);
|
||||
res_h_l = (src_l * src_wt);
|
||||
res_h_l += (dst_l * dst_wt);
|
||||
SRARI_H2_SH(res_h_r, res_h_l, MFQE_PRECISION);
|
||||
PCKEV_ST_SB(res_h_r, res_h_l, dst_ptr);
|
||||
dst_ptr += dst_stride;
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_filter_by_weight8x8_msa(const uint8_t *src, int src_stride,
|
||||
uint8_t *dst, int dst_stride, int src_weight) {
|
||||
filter_by_weight8x8_msa(src, src_stride, dst, dst_stride, src_weight);
|
||||
}
|
||||
|
||||
void vp9_filter_by_weight16x16_msa(const uint8_t *src, int src_stride,
|
||||
uint8_t *dst, int dst_stride,
|
||||
int src_weight) {
|
||||
filter_by_weight16x16_msa(src, src_stride, dst, dst_stride, src_weight);
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (c) 2018 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_rtcd.h"
|
||||
#include "vpx_dsp/vpx_dsp_common.h"
|
||||
#include "vpx_dsp/ppc/inv_txfm_vsx.h"
|
||||
#include "vpx_dsp/ppc/bitdepth_conversion_vsx.h"
|
||||
|
||||
#include "vp9/common/vp9_enums.h"
|
||||
|
||||
void vp9_iht4x4_16_add_vsx(const tran_low_t *input, uint8_t *dest, int stride,
|
||||
int tx_type) {
|
||||
int16x8_t in[2], out[2];
|
||||
|
||||
in[0] = load_tran_low(0, input);
|
||||
in[1] = load_tran_low(8 * sizeof(*input), input);
|
||||
|
||||
switch (tx_type) {
|
||||
case DCT_DCT:
|
||||
vpx_idct4_vsx(in, out);
|
||||
vpx_idct4_vsx(out, in);
|
||||
break;
|
||||
case ADST_DCT:
|
||||
vpx_idct4_vsx(in, out);
|
||||
vp9_iadst4_vsx(out, in);
|
||||
break;
|
||||
case DCT_ADST:
|
||||
vp9_iadst4_vsx(in, out);
|
||||
vpx_idct4_vsx(out, in);
|
||||
break;
|
||||
default:
|
||||
assert(tx_type == ADST_ADST);
|
||||
vp9_iadst4_vsx(in, out);
|
||||
vp9_iadst4_vsx(out, in);
|
||||
break;
|
||||
}
|
||||
|
||||
vpx_round_store4x4_vsx(in, out, dest, stride);
|
||||
}
|
||||
|
||||
void vp9_iht8x8_64_add_vsx(const tran_low_t *input, uint8_t *dest, int stride,
|
||||
int tx_type) {
|
||||
int16x8_t in[8], out[8];
|
||||
|
||||
// load input data
|
||||
in[0] = load_tran_low(0, input);
|
||||
in[1] = load_tran_low(8 * sizeof(*input), input);
|
||||
in[2] = load_tran_low(2 * 8 * sizeof(*input), input);
|
||||
in[3] = load_tran_low(3 * 8 * sizeof(*input), input);
|
||||
in[4] = load_tran_low(4 * 8 * sizeof(*input), input);
|
||||
in[5] = load_tran_low(5 * 8 * sizeof(*input), input);
|
||||
in[6] = load_tran_low(6 * 8 * sizeof(*input), input);
|
||||
in[7] = load_tran_low(7 * 8 * sizeof(*input), input);
|
||||
|
||||
switch (tx_type) {
|
||||
case DCT_DCT:
|
||||
vpx_idct8_vsx(in, out);
|
||||
vpx_idct8_vsx(out, in);
|
||||
break;
|
||||
case ADST_DCT:
|
||||
vpx_idct8_vsx(in, out);
|
||||
vp9_iadst8_vsx(out, in);
|
||||
break;
|
||||
case DCT_ADST:
|
||||
vp9_iadst8_vsx(in, out);
|
||||
vpx_idct8_vsx(out, in);
|
||||
break;
|
||||
default:
|
||||
assert(tx_type == ADST_ADST);
|
||||
vp9_iadst8_vsx(in, out);
|
||||
vp9_iadst8_vsx(out, in);
|
||||
break;
|
||||
}
|
||||
|
||||
vpx_round_store8x8_vsx(in, dest, stride);
|
||||
}
|
||||
|
||||
void vp9_iht16x16_256_add_vsx(const tran_low_t *input, uint8_t *dest,
|
||||
int stride, int tx_type) {
|
||||
int16x8_t in0[16], in1[16];
|
||||
|
||||
LOAD_INPUT16(load_tran_low, input, 0, 8 * sizeof(*input), in0);
|
||||
LOAD_INPUT16(load_tran_low, input, 8 * 8 * 2 * sizeof(*input),
|
||||
8 * sizeof(*input), in1);
|
||||
|
||||
switch (tx_type) {
|
||||
case DCT_DCT:
|
||||
vpx_idct16_vsx(in0, in1);
|
||||
vpx_idct16_vsx(in0, in1);
|
||||
break;
|
||||
case ADST_DCT:
|
||||
vpx_idct16_vsx(in0, in1);
|
||||
vpx_iadst16_vsx(in0, in1);
|
||||
break;
|
||||
case DCT_ADST:
|
||||
vpx_iadst16_vsx(in0, in1);
|
||||
vpx_idct16_vsx(in0, in1);
|
||||
break;
|
||||
default:
|
||||
assert(tx_type == ADST_ADST);
|
||||
vpx_iadst16_vsx(in0, in1);
|
||||
vpx_iadst16_vsx(in0, in1);
|
||||
break;
|
||||
}
|
||||
|
||||
vpx_round_store16x16_vsx(in0, in1, dest, stride);
|
||||
}
|
||||
@@ -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 "./vpx_config.h"
|
||||
#include "vpx_mem/vpx_mem.h"
|
||||
|
||||
#include "vp9/common/vp9_alloccommon.h"
|
||||
#include "vp9/common/vp9_blockd.h"
|
||||
#include "vp9/common/vp9_entropymode.h"
|
||||
#include "vp9/common/vp9_entropymv.h"
|
||||
#include "vp9/common/vp9_onyxc_int.h"
|
||||
|
||||
void vp9_set_mi_size(int *mi_rows, int *mi_cols, int *mi_stride, int width,
|
||||
int height) {
|
||||
const int aligned_width = ALIGN_POWER_OF_TWO(width, MI_SIZE_LOG2);
|
||||
const int aligned_height = ALIGN_POWER_OF_TWO(height, MI_SIZE_LOG2);
|
||||
*mi_cols = aligned_width >> MI_SIZE_LOG2;
|
||||
*mi_rows = aligned_height >> MI_SIZE_LOG2;
|
||||
*mi_stride = calc_mi_size(*mi_cols);
|
||||
}
|
||||
|
||||
void vp9_set_mb_size(int *mb_rows, int *mb_cols, int *mb_num, int mi_rows,
|
||||
int mi_cols) {
|
||||
*mb_cols = (mi_cols + 1) >> 1;
|
||||
*mb_rows = (mi_rows + 1) >> 1;
|
||||
*mb_num = (*mb_rows) * (*mb_cols);
|
||||
}
|
||||
|
||||
void vp9_set_mb_mi(VP9_COMMON *cm, int width, int height) {
|
||||
vp9_set_mi_size(&cm->mi_rows, &cm->mi_cols, &cm->mi_stride, width, height);
|
||||
vp9_set_mb_size(&cm->mb_rows, &cm->mb_cols, &cm->MBs, cm->mi_rows,
|
||||
cm->mi_cols);
|
||||
}
|
||||
|
||||
static int alloc_seg_map(VP9_COMMON *cm, int seg_map_size) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_PING_PONG_BUFFERS; ++i) {
|
||||
cm->seg_map_array[i] = (uint8_t *)vpx_calloc(seg_map_size, 1);
|
||||
if (cm->seg_map_array[i] == NULL) return 1;
|
||||
}
|
||||
cm->seg_map_alloc_size = seg_map_size;
|
||||
|
||||
// Init the index.
|
||||
cm->seg_map_idx = 0;
|
||||
cm->prev_seg_map_idx = 1;
|
||||
|
||||
cm->current_frame_seg_map = cm->seg_map_array[cm->seg_map_idx];
|
||||
cm->last_frame_seg_map = cm->seg_map_array[cm->prev_seg_map_idx];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void free_seg_map(VP9_COMMON *cm) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_PING_PONG_BUFFERS; ++i) {
|
||||
vpx_free(cm->seg_map_array[i]);
|
||||
cm->seg_map_array[i] = NULL;
|
||||
}
|
||||
|
||||
cm->current_frame_seg_map = NULL;
|
||||
cm->last_frame_seg_map = NULL;
|
||||
}
|
||||
|
||||
void vp9_free_ref_frame_buffers(BufferPool *pool) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < FRAME_BUFFERS; ++i) {
|
||||
if (!pool->frame_bufs[i].released &&
|
||||
pool->frame_bufs[i].raw_frame_buffer.data != NULL) {
|
||||
pool->release_fb_cb(pool->cb_priv, &pool->frame_bufs[i].raw_frame_buffer);
|
||||
pool->frame_bufs[i].ref_count = 0;
|
||||
pool->frame_bufs[i].released = 1;
|
||||
}
|
||||
vpx_free(pool->frame_bufs[i].mvs);
|
||||
pool->frame_bufs[i].mvs = NULL;
|
||||
vpx_free_frame_buffer(&pool->frame_bufs[i].buf);
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_free_postproc_buffers(VP9_COMMON *cm) {
|
||||
#if CONFIG_VP9_POSTPROC
|
||||
vpx_free_frame_buffer(&cm->post_proc_buffer);
|
||||
vpx_free_frame_buffer(&cm->post_proc_buffer_int);
|
||||
vpx_free(cm->postproc_state.limits);
|
||||
cm->postproc_state.limits = NULL;
|
||||
vpx_free(cm->postproc_state.generated_noise);
|
||||
cm->postproc_state.generated_noise = NULL;
|
||||
#else
|
||||
(void)cm;
|
||||
#endif
|
||||
}
|
||||
|
||||
void vp9_free_context_buffers(VP9_COMMON *cm) {
|
||||
cm->free_mi(cm);
|
||||
free_seg_map(cm);
|
||||
vpx_free(cm->above_context);
|
||||
cm->above_context = NULL;
|
||||
vpx_free(cm->above_seg_context);
|
||||
cm->above_seg_context = NULL;
|
||||
vpx_free(cm->lf.lfm);
|
||||
cm->lf.lfm = NULL;
|
||||
}
|
||||
|
||||
int vp9_alloc_loop_filter(VP9_COMMON *cm) {
|
||||
vpx_free(cm->lf.lfm);
|
||||
// Each lfm holds bit masks for all the 8x8 blocks in a 64x64 region. The
|
||||
// stride and rows are rounded up / truncated to a multiple of 8.
|
||||
cm->lf.lfm_stride = (cm->mi_cols + (MI_BLOCK_SIZE - 1)) >> 3;
|
||||
cm->lf.lfm = (LOOP_FILTER_MASK *)vpx_calloc(
|
||||
((cm->mi_rows + (MI_BLOCK_SIZE - 1)) >> 3) * cm->lf.lfm_stride,
|
||||
sizeof(*cm->lf.lfm));
|
||||
if (!cm->lf.lfm) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vp9_alloc_context_buffers(VP9_COMMON *cm, int width, int height) {
|
||||
int new_mi_size;
|
||||
|
||||
vp9_set_mb_mi(cm, width, height);
|
||||
new_mi_size = cm->mi_stride * calc_mi_size(cm->mi_rows);
|
||||
if (cm->mi_alloc_size < new_mi_size) {
|
||||
cm->free_mi(cm);
|
||||
if (cm->alloc_mi(cm, new_mi_size)) goto fail;
|
||||
}
|
||||
|
||||
if (cm->seg_map_alloc_size < cm->mi_rows * cm->mi_cols) {
|
||||
// Create the segmentation map structure and set to 0.
|
||||
free_seg_map(cm);
|
||||
if (alloc_seg_map(cm, cm->mi_rows * cm->mi_cols)) goto fail;
|
||||
}
|
||||
|
||||
if (cm->above_context_alloc_cols < cm->mi_cols) {
|
||||
vpx_free(cm->above_context);
|
||||
cm->above_context = (ENTROPY_CONTEXT *)vpx_calloc(
|
||||
2 * mi_cols_aligned_to_sb(cm->mi_cols) * MAX_MB_PLANE,
|
||||
sizeof(*cm->above_context));
|
||||
if (!cm->above_context) goto fail;
|
||||
|
||||
vpx_free(cm->above_seg_context);
|
||||
cm->above_seg_context = (PARTITION_CONTEXT *)vpx_calloc(
|
||||
mi_cols_aligned_to_sb(cm->mi_cols), sizeof(*cm->above_seg_context));
|
||||
if (!cm->above_seg_context) goto fail;
|
||||
cm->above_context_alloc_cols = cm->mi_cols;
|
||||
}
|
||||
|
||||
if (vp9_alloc_loop_filter(cm)) goto fail;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
// clear the mi_* values to force a realloc on resync
|
||||
vp9_set_mb_mi(cm, 0, 0);
|
||||
vp9_free_context_buffers(cm);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void vp9_remove_common(VP9_COMMON *cm) {
|
||||
#if CONFIG_VP9_POSTPROC
|
||||
vp9_free_postproc_buffers(cm);
|
||||
#endif
|
||||
vp9_free_context_buffers(cm);
|
||||
|
||||
vpx_free(cm->fc);
|
||||
cm->fc = NULL;
|
||||
vpx_free(cm->frame_contexts);
|
||||
cm->frame_contexts = NULL;
|
||||
}
|
||||
|
||||
void vp9_init_context_buffers(VP9_COMMON *cm) {
|
||||
cm->setup_mi(cm);
|
||||
if (cm->last_frame_seg_map)
|
||||
memset(cm->last_frame_seg_map, 0, cm->mi_rows * cm->mi_cols);
|
||||
}
|
||||
|
||||
void vp9_swap_current_and_last_seg_map(VP9_COMMON *cm) {
|
||||
// Swap indices.
|
||||
const int tmp = cm->seg_map_idx;
|
||||
cm->seg_map_idx = cm->prev_seg_map_idx;
|
||||
cm->prev_seg_map_idx = tmp;
|
||||
|
||||
cm->current_frame_seg_map = cm->seg_map_array[cm->seg_map_idx];
|
||||
cm->last_frame_seg_map = cm->seg_map_array[cm->prev_seg_map_idx];
|
||||
}
|
||||
@@ -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 VPX_VP9_COMMON_VP9_ALLOCCOMMON_H_
|
||||
#define VPX_VP9_COMMON_VP9_ALLOCCOMMON_H_
|
||||
|
||||
#define INVALID_IDX (-1) // Invalid buffer index.
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct VP9Common;
|
||||
struct BufferPool;
|
||||
|
||||
void vp9_remove_common(struct VP9Common *cm);
|
||||
|
||||
int vp9_alloc_loop_filter(struct VP9Common *cm);
|
||||
int vp9_alloc_context_buffers(struct VP9Common *cm, int width, int height);
|
||||
void vp9_init_context_buffers(struct VP9Common *cm);
|
||||
void vp9_free_context_buffers(struct VP9Common *cm);
|
||||
|
||||
void vp9_free_ref_frame_buffers(struct BufferPool *pool);
|
||||
void vp9_free_postproc_buffers(struct VP9Common *cm);
|
||||
|
||||
int vp9_alloc_state_buffers(struct VP9Common *cm, int width, int height);
|
||||
void vp9_free_state_buffers(struct VP9Common *cm);
|
||||
|
||||
void vp9_set_mi_size(int *mi_rows, int *mi_cols, int *mi_stride, int width,
|
||||
int height);
|
||||
void vp9_set_mb_size(int *mb_rows, int *mb_cols, int *mb_num, int mi_rows,
|
||||
int mi_cols);
|
||||
|
||||
void vp9_set_mb_mi(struct VP9Common *cm, int width, int height);
|
||||
|
||||
void vp9_swap_current_and_last_seg_map(struct VP9Common *cm);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_COMMON_VP9_ALLOCCOMMON_H_
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* 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/common/vp9_blockd.h"
|
||||
|
||||
PREDICTION_MODE vp9_left_block_mode(const MODE_INFO *cur_mi,
|
||||
const MODE_INFO *left_mi, int b) {
|
||||
if (b == 0 || b == 2) {
|
||||
if (!left_mi || is_inter_block(left_mi)) return DC_PRED;
|
||||
|
||||
return get_y_mode(left_mi, b + 1);
|
||||
} else {
|
||||
assert(b == 1 || b == 3);
|
||||
return cur_mi->bmi[b - 1].as_mode;
|
||||
}
|
||||
}
|
||||
|
||||
PREDICTION_MODE vp9_above_block_mode(const MODE_INFO *cur_mi,
|
||||
const MODE_INFO *above_mi, int b) {
|
||||
if (b == 0 || b == 1) {
|
||||
if (!above_mi || is_inter_block(above_mi)) return DC_PRED;
|
||||
|
||||
return get_y_mode(above_mi, b + 2);
|
||||
} else {
|
||||
assert(b == 2 || b == 3);
|
||||
return cur_mi->bmi[b - 2].as_mode;
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_foreach_transformed_block_in_plane(
|
||||
const MACROBLOCKD *const xd, BLOCK_SIZE bsize, int plane,
|
||||
foreach_transformed_block_visitor visit, void *arg) {
|
||||
const struct macroblockd_plane *const pd = &xd->plane[plane];
|
||||
const MODE_INFO *mi = xd->mi[0];
|
||||
// block and transform sizes, in number of 4x4 blocks log 2 ("*_b")
|
||||
// 4x4=0, 8x8=2, 16x16=4, 32x32=6, 64x64=8
|
||||
// transform size varies per plane, look it up in a common way.
|
||||
const TX_SIZE tx_size = plane ? get_uv_tx_size(mi, pd) : mi->tx_size;
|
||||
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 int step = 1 << (tx_size << 1);
|
||||
int i = 0, r, c;
|
||||
|
||||
// If mb_to_right_edge is < 0 we are in a situation in which
|
||||
// the current block size extends into the UMV and we won't
|
||||
// visit the sub blocks that are wholly within the UMV.
|
||||
const int max_blocks_wide =
|
||||
num_4x4_w + (xd->mb_to_right_edge >= 0
|
||||
? 0
|
||||
: xd->mb_to_right_edge >> (5 + pd->subsampling_x));
|
||||
const int max_blocks_high =
|
||||
num_4x4_h + (xd->mb_to_bottom_edge >= 0
|
||||
? 0
|
||||
: xd->mb_to_bottom_edge >> (5 + pd->subsampling_y));
|
||||
const int extra_step = ((num_4x4_w - max_blocks_wide) >> tx_size) * step;
|
||||
|
||||
// Keep track of the row and column of the blocks we use so that we know
|
||||
// if we are in the unrestricted motion border.
|
||||
for (r = 0; r < max_blocks_high; r += (1 << tx_size)) {
|
||||
// Skip visiting the sub blocks that are wholly within the UMV.
|
||||
for (c = 0; c < max_blocks_wide; c += (1 << tx_size)) {
|
||||
visit(plane, i, r, c, plane_bsize, tx_size, arg);
|
||||
i += step;
|
||||
}
|
||||
i += extra_step;
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_foreach_transformed_block(const MACROBLOCKD *const xd,
|
||||
BLOCK_SIZE bsize,
|
||||
foreach_transformed_block_visitor visit,
|
||||
void *arg) {
|
||||
int plane;
|
||||
|
||||
for (plane = 0; plane < MAX_MB_PLANE; ++plane)
|
||||
vp9_foreach_transformed_block_in_plane(xd, bsize, plane, visit, arg);
|
||||
}
|
||||
|
||||
void vp9_set_contexts(const MACROBLOCKD *xd, struct macroblockd_plane *pd,
|
||||
BLOCK_SIZE plane_bsize, TX_SIZE tx_size, int has_eob,
|
||||
int aoff, int loff) {
|
||||
ENTROPY_CONTEXT *const a = pd->above_context + aoff;
|
||||
ENTROPY_CONTEXT *const l = pd->left_context + loff;
|
||||
const int tx_size_in_blocks = 1 << tx_size;
|
||||
|
||||
// above
|
||||
if (has_eob && xd->mb_to_right_edge < 0) {
|
||||
int i;
|
||||
const int blocks_wide = num_4x4_blocks_wide_lookup[plane_bsize] +
|
||||
(xd->mb_to_right_edge >> (5 + pd->subsampling_x));
|
||||
int above_contexts = tx_size_in_blocks;
|
||||
if (above_contexts + aoff > blocks_wide)
|
||||
above_contexts = blocks_wide - aoff;
|
||||
|
||||
for (i = 0; i < above_contexts; ++i) a[i] = has_eob;
|
||||
for (i = above_contexts; i < tx_size_in_blocks; ++i) a[i] = 0;
|
||||
} else {
|
||||
memset(a, has_eob, sizeof(ENTROPY_CONTEXT) * tx_size_in_blocks);
|
||||
}
|
||||
|
||||
// left
|
||||
if (has_eob && xd->mb_to_bottom_edge < 0) {
|
||||
int i;
|
||||
const int blocks_high = num_4x4_blocks_high_lookup[plane_bsize] +
|
||||
(xd->mb_to_bottom_edge >> (5 + pd->subsampling_y));
|
||||
int left_contexts = tx_size_in_blocks;
|
||||
if (left_contexts + loff > blocks_high) left_contexts = blocks_high - loff;
|
||||
|
||||
for (i = 0; i < left_contexts; ++i) l[i] = has_eob;
|
||||
for (i = left_contexts; i < tx_size_in_blocks; ++i) l[i] = 0;
|
||||
} else {
|
||||
memset(l, has_eob, sizeof(ENTROPY_CONTEXT) * tx_size_in_blocks);
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_setup_block_planes(MACROBLOCKD *xd, int ss_x, int ss_y) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_MB_PLANE; i++) {
|
||||
xd->plane[i].subsampling_x = i ? ss_x : 0;
|
||||
xd->plane[i].subsampling_y = i ? ss_y : 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,316 @@
|
||||
/*
|
||||
* 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 VPX_VP9_COMMON_VP9_BLOCKD_H_
|
||||
#define VPX_VP9_COMMON_VP9_BLOCKD_H_
|
||||
|
||||
#include "./vpx_config.h"
|
||||
|
||||
#include "vpx_dsp/vpx_dsp_common.h"
|
||||
#include "vpx_ports/mem.h"
|
||||
#include "vpx_scale/yv12config.h"
|
||||
|
||||
#include "vp9/common/vp9_common_data.h"
|
||||
#include "vp9/common/vp9_entropy.h"
|
||||
#include "vp9/common/vp9_entropymode.h"
|
||||
#include "vp9/common/vp9_mv.h"
|
||||
#include "vp9/common/vp9_scale.h"
|
||||
#include "vp9/common/vp9_seg_common.h"
|
||||
#include "vp9/common/vp9_tile_common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define MAX_MB_PLANE 3
|
||||
|
||||
typedef enum {
|
||||
KEY_FRAME = 0,
|
||||
INTER_FRAME = 1,
|
||||
FRAME_TYPES,
|
||||
} FRAME_TYPE;
|
||||
|
||||
static INLINE int is_inter_mode(PREDICTION_MODE mode) {
|
||||
return mode >= NEARESTMV && mode <= NEWMV;
|
||||
}
|
||||
|
||||
/* For keyframes, intra block modes are predicted by the (already decoded)
|
||||
modes for the Y blocks to the left and above us; for interframes, there
|
||||
is a single probability table. */
|
||||
|
||||
typedef struct {
|
||||
PREDICTION_MODE as_mode;
|
||||
int_mv as_mv[2]; // first, second inter predictor motion vectors
|
||||
} b_mode_info;
|
||||
|
||||
// Note that the rate-distortion optimization loop, bit-stream writer, and
|
||||
// decoder implementation modules critically rely on the defined entry values
|
||||
// specified herein. They should be refactored concurrently.
|
||||
|
||||
#define NONE (-1)
|
||||
#define INTRA_FRAME 0
|
||||
#define LAST_FRAME 1
|
||||
#define GOLDEN_FRAME 2
|
||||
#define ALTREF_FRAME 3
|
||||
#define MAX_REF_FRAMES 4
|
||||
#define MAX_INTER_REF_FRAMES 3
|
||||
|
||||
typedef int8_t MV_REFERENCE_FRAME;
|
||||
|
||||
// This structure now relates to 8x8 block regions.
|
||||
typedef struct MODE_INFO {
|
||||
// Common for both INTER and INTRA blocks
|
||||
BLOCK_SIZE sb_type;
|
||||
PREDICTION_MODE mode;
|
||||
TX_SIZE tx_size;
|
||||
int8_t skip;
|
||||
int8_t segment_id;
|
||||
int8_t seg_id_predicted; // valid only when temporal_update is enabled
|
||||
|
||||
// Only for INTRA blocks
|
||||
PREDICTION_MODE uv_mode;
|
||||
|
||||
// Only for INTER blocks
|
||||
INTERP_FILTER interp_filter;
|
||||
|
||||
// if ref_frame[idx] is equal to ALTREF_FRAME then
|
||||
// MACROBLOCKD::block_ref[idx] is an altref
|
||||
MV_REFERENCE_FRAME ref_frame[2];
|
||||
|
||||
// TODO(slavarnway): Delete and use bmi[3].as_mv[] instead.
|
||||
int_mv mv[2];
|
||||
|
||||
b_mode_info bmi[4];
|
||||
} MODE_INFO;
|
||||
|
||||
static INLINE PREDICTION_MODE get_y_mode(const MODE_INFO *mi, int block) {
|
||||
return mi->sb_type < BLOCK_8X8 ? mi->bmi[block].as_mode : mi->mode;
|
||||
}
|
||||
|
||||
static INLINE int is_inter_block(const MODE_INFO *mi) {
|
||||
return mi->ref_frame[0] > INTRA_FRAME;
|
||||
}
|
||||
|
||||
static INLINE int has_second_ref(const MODE_INFO *mi) {
|
||||
return mi->ref_frame[1] > INTRA_FRAME;
|
||||
}
|
||||
|
||||
PREDICTION_MODE vp9_left_block_mode(const MODE_INFO *cur_mi,
|
||||
const MODE_INFO *left_mi, int b);
|
||||
|
||||
PREDICTION_MODE vp9_above_block_mode(const MODE_INFO *cur_mi,
|
||||
const MODE_INFO *above_mi, int b);
|
||||
|
||||
enum mv_precision { MV_PRECISION_Q3, MV_PRECISION_Q4 };
|
||||
|
||||
struct buf_2d {
|
||||
uint8_t *buf;
|
||||
int stride;
|
||||
};
|
||||
|
||||
struct macroblockd_plane {
|
||||
tran_low_t *dqcoeff;
|
||||
int subsampling_x;
|
||||
int subsampling_y;
|
||||
struct buf_2d dst;
|
||||
struct buf_2d pre[2];
|
||||
ENTROPY_CONTEXT *above_context;
|
||||
ENTROPY_CONTEXT *left_context;
|
||||
int16_t seg_dequant[MAX_SEGMENTS][2];
|
||||
|
||||
// number of 4x4s in current block
|
||||
uint16_t n4_w, n4_h;
|
||||
// log2 of n4_w, n4_h
|
||||
uint8_t n4_wl, n4_hl;
|
||||
|
||||
// encoder
|
||||
const int16_t *dequant;
|
||||
|
||||
int *eob;
|
||||
};
|
||||
|
||||
#define BLOCK_OFFSET(x, i) ((x) + (i)*16)
|
||||
|
||||
typedef struct RefBuffer {
|
||||
// TODO(dkovalev): idx is not really required and should be removed, now it
|
||||
// is used in vp9_onyxd_if.c
|
||||
int idx;
|
||||
YV12_BUFFER_CONFIG *buf;
|
||||
struct scale_factors sf;
|
||||
} RefBuffer;
|
||||
|
||||
typedef struct macroblockd {
|
||||
struct macroblockd_plane plane[MAX_MB_PLANE];
|
||||
uint8_t bmode_blocks_wl;
|
||||
uint8_t bmode_blocks_hl;
|
||||
|
||||
FRAME_COUNTS *counts;
|
||||
TileInfo tile;
|
||||
|
||||
int mi_stride;
|
||||
|
||||
// Grid of 8x8 cells is placed over the block.
|
||||
// If some of them belong to the same mbtree-block
|
||||
// they will just have same mi[i][j] value
|
||||
MODE_INFO **mi;
|
||||
MODE_INFO *left_mi;
|
||||
MODE_INFO *above_mi;
|
||||
|
||||
unsigned int max_blocks_wide;
|
||||
unsigned int max_blocks_high;
|
||||
|
||||
const vpx_prob (*partition_probs)[PARTITION_TYPES - 1];
|
||||
|
||||
/* Distance of MB away from frame edges */
|
||||
int mb_to_left_edge;
|
||||
int mb_to_right_edge;
|
||||
int mb_to_top_edge;
|
||||
int mb_to_bottom_edge;
|
||||
|
||||
FRAME_CONTEXT *fc;
|
||||
|
||||
/* pointers to reference frames */
|
||||
const RefBuffer *block_refs[2];
|
||||
|
||||
/* pointer to current frame */
|
||||
const YV12_BUFFER_CONFIG *cur_buf;
|
||||
|
||||
ENTROPY_CONTEXT *above_context[MAX_MB_PLANE];
|
||||
ENTROPY_CONTEXT left_context[MAX_MB_PLANE][16];
|
||||
|
||||
PARTITION_CONTEXT *above_seg_context;
|
||||
PARTITION_CONTEXT left_seg_context[8];
|
||||
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
/* Bit depth: 8, 10, 12 */
|
||||
int bd;
|
||||
#endif
|
||||
|
||||
int lossless;
|
||||
int corrupted;
|
||||
|
||||
struct vpx_internal_error_info *error_info;
|
||||
|
||||
PARTITION_TYPE *partition;
|
||||
} MACROBLOCKD;
|
||||
|
||||
static INLINE PLANE_TYPE get_plane_type(int plane) {
|
||||
return (PLANE_TYPE)(plane > 0);
|
||||
}
|
||||
|
||||
static INLINE BLOCK_SIZE get_subsize(BLOCK_SIZE bsize,
|
||||
PARTITION_TYPE partition) {
|
||||
return subsize_lookup[partition][bsize];
|
||||
}
|
||||
|
||||
extern const TX_TYPE intra_mode_to_tx_type_lookup[INTRA_MODES];
|
||||
|
||||
static INLINE TX_TYPE get_tx_type(PLANE_TYPE plane_type,
|
||||
const MACROBLOCKD *xd) {
|
||||
const MODE_INFO *const mi = xd->mi[0];
|
||||
|
||||
if (plane_type != PLANE_TYPE_Y || xd->lossless || is_inter_block(mi))
|
||||
return DCT_DCT;
|
||||
|
||||
return intra_mode_to_tx_type_lookup[mi->mode];
|
||||
}
|
||||
|
||||
static INLINE TX_TYPE get_tx_type_4x4(PLANE_TYPE plane_type,
|
||||
const MACROBLOCKD *xd, int ib) {
|
||||
const MODE_INFO *const mi = xd->mi[0];
|
||||
|
||||
if (plane_type != PLANE_TYPE_Y || xd->lossless || is_inter_block(mi))
|
||||
return DCT_DCT;
|
||||
|
||||
return intra_mode_to_tx_type_lookup[get_y_mode(mi, ib)];
|
||||
}
|
||||
|
||||
void vp9_setup_block_planes(MACROBLOCKD *xd, int ss_x, int ss_y);
|
||||
|
||||
static INLINE TX_SIZE get_uv_tx_size(const MODE_INFO *mi,
|
||||
const struct macroblockd_plane *pd) {
|
||||
assert(mi->sb_type < BLOCK_8X8 ||
|
||||
ss_size_lookup[mi->sb_type][pd->subsampling_x][pd->subsampling_y] !=
|
||||
BLOCK_INVALID);
|
||||
return uv_txsize_lookup[mi->sb_type][mi->tx_size][pd->subsampling_x]
|
||||
[pd->subsampling_y];
|
||||
}
|
||||
|
||||
static INLINE BLOCK_SIZE
|
||||
get_plane_block_size(BLOCK_SIZE bsize, const struct macroblockd_plane *pd) {
|
||||
return ss_size_lookup[bsize][pd->subsampling_x][pd->subsampling_y];
|
||||
}
|
||||
|
||||
static INLINE void reset_skip_context(MACROBLOCKD *xd, BLOCK_SIZE bsize) {
|
||||
int i;
|
||||
for (i = 0; i < MAX_MB_PLANE; i++) {
|
||||
struct macroblockd_plane *const pd = &xd->plane[i];
|
||||
const BLOCK_SIZE plane_bsize = get_plane_block_size(bsize, pd);
|
||||
memset(pd->above_context, 0,
|
||||
sizeof(ENTROPY_CONTEXT) * num_4x4_blocks_wide_lookup[plane_bsize]);
|
||||
memset(pd->left_context, 0,
|
||||
sizeof(ENTROPY_CONTEXT) * num_4x4_blocks_high_lookup[plane_bsize]);
|
||||
}
|
||||
}
|
||||
|
||||
static INLINE const vpx_prob *get_y_mode_probs(const MODE_INFO *mi,
|
||||
const MODE_INFO *above_mi,
|
||||
const MODE_INFO *left_mi,
|
||||
int block) {
|
||||
const PREDICTION_MODE above = vp9_above_block_mode(mi, above_mi, block);
|
||||
const PREDICTION_MODE left = vp9_left_block_mode(mi, left_mi, block);
|
||||
return vp9_kf_y_mode_prob[above][left];
|
||||
}
|
||||
|
||||
typedef void (*foreach_transformed_block_visitor)(int plane, int block, int row,
|
||||
int col,
|
||||
BLOCK_SIZE plane_bsize,
|
||||
TX_SIZE tx_size, void *arg);
|
||||
|
||||
void vp9_foreach_transformed_block_in_plane(
|
||||
const MACROBLOCKD *const xd, BLOCK_SIZE bsize, int plane,
|
||||
foreach_transformed_block_visitor visit, void *arg);
|
||||
|
||||
void vp9_foreach_transformed_block(const MACROBLOCKD *const xd,
|
||||
BLOCK_SIZE bsize,
|
||||
foreach_transformed_block_visitor visit,
|
||||
void *arg);
|
||||
|
||||
void vp9_set_contexts(const MACROBLOCKD *xd, struct macroblockd_plane *pd,
|
||||
BLOCK_SIZE plane_bsize, TX_SIZE tx_size, int has_eob,
|
||||
int aoff, int loff);
|
||||
|
||||
#if CONFIG_MISMATCH_DEBUG
|
||||
#define TX_UNIT_SIZE_LOG2 2
|
||||
static INLINE void mi_to_pixel_loc(int *pixel_c, int *pixel_r, int mi_col,
|
||||
int mi_row, int tx_blk_col, int tx_blk_row,
|
||||
int subsampling_x, int subsampling_y) {
|
||||
*pixel_c = ((mi_col << MI_SIZE_LOG2) >> subsampling_x) +
|
||||
(tx_blk_col << TX_UNIT_SIZE_LOG2);
|
||||
*pixel_r = ((mi_row << MI_SIZE_LOG2) >> subsampling_y) +
|
||||
(tx_blk_row << TX_UNIT_SIZE_LOG2);
|
||||
}
|
||||
|
||||
static INLINE int get_block_width(BLOCK_SIZE bsize) {
|
||||
const int num_4x4_w = num_4x4_blocks_wide_lookup[bsize];
|
||||
return 4 * num_4x4_w;
|
||||
}
|
||||
|
||||
static INLINE int get_block_height(BLOCK_SIZE bsize) {
|
||||
const int num_4x4_h = num_4x4_blocks_high_lookup[bsize];
|
||||
return 4 * num_4x4_h;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_COMMON_VP9_BLOCKD_H_
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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 VPX_VP9_COMMON_VP9_COMMON_H_
|
||||
#define VPX_VP9_COMMON_VP9_COMMON_H_
|
||||
|
||||
/* Interface header for common constant data structures and lookup tables */
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "./vpx_config.h"
|
||||
#include "vpx_dsp/vpx_dsp_common.h"
|
||||
#include "vpx_mem/vpx_mem.h"
|
||||
#include "vpx/vpx_integer.h"
|
||||
#include "vpx_ports/bitops.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Only need this for fixed-size arrays, for structs just assign.
|
||||
#define vp9_copy(dest, src) \
|
||||
{ \
|
||||
assert(sizeof(dest) == sizeof(src)); \
|
||||
memcpy(dest, src, sizeof(src)); \
|
||||
}
|
||||
|
||||
// Use this for variably-sized arrays.
|
||||
#define vp9_copy_array(dest, src, n) \
|
||||
{ \
|
||||
assert(sizeof(*(dest)) == sizeof(*(src))); \
|
||||
memcpy(dest, src, (n) * sizeof(*(src))); \
|
||||
}
|
||||
|
||||
#define vp9_zero(dest) memset(&(dest), 0, sizeof(dest))
|
||||
#define vp9_zero_array(dest, n) memset(dest, 0, (n) * sizeof(*(dest)))
|
||||
|
||||
static INLINE int get_unsigned_bits(unsigned int num_values) {
|
||||
return num_values > 0 ? get_msb(num_values) + 1 : 0;
|
||||
}
|
||||
|
||||
#if CONFIG_DEBUG
|
||||
#define CHECK_MEM_ERROR(cm, lval, expr) \
|
||||
do { \
|
||||
(lval) = (expr); \
|
||||
if (!(lval)) \
|
||||
vpx_internal_error(&(cm)->error, VPX_CODEC_MEM_ERROR, \
|
||||
"Failed to allocate " #lval " at %s:%d", __FILE__, \
|
||||
__LINE__); \
|
||||
} while (0)
|
||||
#else
|
||||
#define CHECK_MEM_ERROR(cm, lval, expr) \
|
||||
do { \
|
||||
(lval) = (expr); \
|
||||
if (!(lval)) \
|
||||
vpx_internal_error(&(cm)->error, VPX_CODEC_MEM_ERROR, \
|
||||
"Failed to allocate " #lval); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#define VP9_SYNC_CODE_0 0x49
|
||||
#define VP9_SYNC_CODE_1 0x83
|
||||
#define VP9_SYNC_CODE_2 0x42
|
||||
|
||||
#define VP9_FRAME_MARKER 0x2
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_COMMON_VP9_COMMON_H_
|
||||
@@ -0,0 +1,259 @@
|
||||
/*
|
||||
* 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/common/vp9_common_data.h"
|
||||
#include "vpx_dsp/vpx_dsp_common.h"
|
||||
|
||||
// Log 2 conversion lookup tables for block width and height
|
||||
const uint8_t b_width_log2_lookup[BLOCK_SIZES] = { 0, 0, 1, 1, 1, 2, 2,
|
||||
2, 3, 3, 3, 4, 4 };
|
||||
const uint8_t b_height_log2_lookup[BLOCK_SIZES] = { 0, 1, 0, 1, 2, 1, 2,
|
||||
3, 2, 3, 4, 3, 4 };
|
||||
const uint8_t num_4x4_blocks_wide_lookup[BLOCK_SIZES] = { 1, 1, 2, 2, 2, 4, 4,
|
||||
4, 8, 8, 8, 16, 16 };
|
||||
const uint8_t num_4x4_blocks_high_lookup[BLOCK_SIZES] = { 1, 2, 1, 2, 4, 2, 4,
|
||||
8, 4, 8, 16, 8, 16 };
|
||||
// Log 2 conversion lookup tables for modeinfo width and height
|
||||
const uint8_t mi_width_log2_lookup[BLOCK_SIZES] = { 0, 0, 0, 0, 0, 1, 1,
|
||||
1, 2, 2, 2, 3, 3 };
|
||||
const uint8_t num_8x8_blocks_wide_lookup[BLOCK_SIZES] = { 1, 1, 1, 1, 1, 2, 2,
|
||||
2, 4, 4, 4, 8, 8 };
|
||||
const uint8_t num_8x8_blocks_high_lookup[BLOCK_SIZES] = { 1, 1, 1, 1, 2, 1, 2,
|
||||
4, 2, 4, 8, 4, 8 };
|
||||
|
||||
// VPXMIN(3, VPXMIN(b_width_log2_lookup(bsize), b_height_log2_lookup(bsize)))
|
||||
const uint8_t size_group_lookup[BLOCK_SIZES] = { 0, 0, 0, 1, 1, 1, 2,
|
||||
2, 2, 3, 3, 3, 3 };
|
||||
|
||||
const uint8_t num_pels_log2_lookup[BLOCK_SIZES] = { 4, 5, 5, 6, 7, 7, 8,
|
||||
9, 9, 10, 11, 11, 12 };
|
||||
|
||||
const PARTITION_TYPE partition_lookup[][BLOCK_SIZES] = {
|
||||
{ // 4X4
|
||||
// 4X4, 4X8,8X4,8X8,8X16,16X8,16X16,16X32,32X16,32X32,32X64,64X32,64X64
|
||||
PARTITION_NONE, PARTITION_INVALID, PARTITION_INVALID, PARTITION_INVALID,
|
||||
PARTITION_INVALID, PARTITION_INVALID, PARTITION_INVALID, PARTITION_INVALID,
|
||||
PARTITION_INVALID, PARTITION_INVALID, PARTITION_INVALID, PARTITION_INVALID,
|
||||
PARTITION_INVALID },
|
||||
{ // 8X8
|
||||
// 4X4, 4X8,8X4,8X8,8X16,16X8,16X16,16X32,32X16,32X32,32X64,64X32,64X64
|
||||
PARTITION_SPLIT, PARTITION_VERT, PARTITION_HORZ, PARTITION_NONE,
|
||||
PARTITION_INVALID, PARTITION_INVALID, PARTITION_INVALID, PARTITION_INVALID,
|
||||
PARTITION_INVALID, PARTITION_INVALID, PARTITION_INVALID, PARTITION_INVALID,
|
||||
PARTITION_INVALID },
|
||||
{ // 16X16
|
||||
// 4X4, 4X8,8X4,8X8,8X16,16X8,16X16,16X32,32X16,32X32,32X64,64X32,64X64
|
||||
PARTITION_SPLIT, PARTITION_SPLIT, PARTITION_SPLIT, PARTITION_SPLIT,
|
||||
PARTITION_VERT, PARTITION_HORZ, PARTITION_NONE, PARTITION_INVALID,
|
||||
PARTITION_INVALID, PARTITION_INVALID, PARTITION_INVALID, PARTITION_INVALID,
|
||||
PARTITION_INVALID },
|
||||
{ // 32X32
|
||||
// 4X4, 4X8,8X4,8X8,8X16,16X8,16X16,16X32,32X16,32X32,32X64,64X32,64X64
|
||||
PARTITION_SPLIT, PARTITION_SPLIT, PARTITION_SPLIT, PARTITION_SPLIT,
|
||||
PARTITION_SPLIT, PARTITION_SPLIT, PARTITION_SPLIT, PARTITION_VERT,
|
||||
PARTITION_HORZ, PARTITION_NONE, PARTITION_INVALID, PARTITION_INVALID,
|
||||
PARTITION_INVALID },
|
||||
{ // 64X64
|
||||
// 4X4, 4X8,8X4,8X8,8X16,16X8,16X16,16X32,32X16,32X32,32X64,64X32,64X64
|
||||
PARTITION_SPLIT, PARTITION_SPLIT, PARTITION_SPLIT, PARTITION_SPLIT,
|
||||
PARTITION_SPLIT, PARTITION_SPLIT, PARTITION_SPLIT, PARTITION_SPLIT,
|
||||
PARTITION_SPLIT, PARTITION_SPLIT, PARTITION_VERT, PARTITION_HORZ,
|
||||
PARTITION_NONE }
|
||||
};
|
||||
|
||||
const BLOCK_SIZE subsize_lookup[PARTITION_TYPES][BLOCK_SIZES] = {
|
||||
{ // PARTITION_NONE
|
||||
BLOCK_4X4, BLOCK_4X8, BLOCK_8X4, BLOCK_8X8, BLOCK_8X16, BLOCK_16X8,
|
||||
BLOCK_16X16, BLOCK_16X32, BLOCK_32X16, BLOCK_32X32, BLOCK_32X64,
|
||||
BLOCK_64X32, BLOCK_64X64 },
|
||||
{ // PARTITION_HORZ
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID, BLOCK_8X4, BLOCK_INVALID,
|
||||
BLOCK_INVALID, BLOCK_16X8, BLOCK_INVALID, BLOCK_INVALID, BLOCK_32X16,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_64X32 },
|
||||
{ // PARTITION_VERT
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID, BLOCK_4X8, BLOCK_INVALID,
|
||||
BLOCK_INVALID, BLOCK_8X16, BLOCK_INVALID, BLOCK_INVALID, BLOCK_16X32,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_32X64 },
|
||||
{ // PARTITION_SPLIT
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID, BLOCK_4X4, BLOCK_INVALID,
|
||||
BLOCK_INVALID, BLOCK_8X8, BLOCK_INVALID, BLOCK_INVALID, BLOCK_16X16,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_32X32 }
|
||||
};
|
||||
|
||||
const TX_SIZE max_txsize_lookup[BLOCK_SIZES] = {
|
||||
TX_4X4, TX_4X4, TX_4X4, TX_8X8, TX_8X8, TX_8X8, TX_16X16,
|
||||
TX_16X16, TX_16X16, TX_32X32, TX_32X32, TX_32X32, TX_32X32
|
||||
};
|
||||
|
||||
const BLOCK_SIZE txsize_to_bsize[TX_SIZES] = {
|
||||
BLOCK_4X4, // TX_4X4
|
||||
BLOCK_8X8, // TX_8X8
|
||||
BLOCK_16X16, // TX_16X16
|
||||
BLOCK_32X32, // TX_32X32
|
||||
};
|
||||
|
||||
const TX_SIZE tx_mode_to_biggest_tx_size[TX_MODES] = {
|
||||
TX_4X4, // ONLY_4X4
|
||||
TX_8X8, // ALLOW_8X8
|
||||
TX_16X16, // ALLOW_16X16
|
||||
TX_32X32, // ALLOW_32X32
|
||||
TX_32X32, // TX_MODE_SELECT
|
||||
};
|
||||
|
||||
const BLOCK_SIZE ss_size_lookup[BLOCK_SIZES][2][2] = {
|
||||
// ss_x == 0 ss_x == 0 ss_x == 1 ss_x == 1
|
||||
// ss_y == 0 ss_y == 1 ss_y == 0 ss_y == 1
|
||||
{ { BLOCK_4X4, BLOCK_INVALID }, { BLOCK_INVALID, BLOCK_INVALID } },
|
||||
{ { BLOCK_4X8, BLOCK_4X4 }, { BLOCK_INVALID, BLOCK_INVALID } },
|
||||
{ { BLOCK_8X4, BLOCK_INVALID }, { BLOCK_4X4, BLOCK_INVALID } },
|
||||
{ { BLOCK_8X8, BLOCK_8X4 }, { BLOCK_4X8, BLOCK_4X4 } },
|
||||
{ { BLOCK_8X16, BLOCK_8X8 }, { BLOCK_INVALID, BLOCK_4X8 } },
|
||||
{ { BLOCK_16X8, BLOCK_INVALID }, { BLOCK_8X8, BLOCK_8X4 } },
|
||||
{ { BLOCK_16X16, BLOCK_16X8 }, { BLOCK_8X16, BLOCK_8X8 } },
|
||||
{ { BLOCK_16X32, BLOCK_16X16 }, { BLOCK_INVALID, BLOCK_8X16 } },
|
||||
{ { BLOCK_32X16, BLOCK_INVALID }, { BLOCK_16X16, BLOCK_16X8 } },
|
||||
{ { BLOCK_32X32, BLOCK_32X16 }, { BLOCK_16X32, BLOCK_16X16 } },
|
||||
{ { BLOCK_32X64, BLOCK_32X32 }, { BLOCK_INVALID, BLOCK_16X32 } },
|
||||
{ { BLOCK_64X32, BLOCK_INVALID }, { BLOCK_32X32, BLOCK_32X16 } },
|
||||
{ { BLOCK_64X64, BLOCK_64X32 }, { BLOCK_32X64, BLOCK_32X32 } },
|
||||
};
|
||||
|
||||
const TX_SIZE uv_txsize_lookup[BLOCK_SIZES][TX_SIZES][2][2] = {
|
||||
// ss_x == 0 ss_x == 0 ss_x == 1 ss_x == 1
|
||||
// ss_y == 0 ss_y == 1 ss_y == 0 ss_y == 1
|
||||
{
|
||||
// BLOCK_4X4
|
||||
{ { TX_4X4, TX_4X4 }, { TX_4X4, TX_4X4 } },
|
||||
{ { TX_4X4, TX_4X4 }, { TX_4X4, TX_4X4 } },
|
||||
{ { TX_4X4, TX_4X4 }, { TX_4X4, TX_4X4 } },
|
||||
{ { TX_4X4, TX_4X4 }, { TX_4X4, TX_4X4 } },
|
||||
},
|
||||
{
|
||||
// BLOCK_4X8
|
||||
{ { TX_4X4, TX_4X4 }, { TX_4X4, TX_4X4 } },
|
||||
{ { TX_4X4, TX_4X4 }, { TX_4X4, TX_4X4 } },
|
||||
{ { TX_4X4, TX_4X4 }, { TX_4X4, TX_4X4 } },
|
||||
{ { TX_4X4, TX_4X4 }, { TX_4X4, TX_4X4 } },
|
||||
},
|
||||
{
|
||||
// BLOCK_8X4
|
||||
{ { TX_4X4, TX_4X4 }, { TX_4X4, TX_4X4 } },
|
||||
{ { TX_4X4, TX_4X4 }, { TX_4X4, TX_4X4 } },
|
||||
{ { TX_4X4, TX_4X4 }, { TX_4X4, TX_4X4 } },
|
||||
{ { TX_4X4, TX_4X4 }, { TX_4X4, TX_4X4 } },
|
||||
},
|
||||
{
|
||||
// BLOCK_8X8
|
||||
{ { TX_4X4, TX_4X4 }, { TX_4X4, TX_4X4 } },
|
||||
{ { TX_8X8, TX_4X4 }, { TX_4X4, TX_4X4 } },
|
||||
{ { TX_8X8, TX_4X4 }, { TX_4X4, TX_4X4 } },
|
||||
{ { TX_8X8, TX_4X4 }, { TX_4X4, TX_4X4 } },
|
||||
},
|
||||
{
|
||||
// BLOCK_8X16
|
||||
{ { TX_4X4, TX_4X4 }, { TX_4X4, TX_4X4 } },
|
||||
{ { TX_8X8, TX_8X8 }, { TX_4X4, TX_4X4 } },
|
||||
{ { TX_8X8, TX_8X8 }, { TX_4X4, TX_4X4 } },
|
||||
{ { TX_8X8, TX_8X8 }, { TX_4X4, TX_4X4 } },
|
||||
},
|
||||
{
|
||||
// BLOCK_16X8
|
||||
{ { TX_4X4, TX_4X4 }, { TX_4X4, TX_4X4 } },
|
||||
{ { TX_8X8, TX_4X4 }, { TX_8X8, TX_4X4 } },
|
||||
{ { TX_8X8, TX_4X4 }, { TX_8X8, TX_8X8 } },
|
||||
{ { TX_8X8, TX_4X4 }, { TX_8X8, TX_8X8 } },
|
||||
},
|
||||
{
|
||||
// BLOCK_16X16
|
||||
{ { TX_4X4, TX_4X4 }, { TX_4X4, TX_4X4 } },
|
||||
{ { TX_8X8, TX_8X8 }, { TX_8X8, TX_8X8 } },
|
||||
{ { TX_16X16, TX_8X8 }, { TX_8X8, TX_8X8 } },
|
||||
{ { TX_16X16, TX_8X8 }, { TX_8X8, TX_8X8 } },
|
||||
},
|
||||
{
|
||||
// BLOCK_16X32
|
||||
{ { TX_4X4, TX_4X4 }, { TX_4X4, TX_4X4 } },
|
||||
{ { TX_8X8, TX_8X8 }, { TX_8X8, TX_8X8 } },
|
||||
{ { TX_16X16, TX_16X16 }, { TX_8X8, TX_8X8 } },
|
||||
{ { TX_16X16, TX_16X16 }, { TX_8X8, TX_8X8 } },
|
||||
},
|
||||
{
|
||||
// BLOCK_32X16
|
||||
{ { TX_4X4, TX_4X4 }, { TX_4X4, TX_4X4 } },
|
||||
{ { TX_8X8, TX_8X8 }, { TX_8X8, TX_8X8 } },
|
||||
{ { TX_16X16, TX_8X8 }, { TX_16X16, TX_8X8 } },
|
||||
{ { TX_16X16, TX_8X8 }, { TX_16X16, TX_8X8 } },
|
||||
},
|
||||
{
|
||||
// BLOCK_32X32
|
||||
{ { TX_4X4, TX_4X4 }, { TX_4X4, TX_4X4 } },
|
||||
{ { TX_8X8, TX_8X8 }, { TX_8X8, TX_8X8 } },
|
||||
{ { TX_16X16, TX_16X16 }, { TX_16X16, TX_16X16 } },
|
||||
{ { TX_32X32, TX_16X16 }, { TX_16X16, TX_16X16 } },
|
||||
},
|
||||
{
|
||||
// BLOCK_32X64
|
||||
{ { TX_4X4, TX_4X4 }, { TX_4X4, TX_4X4 } },
|
||||
{ { TX_8X8, TX_8X8 }, { TX_8X8, TX_8X8 } },
|
||||
{ { TX_16X16, TX_16X16 }, { TX_16X16, TX_16X16 } },
|
||||
{ { TX_32X32, TX_32X32 }, { TX_16X16, TX_16X16 } },
|
||||
},
|
||||
{
|
||||
// BLOCK_64X32
|
||||
{ { TX_4X4, TX_4X4 }, { TX_4X4, TX_4X4 } },
|
||||
{ { TX_8X8, TX_8X8 }, { TX_8X8, TX_8X8 } },
|
||||
{ { TX_16X16, TX_16X16 }, { TX_16X16, TX_16X16 } },
|
||||
{ { TX_32X32, TX_16X16 }, { TX_32X32, TX_16X16 } },
|
||||
},
|
||||
{
|
||||
// BLOCK_64X64
|
||||
{ { TX_4X4, TX_4X4 }, { TX_4X4, TX_4X4 } },
|
||||
{ { TX_8X8, TX_8X8 }, { TX_8X8, TX_8X8 } },
|
||||
{ { TX_16X16, TX_16X16 }, { TX_16X16, TX_16X16 } },
|
||||
{ { TX_32X32, TX_32X32 }, { TX_32X32, TX_32X32 } },
|
||||
},
|
||||
};
|
||||
|
||||
// Generates 4 bit field in which each bit set to 1 represents
|
||||
// a blocksize partition 1111 means we split 64x64, 32x32, 16x16
|
||||
// and 8x8. 1000 means we just split the 64x64 to 32x32
|
||||
const struct {
|
||||
PARTITION_CONTEXT above;
|
||||
PARTITION_CONTEXT left;
|
||||
} partition_context_lookup[BLOCK_SIZES] = {
|
||||
{ 15, 15 }, // 4X4 - {0b1111, 0b1111}
|
||||
{ 15, 14 }, // 4X8 - {0b1111, 0b1110}
|
||||
{ 14, 15 }, // 8X4 - {0b1110, 0b1111}
|
||||
{ 14, 14 }, // 8X8 - {0b1110, 0b1110}
|
||||
{ 14, 12 }, // 8X16 - {0b1110, 0b1100}
|
||||
{ 12, 14 }, // 16X8 - {0b1100, 0b1110}
|
||||
{ 12, 12 }, // 16X16 - {0b1100, 0b1100}
|
||||
{ 12, 8 }, // 16X32 - {0b1100, 0b1000}
|
||||
{ 8, 12 }, // 32X16 - {0b1000, 0b1100}
|
||||
{ 8, 8 }, // 32X32 - {0b1000, 0b1000}
|
||||
{ 8, 0 }, // 32X64 - {0b1000, 0b0000}
|
||||
{ 0, 8 }, // 64X32 - {0b0000, 0b1000}
|
||||
{ 0, 0 }, // 64X64 - {0b0000, 0b0000}
|
||||
};
|
||||
|
||||
#if CONFIG_BETTER_HW_COMPATIBILITY && CONFIG_VP9_HIGHBITDEPTH
|
||||
const uint8_t need_top_left[INTRA_MODES] = {
|
||||
0, // DC_PRED
|
||||
0, // V_PRED
|
||||
0, // H_PRED
|
||||
0, // D45_PRED
|
||||
1, // D135_PRED
|
||||
1, // D117_PRED
|
||||
1, // D153_PRED
|
||||
0, // D207_PRED
|
||||
0, // D63_PRED
|
||||
1, // TM_PRED
|
||||
};
|
||||
#endif // CONFIG_BETTER_HW_COMPATIBILITY && CONFIG_VP9_HIGHBITDEPTH
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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 VPX_VP9_COMMON_VP9_COMMON_DATA_H_
|
||||
#define VPX_VP9_COMMON_VP9_COMMON_DATA_H_
|
||||
|
||||
#include "vp9/common/vp9_enums.h"
|
||||
#include "vpx/vpx_integer.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern const uint8_t b_width_log2_lookup[BLOCK_SIZES];
|
||||
extern const uint8_t b_height_log2_lookup[BLOCK_SIZES];
|
||||
extern const uint8_t mi_width_log2_lookup[BLOCK_SIZES];
|
||||
extern const uint8_t num_8x8_blocks_wide_lookup[BLOCK_SIZES];
|
||||
extern const uint8_t num_8x8_blocks_high_lookup[BLOCK_SIZES];
|
||||
extern const uint8_t num_4x4_blocks_high_lookup[BLOCK_SIZES];
|
||||
extern const uint8_t num_4x4_blocks_wide_lookup[BLOCK_SIZES];
|
||||
extern const uint8_t size_group_lookup[BLOCK_SIZES];
|
||||
extern const uint8_t num_pels_log2_lookup[BLOCK_SIZES];
|
||||
extern const PARTITION_TYPE partition_lookup[][BLOCK_SIZES];
|
||||
extern const BLOCK_SIZE subsize_lookup[PARTITION_TYPES][BLOCK_SIZES];
|
||||
extern const TX_SIZE max_txsize_lookup[BLOCK_SIZES];
|
||||
extern const BLOCK_SIZE txsize_to_bsize[TX_SIZES];
|
||||
extern const TX_SIZE tx_mode_to_biggest_tx_size[TX_MODES];
|
||||
extern const BLOCK_SIZE ss_size_lookup[BLOCK_SIZES][2][2];
|
||||
extern const TX_SIZE uv_txsize_lookup[BLOCK_SIZES][TX_SIZES][2][2];
|
||||
#if CONFIG_BETTER_HW_COMPATIBILITY && CONFIG_VP9_HIGHBITDEPTH
|
||||
extern const uint8_t need_top_left[INTRA_MODES];
|
||||
#endif // CONFIG_BETTER_HW_COMPATIBILITY && CONFIG_VP9_HIGHBITDEPTH
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_COMMON_VP9_COMMON_DATA_H_
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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 <stdio.h>
|
||||
|
||||
#include "vp9/common/vp9_blockd.h"
|
||||
#include "vp9/common/vp9_onyxc_int.h"
|
||||
|
||||
static void log_frame_info(VP9_COMMON *cm, const char *str, FILE *f) {
|
||||
fprintf(f, "%s", str);
|
||||
fprintf(f, "(Frame %d, Show:%d, Q:%d): \n", cm->current_video_frame,
|
||||
cm->show_frame, cm->base_qindex);
|
||||
}
|
||||
/* This function dereferences a pointer to the mbmi structure
|
||||
* and uses the passed in member offset to print out the value of an integer
|
||||
* for each mbmi member value in the mi structure.
|
||||
*/
|
||||
static void print_mi_data(VP9_COMMON *cm, FILE *file, const char *descriptor,
|
||||
size_t member_offset) {
|
||||
int mi_row, mi_col;
|
||||
MODE_INFO **mi = cm->mi_grid_visible;
|
||||
int rows = cm->mi_rows;
|
||||
int cols = cm->mi_cols;
|
||||
char prefix = descriptor[0];
|
||||
|
||||
log_frame_info(cm, descriptor, file);
|
||||
for (mi_row = 0; mi_row < rows; mi_row++) {
|
||||
fprintf(file, "%c ", prefix);
|
||||
for (mi_col = 0; mi_col < cols; mi_col++) {
|
||||
fprintf(file, "%2d ", *((char *)((char *)(mi[0]) + member_offset)));
|
||||
mi++;
|
||||
}
|
||||
fprintf(file, "\n");
|
||||
mi += 8;
|
||||
}
|
||||
fprintf(file, "\n");
|
||||
}
|
||||
|
||||
void vp9_print_modes_and_motion_vectors(VP9_COMMON *cm, const char *file) {
|
||||
int mi_row;
|
||||
int mi_col;
|
||||
FILE *mvs = fopen(file, "a");
|
||||
MODE_INFO **mi = cm->mi_grid_visible;
|
||||
int rows = cm->mi_rows;
|
||||
int cols = cm->mi_cols;
|
||||
|
||||
print_mi_data(cm, mvs, "Partitions:", offsetof(MODE_INFO, sb_type));
|
||||
print_mi_data(cm, mvs, "Modes:", offsetof(MODE_INFO, mode));
|
||||
print_mi_data(cm, mvs, "Ref frame:", offsetof(MODE_INFO, ref_frame[0]));
|
||||
print_mi_data(cm, mvs, "Transform:", offsetof(MODE_INFO, tx_size));
|
||||
print_mi_data(cm, mvs, "UV Modes:", offsetof(MODE_INFO, uv_mode));
|
||||
|
||||
// output skip infomation.
|
||||
log_frame_info(cm, "Skips:", mvs);
|
||||
for (mi_row = 0; mi_row < rows; mi_row++) {
|
||||
fprintf(mvs, "S ");
|
||||
for (mi_col = 0; mi_col < cols; mi_col++) {
|
||||
fprintf(mvs, "%2d ", mi[0]->skip);
|
||||
mi++;
|
||||
}
|
||||
fprintf(mvs, "\n");
|
||||
mi += 8;
|
||||
}
|
||||
fprintf(mvs, "\n");
|
||||
|
||||
// output motion vectors.
|
||||
log_frame_info(cm, "Vectors ", mvs);
|
||||
mi = cm->mi_grid_visible;
|
||||
for (mi_row = 0; mi_row < rows; mi_row++) {
|
||||
fprintf(mvs, "V ");
|
||||
for (mi_col = 0; mi_col < cols; mi_col++) {
|
||||
fprintf(mvs, "%4d:%4d ", mi[0]->mv[0].as_mv.row, mi[0]->mv[0].as_mv.col);
|
||||
mi++;
|
||||
}
|
||||
fprintf(mvs, "\n");
|
||||
mi += 8;
|
||||
}
|
||||
fprintf(mvs, "\n");
|
||||
|
||||
fclose(mvs);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
* 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 VPX_VP9_COMMON_VP9_ENTROPY_H_
|
||||
#define VPX_VP9_COMMON_VP9_ENTROPY_H_
|
||||
|
||||
#include "vpx/vpx_integer.h"
|
||||
#include "vpx_dsp/prob.h"
|
||||
|
||||
#include "vp9/common/vp9_common.h"
|
||||
#include "vp9/common/vp9_enums.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define DIFF_UPDATE_PROB 252
|
||||
|
||||
// Coefficient token alphabet
|
||||
#define ZERO_TOKEN 0 // 0 Extra Bits 0+0
|
||||
#define ONE_TOKEN 1 // 1 Extra Bits 0+1
|
||||
#define TWO_TOKEN 2 // 2 Extra Bits 0+1
|
||||
#define THREE_TOKEN 3 // 3 Extra Bits 0+1
|
||||
#define FOUR_TOKEN 4 // 4 Extra Bits 0+1
|
||||
#define CATEGORY1_TOKEN 5 // 5-6 Extra Bits 1+1
|
||||
#define CATEGORY2_TOKEN 6 // 7-10 Extra Bits 2+1
|
||||
#define CATEGORY3_TOKEN 7 // 11-18 Extra Bits 3+1
|
||||
#define CATEGORY4_TOKEN 8 // 19-34 Extra Bits 4+1
|
||||
#define CATEGORY5_TOKEN 9 // 35-66 Extra Bits 5+1
|
||||
#define CATEGORY6_TOKEN 10 // 67+ Extra Bits 14+1
|
||||
#define EOB_TOKEN 11 // EOB Extra Bits 0+0
|
||||
|
||||
#define ENTROPY_TOKENS 12
|
||||
|
||||
#define ENTROPY_NODES 11
|
||||
|
||||
DECLARE_ALIGNED(16, extern const uint8_t, vp9_pt_energy_class[ENTROPY_TOKENS]);
|
||||
|
||||
#define CAT1_MIN_VAL 5
|
||||
#define CAT2_MIN_VAL 7
|
||||
#define CAT3_MIN_VAL 11
|
||||
#define CAT4_MIN_VAL 19
|
||||
#define CAT5_MIN_VAL 35
|
||||
#define CAT6_MIN_VAL 67
|
||||
|
||||
// Extra bit probabilities.
|
||||
DECLARE_ALIGNED(16, extern const uint8_t, vp9_cat1_prob[1]);
|
||||
DECLARE_ALIGNED(16, extern const uint8_t, vp9_cat2_prob[2]);
|
||||
DECLARE_ALIGNED(16, extern const uint8_t, vp9_cat3_prob[3]);
|
||||
DECLARE_ALIGNED(16, extern const uint8_t, vp9_cat4_prob[4]);
|
||||
DECLARE_ALIGNED(16, extern const uint8_t, vp9_cat5_prob[5]);
|
||||
DECLARE_ALIGNED(16, extern const uint8_t, vp9_cat6_prob[14]);
|
||||
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
DECLARE_ALIGNED(16, extern const uint8_t, vp9_cat1_prob_high10[1]);
|
||||
DECLARE_ALIGNED(16, extern const uint8_t, vp9_cat2_prob_high10[2]);
|
||||
DECLARE_ALIGNED(16, extern const uint8_t, vp9_cat3_prob_high10[3]);
|
||||
DECLARE_ALIGNED(16, extern const uint8_t, vp9_cat4_prob_high10[4]);
|
||||
DECLARE_ALIGNED(16, extern const uint8_t, vp9_cat5_prob_high10[5]);
|
||||
DECLARE_ALIGNED(16, extern const uint8_t, vp9_cat6_prob_high10[16]);
|
||||
DECLARE_ALIGNED(16, extern const uint8_t, vp9_cat1_prob_high12[1]);
|
||||
DECLARE_ALIGNED(16, extern const uint8_t, vp9_cat2_prob_high12[2]);
|
||||
DECLARE_ALIGNED(16, extern const uint8_t, vp9_cat3_prob_high12[3]);
|
||||
DECLARE_ALIGNED(16, extern const uint8_t, vp9_cat4_prob_high12[4]);
|
||||
DECLARE_ALIGNED(16, extern const uint8_t, vp9_cat5_prob_high12[5]);
|
||||
DECLARE_ALIGNED(16, extern const uint8_t, vp9_cat6_prob_high12[18]);
|
||||
#endif // CONFIG_VP9_HIGHBITDEPTH
|
||||
|
||||
#define EOB_MODEL_TOKEN 3
|
||||
|
||||
#define DCT_MAX_VALUE 16384
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
#define DCT_MAX_VALUE_HIGH10 65536
|
||||
#define DCT_MAX_VALUE_HIGH12 262144
|
||||
#endif // CONFIG_VP9_HIGHBITDEPTH
|
||||
|
||||
/* Coefficients are predicted via a 3-dimensional probability table. */
|
||||
|
||||
#define REF_TYPES 2 // intra=0, inter=1
|
||||
|
||||
/* Middle dimension reflects the coefficient position within the transform. */
|
||||
#define COEF_BANDS 6
|
||||
|
||||
/* Inside dimension is measure of nearby complexity, that reflects the energy
|
||||
of nearby coefficients are nonzero. For the first coefficient (DC, unless
|
||||
block type is 0), we look at the (already encoded) blocks above and to the
|
||||
left of the current block. The context index is then the number (0,1,or 2)
|
||||
of these blocks having nonzero coefficients.
|
||||
After decoding a coefficient, the measure is determined by the size of the
|
||||
most recently decoded coefficient.
|
||||
Note that the intuitive meaning of this measure changes as coefficients
|
||||
are decoded, e.g., prior to the first token, a zero means that my neighbors
|
||||
are empty while, after the first token, because of the use of end-of-block,
|
||||
a zero means we just decoded a zero and hence guarantees that a non-zero
|
||||
coefficient will appear later in this block. However, this shift
|
||||
in meaning is perfectly OK because our context depends also on the
|
||||
coefficient band (and since zigzag positions 0, 1, and 2 are in
|
||||
distinct bands). */
|
||||
|
||||
#define COEFF_CONTEXTS 6
|
||||
#define BAND_COEFF_CONTEXTS(band) ((band) == 0 ? 3 : COEFF_CONTEXTS)
|
||||
|
||||
// #define ENTROPY_STATS
|
||||
|
||||
typedef unsigned int vp9_coeff_count[REF_TYPES][COEF_BANDS][COEFF_CONTEXTS]
|
||||
[ENTROPY_TOKENS];
|
||||
typedef unsigned int vp9_coeff_stats[REF_TYPES][COEF_BANDS][COEFF_CONTEXTS]
|
||||
[ENTROPY_NODES][2];
|
||||
|
||||
#define SUBEXP_PARAM 4 /* Subexponential code parameter */
|
||||
#define MODULUS_PARAM 13 /* Modulus parameter */
|
||||
|
||||
struct VP9Common;
|
||||
void vp9_default_coef_probs(struct VP9Common *cm);
|
||||
void vp9_adapt_coef_probs(struct VP9Common *cm);
|
||||
|
||||
// This is the index in the scan order beyond which all coefficients for
|
||||
// 8x8 transform and above are in the top band.
|
||||
// This macro is currently unused but may be used by certain implementations
|
||||
#define MAXBAND_INDEX 21
|
||||
|
||||
DECLARE_ALIGNED(16, extern const uint8_t, vp9_coefband_trans_8x8plus[1024]);
|
||||
DECLARE_ALIGNED(16, extern const uint8_t, vp9_coefband_trans_4x4[16]);
|
||||
|
||||
static INLINE const uint8_t *get_band_translate(TX_SIZE tx_size) {
|
||||
return tx_size == TX_4X4 ? vp9_coefband_trans_4x4
|
||||
: vp9_coefband_trans_8x8plus;
|
||||
}
|
||||
|
||||
// 128 lists of probabilities are stored for the following ONE node probs:
|
||||
// 1, 3, 5, 7, ..., 253, 255
|
||||
// In between probabilities are interpolated linearly
|
||||
#define COEFF_PROB_MODELS 255
|
||||
|
||||
#define UNCONSTRAINED_NODES 3
|
||||
|
||||
#define PIVOT_NODE 2 // which node is pivot
|
||||
|
||||
#define MODEL_NODES (ENTROPY_NODES - UNCONSTRAINED_NODES)
|
||||
extern const vpx_tree_index vp9_coef_con_tree[TREE_SIZE(ENTROPY_TOKENS)];
|
||||
extern const vpx_prob vp9_pareto8_full[COEFF_PROB_MODELS][MODEL_NODES];
|
||||
|
||||
typedef vpx_prob vp9_coeff_probs_model[REF_TYPES][COEF_BANDS][COEFF_CONTEXTS]
|
||||
[UNCONSTRAINED_NODES];
|
||||
|
||||
typedef unsigned int vp9_coeff_count_model[REF_TYPES][COEF_BANDS]
|
||||
[COEFF_CONTEXTS]
|
||||
[UNCONSTRAINED_NODES + 1];
|
||||
|
||||
void vp9_model_to_full_probs(const vpx_prob *model, vpx_prob *full);
|
||||
|
||||
typedef char ENTROPY_CONTEXT;
|
||||
|
||||
static INLINE int combine_entropy_contexts(ENTROPY_CONTEXT a,
|
||||
ENTROPY_CONTEXT b) {
|
||||
return (a != 0) + (b != 0);
|
||||
}
|
||||
|
||||
static INLINE int get_entropy_context(TX_SIZE tx_size, const ENTROPY_CONTEXT *a,
|
||||
const ENTROPY_CONTEXT *l) {
|
||||
ENTROPY_CONTEXT above_ec = 0, left_ec = 0;
|
||||
|
||||
switch (tx_size) {
|
||||
case TX_4X4:
|
||||
above_ec = a[0] != 0;
|
||||
left_ec = l[0] != 0;
|
||||
break;
|
||||
case TX_8X8:
|
||||
above_ec = !!*(const uint16_t *)a;
|
||||
left_ec = !!*(const uint16_t *)l;
|
||||
break;
|
||||
case TX_16X16:
|
||||
above_ec = !!*(const uint32_t *)a;
|
||||
left_ec = !!*(const uint32_t *)l;
|
||||
break;
|
||||
case TX_32X32:
|
||||
above_ec = !!*(const uint64_t *)a;
|
||||
left_ec = !!*(const uint64_t *)l;
|
||||
break;
|
||||
default: assert(0 && "Invalid transform size."); break;
|
||||
}
|
||||
|
||||
return combine_entropy_contexts(above_ec, left_ec);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_COMMON_VP9_ENTROPY_H_
|
||||
@@ -0,0 +1,470 @@
|
||||
/*
|
||||
* 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 "vp9/common/vp9_onyxc_int.h"
|
||||
#include "vp9/common/vp9_seg_common.h"
|
||||
|
||||
const vpx_prob vp9_kf_y_mode_prob[INTRA_MODES][INTRA_MODES][INTRA_MODES - 1] = {
|
||||
{
|
||||
// above = dc
|
||||
{ 137, 30, 42, 148, 151, 207, 70, 52, 91 }, // left = dc
|
||||
{ 92, 45, 102, 136, 116, 180, 74, 90, 100 }, // left = v
|
||||
{ 73, 32, 19, 187, 222, 215, 46, 34, 100 }, // left = h
|
||||
{ 91, 30, 32, 116, 121, 186, 93, 86, 94 }, // left = d45
|
||||
{ 72, 35, 36, 149, 68, 206, 68, 63, 105 }, // left = d135
|
||||
{ 73, 31, 28, 138, 57, 124, 55, 122, 151 }, // left = d117
|
||||
{ 67, 23, 21, 140, 126, 197, 40, 37, 171 }, // left = d153
|
||||
{ 86, 27, 28, 128, 154, 212, 45, 43, 53 }, // left = d207
|
||||
{ 74, 32, 27, 107, 86, 160, 63, 134, 102 }, // left = d63
|
||||
{ 59, 67, 44, 140, 161, 202, 78, 67, 119 } // left = tm
|
||||
},
|
||||
{
|
||||
// above = v
|
||||
{ 63, 36, 126, 146, 123, 158, 60, 90, 96 }, // left = dc
|
||||
{ 43, 46, 168, 134, 107, 128, 69, 142, 92 }, // left = v
|
||||
{ 44, 29, 68, 159, 201, 177, 50, 57, 77 }, // left = h
|
||||
{ 58, 38, 76, 114, 97, 172, 78, 133, 92 }, // left = d45
|
||||
{ 46, 41, 76, 140, 63, 184, 69, 112, 57 }, // left = d135
|
||||
{ 38, 32, 85, 140, 46, 112, 54, 151, 133 }, // left = d117
|
||||
{ 39, 27, 61, 131, 110, 175, 44, 75, 136 }, // left = d153
|
||||
{ 52, 30, 74, 113, 130, 175, 51, 64, 58 }, // left = d207
|
||||
{ 47, 35, 80, 100, 74, 143, 64, 163, 74 }, // left = d63
|
||||
{ 36, 61, 116, 114, 128, 162, 80, 125, 82 } // left = tm
|
||||
},
|
||||
{
|
||||
// above = h
|
||||
{ 82, 26, 26, 171, 208, 204, 44, 32, 105 }, // left = dc
|
||||
{ 55, 44, 68, 166, 179, 192, 57, 57, 108 }, // left = v
|
||||
{ 42, 26, 11, 199, 241, 228, 23, 15, 85 }, // left = h
|
||||
{ 68, 42, 19, 131, 160, 199, 55, 52, 83 }, // left = d45
|
||||
{ 58, 50, 25, 139, 115, 232, 39, 52, 118 }, // left = d135
|
||||
{ 50, 35, 33, 153, 104, 162, 64, 59, 131 }, // left = d117
|
||||
{ 44, 24, 16, 150, 177, 202, 33, 19, 156 }, // left = d153
|
||||
{ 55, 27, 12, 153, 203, 218, 26, 27, 49 }, // left = d207
|
||||
{ 53, 49, 21, 110, 116, 168, 59, 80, 76 }, // left = d63
|
||||
{ 38, 72, 19, 168, 203, 212, 50, 50, 107 } // left = tm
|
||||
},
|
||||
{
|
||||
// above = d45
|
||||
{ 103, 26, 36, 129, 132, 201, 83, 80, 93 }, // left = dc
|
||||
{ 59, 38, 83, 112, 103, 162, 98, 136, 90 }, // left = v
|
||||
{ 62, 30, 23, 158, 200, 207, 59, 57, 50 }, // left = h
|
||||
{ 67, 30, 29, 84, 86, 191, 102, 91, 59 }, // left = d45
|
||||
{ 60, 32, 33, 112, 71, 220, 64, 89, 104 }, // left = d135
|
||||
{ 53, 26, 34, 130, 56, 149, 84, 120, 103 }, // left = d117
|
||||
{ 53, 21, 23, 133, 109, 210, 56, 77, 172 }, // left = d153
|
||||
{ 77, 19, 29, 112, 142, 228, 55, 66, 36 }, // left = d207
|
||||
{ 61, 29, 29, 93, 97, 165, 83, 175, 162 }, // left = d63
|
||||
{ 47, 47, 43, 114, 137, 181, 100, 99, 95 } // left = tm
|
||||
},
|
||||
{
|
||||
// above = d135
|
||||
{ 69, 23, 29, 128, 83, 199, 46, 44, 101 }, // left = dc
|
||||
{ 53, 40, 55, 139, 69, 183, 61, 80, 110 }, // left = v
|
||||
{ 40, 29, 19, 161, 180, 207, 43, 24, 91 }, // left = h
|
||||
{ 60, 34, 19, 105, 61, 198, 53, 64, 89 }, // left = d45
|
||||
{ 52, 31, 22, 158, 40, 209, 58, 62, 89 }, // left = d135
|
||||
{ 44, 31, 29, 147, 46, 158, 56, 102, 198 }, // left = d117
|
||||
{ 35, 19, 12, 135, 87, 209, 41, 45, 167 }, // left = d153
|
||||
{ 55, 25, 21, 118, 95, 215, 38, 39, 66 }, // left = d207
|
||||
{ 51, 38, 25, 113, 58, 164, 70, 93, 97 }, // left = d63
|
||||
{ 47, 54, 34, 146, 108, 203, 72, 103, 151 } // left = tm
|
||||
},
|
||||
{
|
||||
// above = d117
|
||||
{ 64, 19, 37, 156, 66, 138, 49, 95, 133 }, // left = dc
|
||||
{ 46, 27, 80, 150, 55, 124, 55, 121, 135 }, // left = v
|
||||
{ 36, 23, 27, 165, 149, 166, 54, 64, 118 }, // left = h
|
||||
{ 53, 21, 36, 131, 63, 163, 60, 109, 81 }, // left = d45
|
||||
{ 40, 26, 35, 154, 40, 185, 51, 97, 123 }, // left = d135
|
||||
{ 35, 19, 34, 179, 19, 97, 48, 129, 124 }, // left = d117
|
||||
{ 36, 20, 26, 136, 62, 164, 33, 77, 154 }, // left = d153
|
||||
{ 45, 18, 32, 130, 90, 157, 40, 79, 91 }, // left = d207
|
||||
{ 45, 26, 28, 129, 45, 129, 49, 147, 123 }, // left = d63
|
||||
{ 38, 44, 51, 136, 74, 162, 57, 97, 121 } // left = tm
|
||||
},
|
||||
{
|
||||
// above = d153
|
||||
{ 75, 17, 22, 136, 138, 185, 32, 34, 166 }, // left = dc
|
||||
{ 56, 39, 58, 133, 117, 173, 48, 53, 187 }, // left = v
|
||||
{ 35, 21, 12, 161, 212, 207, 20, 23, 145 }, // left = h
|
||||
{ 56, 29, 19, 117, 109, 181, 55, 68, 112 }, // left = d45
|
||||
{ 47, 29, 17, 153, 64, 220, 59, 51, 114 }, // left = d135
|
||||
{ 46, 16, 24, 136, 76, 147, 41, 64, 172 }, // left = d117
|
||||
{ 34, 17, 11, 108, 152, 187, 13, 15, 209 }, // left = d153
|
||||
{ 51, 24, 14, 115, 133, 209, 32, 26, 104 }, // left = d207
|
||||
{ 55, 30, 18, 122, 79, 179, 44, 88, 116 }, // left = d63
|
||||
{ 37, 49, 25, 129, 168, 164, 41, 54, 148 } // left = tm
|
||||
},
|
||||
{
|
||||
// above = d207
|
||||
{ 82, 22, 32, 127, 143, 213, 39, 41, 70 }, // left = dc
|
||||
{ 62, 44, 61, 123, 105, 189, 48, 57, 64 }, // left = v
|
||||
{ 47, 25, 17, 175, 222, 220, 24, 30, 86 }, // left = h
|
||||
{ 68, 36, 17, 106, 102, 206, 59, 74, 74 }, // left = d45
|
||||
{ 57, 39, 23, 151, 68, 216, 55, 63, 58 }, // left = d135
|
||||
{ 49, 30, 35, 141, 70, 168, 82, 40, 115 }, // left = d117
|
||||
{ 51, 25, 15, 136, 129, 202, 38, 35, 139 }, // left = d153
|
||||
{ 68, 26, 16, 111, 141, 215, 29, 28, 28 }, // left = d207
|
||||
{ 59, 39, 19, 114, 75, 180, 77, 104, 42 }, // left = d63
|
||||
{ 40, 61, 26, 126, 152, 206, 61, 59, 93 } // left = tm
|
||||
},
|
||||
{
|
||||
// above = d63
|
||||
{ 78, 23, 39, 111, 117, 170, 74, 124, 94 }, // left = dc
|
||||
{ 48, 34, 86, 101, 92, 146, 78, 179, 134 }, // left = v
|
||||
{ 47, 22, 24, 138, 187, 178, 68, 69, 59 }, // left = h
|
||||
{ 56, 25, 33, 105, 112, 187, 95, 177, 129 }, // left = d45
|
||||
{ 48, 31, 27, 114, 63, 183, 82, 116, 56 }, // left = d135
|
||||
{ 43, 28, 37, 121, 63, 123, 61, 192, 169 }, // left = d117
|
||||
{ 42, 17, 24, 109, 97, 177, 56, 76, 122 }, // left = d153
|
||||
{ 58, 18, 28, 105, 139, 182, 70, 92, 63 }, // left = d207
|
||||
{ 46, 23, 32, 74, 86, 150, 67, 183, 88 }, // left = d63
|
||||
{ 36, 38, 48, 92, 122, 165, 88, 137, 91 } // left = tm
|
||||
},
|
||||
{
|
||||
// above = tm
|
||||
{ 65, 70, 60, 155, 159, 199, 61, 60, 81 }, // left = dc
|
||||
{ 44, 78, 115, 132, 119, 173, 71, 112, 93 }, // left = v
|
||||
{ 39, 38, 21, 184, 227, 206, 42, 32, 64 }, // left = h
|
||||
{ 58, 47, 36, 124, 137, 193, 80, 82, 78 }, // left = d45
|
||||
{ 49, 50, 35, 144, 95, 205, 63, 78, 59 }, // left = d135
|
||||
{ 41, 53, 52, 148, 71, 142, 65, 128, 51 }, // left = d117
|
||||
{ 40, 36, 28, 143, 143, 202, 40, 55, 137 }, // left = d153
|
||||
{ 52, 34, 29, 129, 183, 227, 42, 35, 43 }, // left = d207
|
||||
{ 42, 44, 44, 104, 105, 164, 64, 130, 80 }, // left = d63
|
||||
{ 43, 81, 53, 140, 169, 204, 68, 84, 72 } // left = tm
|
||||
}
|
||||
};
|
||||
|
||||
const vpx_prob vp9_kf_uv_mode_prob[INTRA_MODES][INTRA_MODES - 1] = {
|
||||
{ 144, 11, 54, 157, 195, 130, 46, 58, 108 }, // y = dc
|
||||
{ 118, 15, 123, 148, 131, 101, 44, 93, 131 }, // y = v
|
||||
{ 113, 12, 23, 188, 226, 142, 26, 32, 125 }, // y = h
|
||||
{ 120, 11, 50, 123, 163, 135, 64, 77, 103 }, // y = d45
|
||||
{ 113, 9, 36, 155, 111, 157, 32, 44, 161 }, // y = d135
|
||||
{ 116, 9, 55, 176, 76, 96, 37, 61, 149 }, // y = d117
|
||||
{ 115, 9, 28, 141, 161, 167, 21, 25, 193 }, // y = d153
|
||||
{ 120, 12, 32, 145, 195, 142, 32, 38, 86 }, // y = d207
|
||||
{ 116, 12, 64, 120, 140, 125, 49, 115, 121 }, // y = d63
|
||||
{ 102, 19, 66, 162, 182, 122, 35, 59, 128 } // y = tm
|
||||
};
|
||||
|
||||
static const vpx_prob default_if_y_probs[BLOCK_SIZE_GROUPS][INTRA_MODES - 1] = {
|
||||
{ 65, 32, 18, 144, 162, 194, 41, 51, 98 }, // block_size < 8x8
|
||||
{ 132, 68, 18, 165, 217, 196, 45, 40, 78 }, // block_size < 16x16
|
||||
{ 173, 80, 19, 176, 240, 193, 64, 35, 46 }, // block_size < 32x32
|
||||
{ 221, 135, 38, 194, 248, 121, 96, 85, 29 } // block_size >= 32x32
|
||||
};
|
||||
|
||||
static const vpx_prob default_if_uv_probs[INTRA_MODES][INTRA_MODES - 1] = {
|
||||
{ 120, 7, 76, 176, 208, 126, 28, 54, 103 }, // y = dc
|
||||
{ 48, 12, 154, 155, 139, 90, 34, 117, 119 }, // y = v
|
||||
{ 67, 6, 25, 204, 243, 158, 13, 21, 96 }, // y = h
|
||||
{ 97, 5, 44, 131, 176, 139, 48, 68, 97 }, // y = d45
|
||||
{ 83, 5, 42, 156, 111, 152, 26, 49, 152 }, // y = d135
|
||||
{ 80, 5, 58, 178, 74, 83, 33, 62, 145 }, // y = d117
|
||||
{ 86, 5, 32, 154, 192, 168, 14, 22, 163 }, // y = d153
|
||||
{ 85, 5, 32, 156, 216, 148, 19, 29, 73 }, // y = d207
|
||||
{ 77, 7, 64, 116, 132, 122, 37, 126, 120 }, // y = d63
|
||||
{ 101, 21, 107, 181, 192, 103, 19, 67, 125 } // y = tm
|
||||
};
|
||||
|
||||
const vpx_prob vp9_kf_partition_probs[PARTITION_CONTEXTS]
|
||||
[PARTITION_TYPES - 1] = {
|
||||
// 8x8 -> 4x4
|
||||
{ 158, 97, 94 }, // a/l both not split
|
||||
{ 93, 24, 99 }, // a split, l not split
|
||||
{ 85, 119, 44 }, // l split, a not split
|
||||
{ 62, 59, 67 }, // a/l both split
|
||||
|
||||
// 16x16 -> 8x8
|
||||
{ 149, 53, 53 }, // a/l both not split
|
||||
{ 94, 20, 48 }, // a split, l not split
|
||||
{ 83, 53, 24 }, // l split, a not split
|
||||
{ 52, 18, 18 }, // a/l both split
|
||||
|
||||
// 32x32 -> 16x16
|
||||
{ 150, 40, 39 }, // a/l both not split
|
||||
{ 78, 12, 26 }, // a split, l not split
|
||||
{ 67, 33, 11 }, // l split, a not split
|
||||
{ 24, 7, 5 }, // a/l both split
|
||||
|
||||
// 64x64 -> 32x32
|
||||
{ 174, 35, 49 }, // a/l both not split
|
||||
{ 68, 11, 27 }, // a split, l not split
|
||||
{ 57, 15, 9 }, // l split, a not split
|
||||
{ 12, 3, 3 }, // a/l both split
|
||||
};
|
||||
|
||||
static const vpx_prob
|
||||
default_partition_probs[PARTITION_CONTEXTS][PARTITION_TYPES - 1] = {
|
||||
// 8x8 -> 4x4
|
||||
{ 199, 122, 141 }, // a/l both not split
|
||||
{ 147, 63, 159 }, // a split, l not split
|
||||
{ 148, 133, 118 }, // l split, a not split
|
||||
{ 121, 104, 114 }, // a/l both split
|
||||
// 16x16 -> 8x8
|
||||
{ 174, 73, 87 }, // a/l both not split
|
||||
{ 92, 41, 83 }, // a split, l not split
|
||||
{ 82, 99, 50 }, // l split, a not split
|
||||
{ 53, 39, 39 }, // a/l both split
|
||||
// 32x32 -> 16x16
|
||||
{ 177, 58, 59 }, // a/l both not split
|
||||
{ 68, 26, 63 }, // a split, l not split
|
||||
{ 52, 79, 25 }, // l split, a not split
|
||||
{ 17, 14, 12 }, // a/l both split
|
||||
// 64x64 -> 32x32
|
||||
{ 222, 34, 30 }, // a/l both not split
|
||||
{ 72, 16, 44 }, // a split, l not split
|
||||
{ 58, 32, 12 }, // l split, a not split
|
||||
{ 10, 7, 6 }, // a/l both split
|
||||
};
|
||||
|
||||
static const vpx_prob
|
||||
default_inter_mode_probs[INTER_MODE_CONTEXTS][INTER_MODES - 1] = {
|
||||
{ 2, 173, 34 }, // 0 = both zero mv
|
||||
{ 7, 145, 85 }, // 1 = one zero mv + one a predicted mv
|
||||
{ 7, 166, 63 }, // 2 = two predicted mvs
|
||||
{ 7, 94, 66 }, // 3 = one predicted/zero and one new mv
|
||||
{ 8, 64, 46 }, // 4 = two new mvs
|
||||
{ 17, 81, 31 }, // 5 = one intra neighbour + x
|
||||
{ 25, 29, 30 }, // 6 = two intra neighbours
|
||||
};
|
||||
|
||||
/* Array indices are identical to previously-existing INTRAMODECONTEXTNODES. */
|
||||
const vpx_tree_index vp9_intra_mode_tree[TREE_SIZE(INTRA_MODES)] = {
|
||||
-DC_PRED, 2, /* 0 = DC_NODE */
|
||||
-TM_PRED, 4, /* 1 = TM_NODE */
|
||||
-V_PRED, 6, /* 2 = V_NODE */
|
||||
8, 12, /* 3 = COM_NODE */
|
||||
-H_PRED, 10, /* 4 = H_NODE */
|
||||
-D135_PRED, -D117_PRED, /* 5 = D135_NODE */
|
||||
-D45_PRED, 14, /* 6 = D45_NODE */
|
||||
-D63_PRED, 16, /* 7 = D63_NODE */
|
||||
-D153_PRED, -D207_PRED /* 8 = D153_NODE */
|
||||
};
|
||||
|
||||
const vpx_tree_index vp9_inter_mode_tree[TREE_SIZE(INTER_MODES)] = {
|
||||
-INTER_OFFSET(ZEROMV), 2, -INTER_OFFSET(NEARESTMV), 4, -INTER_OFFSET(NEARMV),
|
||||
-INTER_OFFSET(NEWMV)
|
||||
};
|
||||
|
||||
const vpx_tree_index vp9_partition_tree[TREE_SIZE(PARTITION_TYPES)] = {
|
||||
-PARTITION_NONE, 2, -PARTITION_HORZ, 4, -PARTITION_VERT, -PARTITION_SPLIT
|
||||
};
|
||||
|
||||
static const vpx_prob default_intra_inter_p[INTRA_INTER_CONTEXTS] = { 9, 102,
|
||||
187,
|
||||
225 };
|
||||
|
||||
static const vpx_prob default_comp_inter_p[COMP_INTER_CONTEXTS] = { 239, 183,
|
||||
119, 96,
|
||||
41 };
|
||||
|
||||
static const vpx_prob default_comp_ref_p[REF_CONTEXTS] = { 50, 126, 123, 221,
|
||||
226 };
|
||||
|
||||
static const vpx_prob default_single_ref_p[REF_CONTEXTS][2] = {
|
||||
{ 33, 16 }, { 77, 74 }, { 142, 142 }, { 172, 170 }, { 238, 247 }
|
||||
};
|
||||
|
||||
static const struct tx_probs default_tx_probs = { { { 3, 136, 37 },
|
||||
{ 5, 52, 13 } },
|
||||
|
||||
{ { 20, 152 }, { 15, 101 } },
|
||||
|
||||
{ { 100 }, { 66 } } };
|
||||
|
||||
void tx_counts_to_branch_counts_32x32(const unsigned int *tx_count_32x32p,
|
||||
unsigned int (*ct_32x32p)[2]) {
|
||||
ct_32x32p[0][0] = tx_count_32x32p[TX_4X4];
|
||||
ct_32x32p[0][1] = tx_count_32x32p[TX_8X8] + tx_count_32x32p[TX_16X16] +
|
||||
tx_count_32x32p[TX_32X32];
|
||||
ct_32x32p[1][0] = tx_count_32x32p[TX_8X8];
|
||||
ct_32x32p[1][1] = tx_count_32x32p[TX_16X16] + tx_count_32x32p[TX_32X32];
|
||||
ct_32x32p[2][0] = tx_count_32x32p[TX_16X16];
|
||||
ct_32x32p[2][1] = tx_count_32x32p[TX_32X32];
|
||||
}
|
||||
|
||||
void tx_counts_to_branch_counts_16x16(const unsigned int *tx_count_16x16p,
|
||||
unsigned int (*ct_16x16p)[2]) {
|
||||
ct_16x16p[0][0] = tx_count_16x16p[TX_4X4];
|
||||
ct_16x16p[0][1] = tx_count_16x16p[TX_8X8] + tx_count_16x16p[TX_16X16];
|
||||
ct_16x16p[1][0] = tx_count_16x16p[TX_8X8];
|
||||
ct_16x16p[1][1] = tx_count_16x16p[TX_16X16];
|
||||
}
|
||||
|
||||
void tx_counts_to_branch_counts_8x8(const unsigned int *tx_count_8x8p,
|
||||
unsigned int (*ct_8x8p)[2]) {
|
||||
ct_8x8p[0][0] = tx_count_8x8p[TX_4X4];
|
||||
ct_8x8p[0][1] = tx_count_8x8p[TX_8X8];
|
||||
}
|
||||
|
||||
static const vpx_prob default_skip_probs[SKIP_CONTEXTS] = { 192, 128, 64 };
|
||||
|
||||
static const vpx_prob default_switchable_interp_prob[SWITCHABLE_FILTER_CONTEXTS]
|
||||
[SWITCHABLE_FILTERS - 1] = {
|
||||
{ 235, 162 },
|
||||
{ 36, 255 },
|
||||
{ 34, 3 },
|
||||
{ 149, 144 },
|
||||
};
|
||||
|
||||
static void init_mode_probs(FRAME_CONTEXT *fc) {
|
||||
vp9_copy(fc->uv_mode_prob, default_if_uv_probs);
|
||||
vp9_copy(fc->y_mode_prob, default_if_y_probs);
|
||||
vp9_copy(fc->switchable_interp_prob, default_switchable_interp_prob);
|
||||
vp9_copy(fc->partition_prob, default_partition_probs);
|
||||
vp9_copy(fc->intra_inter_prob, default_intra_inter_p);
|
||||
vp9_copy(fc->comp_inter_prob, default_comp_inter_p);
|
||||
vp9_copy(fc->comp_ref_prob, default_comp_ref_p);
|
||||
vp9_copy(fc->single_ref_prob, default_single_ref_p);
|
||||
fc->tx_probs = default_tx_probs;
|
||||
vp9_copy(fc->skip_probs, default_skip_probs);
|
||||
vp9_copy(fc->inter_mode_probs, default_inter_mode_probs);
|
||||
}
|
||||
|
||||
const vpx_tree_index vp9_switchable_interp_tree[TREE_SIZE(
|
||||
SWITCHABLE_FILTERS)] = { -EIGHTTAP, 2, -EIGHTTAP_SMOOTH, -EIGHTTAP_SHARP };
|
||||
|
||||
void vp9_adapt_mode_probs(VP9_COMMON *cm) {
|
||||
int i, j;
|
||||
FRAME_CONTEXT *fc = cm->fc;
|
||||
const FRAME_CONTEXT *pre_fc = &cm->frame_contexts[cm->frame_context_idx];
|
||||
const FRAME_COUNTS *counts = &cm->counts;
|
||||
|
||||
for (i = 0; i < INTRA_INTER_CONTEXTS; i++)
|
||||
fc->intra_inter_prob[i] = mode_mv_merge_probs(pre_fc->intra_inter_prob[i],
|
||||
counts->intra_inter[i]);
|
||||
for (i = 0; i < COMP_INTER_CONTEXTS; i++)
|
||||
fc->comp_inter_prob[i] =
|
||||
mode_mv_merge_probs(pre_fc->comp_inter_prob[i], counts->comp_inter[i]);
|
||||
for (i = 0; i < REF_CONTEXTS; i++)
|
||||
fc->comp_ref_prob[i] =
|
||||
mode_mv_merge_probs(pre_fc->comp_ref_prob[i], counts->comp_ref[i]);
|
||||
for (i = 0; i < REF_CONTEXTS; i++)
|
||||
for (j = 0; j < 2; j++)
|
||||
fc->single_ref_prob[i][j] = mode_mv_merge_probs(
|
||||
pre_fc->single_ref_prob[i][j], counts->single_ref[i][j]);
|
||||
|
||||
for (i = 0; i < INTER_MODE_CONTEXTS; i++)
|
||||
vpx_tree_merge_probs(vp9_inter_mode_tree, pre_fc->inter_mode_probs[i],
|
||||
counts->inter_mode[i], fc->inter_mode_probs[i]);
|
||||
|
||||
for (i = 0; i < BLOCK_SIZE_GROUPS; i++)
|
||||
vpx_tree_merge_probs(vp9_intra_mode_tree, pre_fc->y_mode_prob[i],
|
||||
counts->y_mode[i], fc->y_mode_prob[i]);
|
||||
|
||||
for (i = 0; i < INTRA_MODES; ++i)
|
||||
vpx_tree_merge_probs(vp9_intra_mode_tree, pre_fc->uv_mode_prob[i],
|
||||
counts->uv_mode[i], fc->uv_mode_prob[i]);
|
||||
|
||||
for (i = 0; i < PARTITION_CONTEXTS; i++)
|
||||
vpx_tree_merge_probs(vp9_partition_tree, pre_fc->partition_prob[i],
|
||||
counts->partition[i], fc->partition_prob[i]);
|
||||
|
||||
if (cm->interp_filter == SWITCHABLE) {
|
||||
for (i = 0; i < SWITCHABLE_FILTER_CONTEXTS; i++)
|
||||
vpx_tree_merge_probs(
|
||||
vp9_switchable_interp_tree, pre_fc->switchable_interp_prob[i],
|
||||
counts->switchable_interp[i], fc->switchable_interp_prob[i]);
|
||||
}
|
||||
|
||||
if (cm->tx_mode == TX_MODE_SELECT) {
|
||||
int j;
|
||||
unsigned int branch_ct_8x8p[TX_SIZES - 3][2];
|
||||
unsigned int branch_ct_16x16p[TX_SIZES - 2][2];
|
||||
unsigned int branch_ct_32x32p[TX_SIZES - 1][2];
|
||||
|
||||
for (i = 0; i < TX_SIZE_CONTEXTS; ++i) {
|
||||
tx_counts_to_branch_counts_8x8(counts->tx.p8x8[i], branch_ct_8x8p);
|
||||
for (j = 0; j < TX_SIZES - 3; ++j)
|
||||
fc->tx_probs.p8x8[i][j] =
|
||||
mode_mv_merge_probs(pre_fc->tx_probs.p8x8[i][j], branch_ct_8x8p[j]);
|
||||
|
||||
tx_counts_to_branch_counts_16x16(counts->tx.p16x16[i], branch_ct_16x16p);
|
||||
for (j = 0; j < TX_SIZES - 2; ++j)
|
||||
fc->tx_probs.p16x16[i][j] = mode_mv_merge_probs(
|
||||
pre_fc->tx_probs.p16x16[i][j], branch_ct_16x16p[j]);
|
||||
|
||||
tx_counts_to_branch_counts_32x32(counts->tx.p32x32[i], branch_ct_32x32p);
|
||||
for (j = 0; j < TX_SIZES - 1; ++j)
|
||||
fc->tx_probs.p32x32[i][j] = mode_mv_merge_probs(
|
||||
pre_fc->tx_probs.p32x32[i][j], branch_ct_32x32p[j]);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < SKIP_CONTEXTS; ++i)
|
||||
fc->skip_probs[i] =
|
||||
mode_mv_merge_probs(pre_fc->skip_probs[i], counts->skip[i]);
|
||||
}
|
||||
|
||||
static void set_default_lf_deltas(struct loopfilter *lf) {
|
||||
lf->mode_ref_delta_enabled = 1;
|
||||
lf->mode_ref_delta_update = 1;
|
||||
|
||||
lf->ref_deltas[INTRA_FRAME] = 1;
|
||||
lf->ref_deltas[LAST_FRAME] = 0;
|
||||
lf->ref_deltas[GOLDEN_FRAME] = -1;
|
||||
lf->ref_deltas[ALTREF_FRAME] = -1;
|
||||
|
||||
lf->mode_deltas[0] = 0;
|
||||
lf->mode_deltas[1] = 0;
|
||||
}
|
||||
|
||||
void vp9_setup_past_independence(VP9_COMMON *cm) {
|
||||
// Reset the segment feature data to the default stats:
|
||||
// Features disabled, 0, with delta coding (Default state).
|
||||
struct loopfilter *const lf = &cm->lf;
|
||||
|
||||
int i;
|
||||
vp9_clearall_segfeatures(&cm->seg);
|
||||
cm->seg.abs_delta = SEGMENT_DELTADATA;
|
||||
|
||||
if (cm->last_frame_seg_map)
|
||||
memset(cm->last_frame_seg_map, 0, (cm->mi_rows * cm->mi_cols));
|
||||
|
||||
if (cm->current_frame_seg_map)
|
||||
memset(cm->current_frame_seg_map, 0, (cm->mi_rows * cm->mi_cols));
|
||||
|
||||
// Reset the mode ref deltas for loop filter
|
||||
vp9_zero(lf->last_ref_deltas);
|
||||
vp9_zero(lf->last_mode_deltas);
|
||||
set_default_lf_deltas(lf);
|
||||
|
||||
// To force update of the sharpness
|
||||
lf->last_sharpness_level = -1;
|
||||
|
||||
vp9_default_coef_probs(cm);
|
||||
init_mode_probs(cm->fc);
|
||||
vp9_init_mv_probs(cm);
|
||||
cm->fc->initialized = 1;
|
||||
|
||||
if (cm->frame_type == KEY_FRAME || cm->error_resilient_mode ||
|
||||
cm->reset_frame_context == 3) {
|
||||
// Reset all frame contexts.
|
||||
for (i = 0; i < FRAME_CONTEXTS; ++i) cm->frame_contexts[i] = *cm->fc;
|
||||
} else if (cm->reset_frame_context == 2) {
|
||||
// Reset only the frame context specified in the frame header.
|
||||
cm->frame_contexts[cm->frame_context_idx] = *cm->fc;
|
||||
}
|
||||
|
||||
// prev_mip will only be allocated in encoder.
|
||||
if (frame_is_intra_only(cm) && cm->prev_mip)
|
||||
memset(cm->prev_mip, 0,
|
||||
cm->mi_stride * (cm->mi_rows + 1) * sizeof(*cm->prev_mip));
|
||||
|
||||
vp9_zero(cm->ref_frame_sign_bias);
|
||||
|
||||
cm->frame_context_idx = 0;
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* 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 VPX_VP9_COMMON_VP9_ENTROPYMODE_H_
|
||||
#define VPX_VP9_COMMON_VP9_ENTROPYMODE_H_
|
||||
|
||||
#include "vp9/common/vp9_entropy.h"
|
||||
#include "vp9/common/vp9_entropymv.h"
|
||||
#include "vp9/common/vp9_filter.h"
|
||||
#include "vpx_dsp/vpx_filter.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define BLOCK_SIZE_GROUPS 4
|
||||
|
||||
#define TX_SIZE_CONTEXTS 2
|
||||
|
||||
#define INTER_OFFSET(mode) ((mode)-NEARESTMV)
|
||||
|
||||
struct VP9Common;
|
||||
|
||||
struct tx_probs {
|
||||
vpx_prob p32x32[TX_SIZE_CONTEXTS][TX_SIZES - 1];
|
||||
vpx_prob p16x16[TX_SIZE_CONTEXTS][TX_SIZES - 2];
|
||||
vpx_prob p8x8[TX_SIZE_CONTEXTS][TX_SIZES - 3];
|
||||
};
|
||||
|
||||
struct tx_counts {
|
||||
unsigned int p32x32[TX_SIZE_CONTEXTS][TX_SIZES];
|
||||
unsigned int p16x16[TX_SIZE_CONTEXTS][TX_SIZES - 1];
|
||||
unsigned int p8x8[TX_SIZE_CONTEXTS][TX_SIZES - 2];
|
||||
unsigned int tx_totals[TX_SIZES];
|
||||
};
|
||||
|
||||
typedef struct frame_contexts {
|
||||
vpx_prob y_mode_prob[BLOCK_SIZE_GROUPS][INTRA_MODES - 1];
|
||||
vpx_prob uv_mode_prob[INTRA_MODES][INTRA_MODES - 1];
|
||||
vpx_prob partition_prob[PARTITION_CONTEXTS][PARTITION_TYPES - 1];
|
||||
vp9_coeff_probs_model coef_probs[TX_SIZES][PLANE_TYPES];
|
||||
vpx_prob switchable_interp_prob[SWITCHABLE_FILTER_CONTEXTS]
|
||||
[SWITCHABLE_FILTERS - 1];
|
||||
vpx_prob inter_mode_probs[INTER_MODE_CONTEXTS][INTER_MODES - 1];
|
||||
vpx_prob intra_inter_prob[INTRA_INTER_CONTEXTS];
|
||||
vpx_prob comp_inter_prob[COMP_INTER_CONTEXTS];
|
||||
vpx_prob single_ref_prob[REF_CONTEXTS][2];
|
||||
vpx_prob comp_ref_prob[REF_CONTEXTS];
|
||||
struct tx_probs tx_probs;
|
||||
vpx_prob skip_probs[SKIP_CONTEXTS];
|
||||
nmv_context nmvc;
|
||||
int initialized;
|
||||
} FRAME_CONTEXT;
|
||||
|
||||
typedef struct FRAME_COUNTS {
|
||||
unsigned int y_mode[BLOCK_SIZE_GROUPS][INTRA_MODES];
|
||||
unsigned int uv_mode[INTRA_MODES][INTRA_MODES];
|
||||
unsigned int partition[PARTITION_CONTEXTS][PARTITION_TYPES];
|
||||
vp9_coeff_count_model coef[TX_SIZES][PLANE_TYPES];
|
||||
unsigned int eob_branch[TX_SIZES][PLANE_TYPES][REF_TYPES][COEF_BANDS]
|
||||
[COEFF_CONTEXTS];
|
||||
unsigned int switchable_interp[SWITCHABLE_FILTER_CONTEXTS]
|
||||
[SWITCHABLE_FILTERS];
|
||||
unsigned int inter_mode[INTER_MODE_CONTEXTS][INTER_MODES];
|
||||
unsigned int intra_inter[INTRA_INTER_CONTEXTS][2];
|
||||
unsigned int comp_inter[COMP_INTER_CONTEXTS][2];
|
||||
unsigned int single_ref[REF_CONTEXTS][2][2];
|
||||
unsigned int comp_ref[REF_CONTEXTS][2];
|
||||
struct tx_counts tx;
|
||||
unsigned int skip[SKIP_CONTEXTS][2];
|
||||
nmv_context_counts mv;
|
||||
} FRAME_COUNTS;
|
||||
|
||||
extern const vpx_prob vp9_kf_uv_mode_prob[INTRA_MODES][INTRA_MODES - 1];
|
||||
extern const vpx_prob vp9_kf_y_mode_prob[INTRA_MODES][INTRA_MODES]
|
||||
[INTRA_MODES - 1];
|
||||
extern const vpx_prob vp9_kf_partition_probs[PARTITION_CONTEXTS]
|
||||
[PARTITION_TYPES - 1];
|
||||
extern const vpx_tree_index vp9_intra_mode_tree[TREE_SIZE(INTRA_MODES)];
|
||||
extern const vpx_tree_index vp9_inter_mode_tree[TREE_SIZE(INTER_MODES)];
|
||||
extern const vpx_tree_index vp9_partition_tree[TREE_SIZE(PARTITION_TYPES)];
|
||||
extern const vpx_tree_index
|
||||
vp9_switchable_interp_tree[TREE_SIZE(SWITCHABLE_FILTERS)];
|
||||
|
||||
void vp9_setup_past_independence(struct VP9Common *cm);
|
||||
|
||||
void vp9_adapt_mode_probs(struct VP9Common *cm);
|
||||
|
||||
void tx_counts_to_branch_counts_32x32(const unsigned int *tx_count_32x32p,
|
||||
unsigned int (*ct_32x32p)[2]);
|
||||
void tx_counts_to_branch_counts_16x16(const unsigned int *tx_count_16x16p,
|
||||
unsigned int (*ct_16x16p)[2]);
|
||||
void tx_counts_to_branch_counts_8x8(const unsigned int *tx_count_8x8p,
|
||||
unsigned int (*ct_8x8p)[2]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_COMMON_VP9_ENTROPYMODE_H_
|
||||
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* 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/common/vp9_onyxc_int.h"
|
||||
#include "vp9/common/vp9_entropymv.h"
|
||||
|
||||
const vpx_tree_index vp9_mv_joint_tree[TREE_SIZE(MV_JOINTS)] = {
|
||||
-MV_JOINT_ZERO, 2, -MV_JOINT_HNZVZ, 4, -MV_JOINT_HZVNZ, -MV_JOINT_HNZVNZ
|
||||
};
|
||||
|
||||
const vpx_tree_index vp9_mv_class_tree[TREE_SIZE(MV_CLASSES)] = {
|
||||
-MV_CLASS_0, 2, -MV_CLASS_1, 4, 6,
|
||||
8, -MV_CLASS_2, -MV_CLASS_3, 10, 12,
|
||||
-MV_CLASS_4, -MV_CLASS_5, -MV_CLASS_6, 14, 16,
|
||||
18, -MV_CLASS_7, -MV_CLASS_8, -MV_CLASS_9, -MV_CLASS_10,
|
||||
};
|
||||
|
||||
const vpx_tree_index vp9_mv_class0_tree[TREE_SIZE(CLASS0_SIZE)] = { -0, -1 };
|
||||
|
||||
const vpx_tree_index vp9_mv_fp_tree[TREE_SIZE(MV_FP_SIZE)] = { -0, 2, -1,
|
||||
4, -2, -3 };
|
||||
|
||||
static const nmv_context default_nmv_context = {
|
||||
{ 32, 64, 96 },
|
||||
{ {
|
||||
// Vertical component
|
||||
128, // sign
|
||||
{ 224, 144, 192, 168, 192, 176, 192, 198, 198, 245 }, // class
|
||||
{ 216 }, // class0
|
||||
{ 136, 140, 148, 160, 176, 192, 224, 234, 234, 240 }, // bits
|
||||
{ { 128, 128, 64 }, { 96, 112, 64 } }, // class0_fp
|
||||
{ 64, 96, 64 }, // fp
|
||||
160, // class0_hp bit
|
||||
128, // hp
|
||||
},
|
||||
{
|
||||
// Horizontal component
|
||||
128, // sign
|
||||
{ 216, 128, 176, 160, 176, 176, 192, 198, 198, 208 }, // class
|
||||
{ 208 }, // class0
|
||||
{ 136, 140, 148, 160, 176, 192, 224, 234, 234, 240 }, // bits
|
||||
{ { 128, 128, 64 }, { 96, 112, 64 } }, // class0_fp
|
||||
{ 64, 96, 64 }, // fp
|
||||
160, // class0_hp bit
|
||||
128, // hp
|
||||
} },
|
||||
};
|
||||
|
||||
static const uint8_t log_in_base_2[] = {
|
||||
0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 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, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7,
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 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, 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, 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, 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, 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,
|
||||
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, 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, 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, 9, 9, 9, 9, 9, 9, 9, 9,
|
||||
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
||||
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
||||
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
||||
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
||||
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
||||
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
||||
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
||||
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
||||
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
||||
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
||||
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
||||
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
||||
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
||||
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
||||
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
||||
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
||||
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
||||
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
||||
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
||||
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10
|
||||
};
|
||||
|
||||
static INLINE int mv_class_base(MV_CLASS_TYPE c) {
|
||||
return c ? CLASS0_SIZE << (c + 2) : 0;
|
||||
}
|
||||
|
||||
MV_CLASS_TYPE vp9_get_mv_class(int z, int *offset) {
|
||||
const MV_CLASS_TYPE c = (z >= CLASS0_SIZE * 4096)
|
||||
? MV_CLASS_10
|
||||
: (MV_CLASS_TYPE)log_in_base_2[z >> 3];
|
||||
if (offset) *offset = z - mv_class_base(c);
|
||||
return c;
|
||||
}
|
||||
|
||||
static void inc_mv_component(int v, nmv_component_counts *comp_counts, int incr,
|
||||
int usehp) {
|
||||
int s, z, c, o, d, e, f;
|
||||
assert(v != 0); /* should not be zero */
|
||||
s = v < 0;
|
||||
comp_counts->sign[s] += incr;
|
||||
z = (s ? -v : v) - 1; /* magnitude - 1 */
|
||||
|
||||
c = vp9_get_mv_class(z, &o);
|
||||
comp_counts->classes[c] += incr;
|
||||
|
||||
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) {
|
||||
comp_counts->class0[d] += incr;
|
||||
comp_counts->class0_fp[d][f] += incr;
|
||||
comp_counts->class0_hp[e] += usehp * incr;
|
||||
} else {
|
||||
int i;
|
||||
int b = c + CLASS0_BITS - 1; // number of bits
|
||||
for (i = 0; i < b; ++i) comp_counts->bits[i][((d >> i) & 1)] += incr;
|
||||
comp_counts->fp[f] += incr;
|
||||
comp_counts->hp[e] += usehp * incr;
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_inc_mv(const MV *mv, nmv_context_counts *counts) {
|
||||
if (counts != NULL) {
|
||||
const MV_JOINT_TYPE j = vp9_get_mv_joint(mv);
|
||||
++counts->joints[j];
|
||||
|
||||
if (mv_joint_vertical(j)) {
|
||||
inc_mv_component(mv->row, &counts->comps[0], 1, 1);
|
||||
}
|
||||
|
||||
if (mv_joint_horizontal(j)) {
|
||||
inc_mv_component(mv->col, &counts->comps[1], 1, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_adapt_mv_probs(VP9_COMMON *cm, int allow_hp) {
|
||||
int i, j;
|
||||
|
||||
nmv_context *fc = &cm->fc->nmvc;
|
||||
const nmv_context *pre_fc = &cm->frame_contexts[cm->frame_context_idx].nmvc;
|
||||
const nmv_context_counts *counts = &cm->counts.mv;
|
||||
|
||||
vpx_tree_merge_probs(vp9_mv_joint_tree, pre_fc->joints, counts->joints,
|
||||
fc->joints);
|
||||
|
||||
for (i = 0; i < 2; ++i) {
|
||||
nmv_component *comp = &fc->comps[i];
|
||||
const nmv_component *pre_comp = &pre_fc->comps[i];
|
||||
const nmv_component_counts *c = &counts->comps[i];
|
||||
|
||||
comp->sign = mode_mv_merge_probs(pre_comp->sign, c->sign);
|
||||
vpx_tree_merge_probs(vp9_mv_class_tree, pre_comp->classes, c->classes,
|
||||
comp->classes);
|
||||
vpx_tree_merge_probs(vp9_mv_class0_tree, pre_comp->class0, c->class0,
|
||||
comp->class0);
|
||||
|
||||
for (j = 0; j < MV_OFFSET_BITS; ++j)
|
||||
comp->bits[j] = mode_mv_merge_probs(pre_comp->bits[j], c->bits[j]);
|
||||
|
||||
for (j = 0; j < CLASS0_SIZE; ++j)
|
||||
vpx_tree_merge_probs(vp9_mv_fp_tree, pre_comp->class0_fp[j],
|
||||
c->class0_fp[j], comp->class0_fp[j]);
|
||||
|
||||
vpx_tree_merge_probs(vp9_mv_fp_tree, pre_comp->fp, c->fp, comp->fp);
|
||||
|
||||
if (allow_hp) {
|
||||
comp->class0_hp = mode_mv_merge_probs(pre_comp->class0_hp, c->class0_hp);
|
||||
comp->hp = mode_mv_merge_probs(pre_comp->hp, c->hp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_init_mv_probs(VP9_COMMON *cm) { cm->fc->nmvc = default_nmv_context; }
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* 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 VPX_VP9_COMMON_VP9_ENTROPYMV_H_
|
||||
#define VPX_VP9_COMMON_VP9_ENTROPYMV_H_
|
||||
|
||||
#include "./vpx_config.h"
|
||||
|
||||
#include "vpx_dsp/prob.h"
|
||||
|
||||
#include "vp9/common/vp9_mv.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct VP9Common;
|
||||
|
||||
void vp9_init_mv_probs(struct VP9Common *cm);
|
||||
|
||||
void vp9_adapt_mv_probs(struct VP9Common *cm, int allow_hp);
|
||||
|
||||
static INLINE int use_mv_hp(const MV *ref) {
|
||||
const int kMvRefThresh = 64; // threshold for use of high-precision 1/8 mv
|
||||
return abs(ref->row) < kMvRefThresh && abs(ref->col) < kMvRefThresh;
|
||||
}
|
||||
|
||||
#define MV_UPDATE_PROB 252
|
||||
|
||||
/* Symbols for coding which components are zero jointly */
|
||||
#define MV_JOINTS 4
|
||||
typedef enum {
|
||||
MV_JOINT_ZERO = 0, /* Zero vector */
|
||||
MV_JOINT_HNZVZ = 1, /* Vert zero, hor nonzero */
|
||||
MV_JOINT_HZVNZ = 2, /* Hor zero, vert nonzero */
|
||||
MV_JOINT_HNZVNZ = 3, /* Both components nonzero */
|
||||
} MV_JOINT_TYPE;
|
||||
|
||||
static INLINE int mv_joint_vertical(MV_JOINT_TYPE type) {
|
||||
return type == MV_JOINT_HZVNZ || type == MV_JOINT_HNZVNZ;
|
||||
}
|
||||
|
||||
static INLINE int mv_joint_horizontal(MV_JOINT_TYPE type) {
|
||||
return type == MV_JOINT_HNZVZ || type == MV_JOINT_HNZVNZ;
|
||||
}
|
||||
|
||||
/* Symbols for coding magnitude class of nonzero components */
|
||||
#define MV_CLASSES 11
|
||||
typedef enum {
|
||||
MV_CLASS_0 = 0, /* (0, 2] integer pel */
|
||||
MV_CLASS_1 = 1, /* (2, 4] integer pel */
|
||||
MV_CLASS_2 = 2, /* (4, 8] integer pel */
|
||||
MV_CLASS_3 = 3, /* (8, 16] integer pel */
|
||||
MV_CLASS_4 = 4, /* (16, 32] integer pel */
|
||||
MV_CLASS_5 = 5, /* (32, 64] integer pel */
|
||||
MV_CLASS_6 = 6, /* (64, 128] integer pel */
|
||||
MV_CLASS_7 = 7, /* (128, 256] integer pel */
|
||||
MV_CLASS_8 = 8, /* (256, 512] integer pel */
|
||||
MV_CLASS_9 = 9, /* (512, 1024] integer pel */
|
||||
MV_CLASS_10 = 10, /* (1024,2048] integer pel */
|
||||
} MV_CLASS_TYPE;
|
||||
|
||||
#define CLASS0_BITS 1 /* bits at integer precision for class 0 */
|
||||
#define CLASS0_SIZE (1 << CLASS0_BITS)
|
||||
#define MV_OFFSET_BITS (MV_CLASSES + CLASS0_BITS - 2)
|
||||
#define MV_FP_SIZE 4
|
||||
|
||||
#define MV_MAX_BITS (MV_CLASSES + CLASS0_BITS + 2)
|
||||
#define MV_MAX ((1 << MV_MAX_BITS) - 1)
|
||||
#define MV_VALS ((MV_MAX << 1) + 1)
|
||||
|
||||
#define MV_IN_USE_BITS 14
|
||||
#define MV_UPP ((1 << MV_IN_USE_BITS) - 1)
|
||||
#define MV_LOW (-(1 << MV_IN_USE_BITS))
|
||||
|
||||
extern const vpx_tree_index vp9_mv_joint_tree[];
|
||||
extern const vpx_tree_index vp9_mv_class_tree[];
|
||||
extern const vpx_tree_index vp9_mv_class0_tree[];
|
||||
extern const vpx_tree_index vp9_mv_fp_tree[];
|
||||
|
||||
typedef struct {
|
||||
vpx_prob sign;
|
||||
vpx_prob classes[MV_CLASSES - 1];
|
||||
vpx_prob class0[CLASS0_SIZE - 1];
|
||||
vpx_prob bits[MV_OFFSET_BITS];
|
||||
vpx_prob class0_fp[CLASS0_SIZE][MV_FP_SIZE - 1];
|
||||
vpx_prob fp[MV_FP_SIZE - 1];
|
||||
vpx_prob class0_hp;
|
||||
vpx_prob hp;
|
||||
} nmv_component;
|
||||
|
||||
typedef struct {
|
||||
vpx_prob joints[MV_JOINTS - 1];
|
||||
nmv_component comps[2];
|
||||
} nmv_context;
|
||||
|
||||
static INLINE MV_JOINT_TYPE vp9_get_mv_joint(const MV *mv) {
|
||||
if (mv->row == 0) {
|
||||
return mv->col == 0 ? MV_JOINT_ZERO : MV_JOINT_HNZVZ;
|
||||
} else {
|
||||
return mv->col == 0 ? MV_JOINT_HZVNZ : MV_JOINT_HNZVNZ;
|
||||
}
|
||||
}
|
||||
|
||||
MV_CLASS_TYPE vp9_get_mv_class(int z, int *offset);
|
||||
|
||||
typedef struct {
|
||||
unsigned int sign[2];
|
||||
unsigned int classes[MV_CLASSES];
|
||||
unsigned int class0[CLASS0_SIZE];
|
||||
unsigned int bits[MV_OFFSET_BITS][2];
|
||||
unsigned int class0_fp[CLASS0_SIZE][MV_FP_SIZE];
|
||||
unsigned int fp[MV_FP_SIZE];
|
||||
unsigned int class0_hp[2];
|
||||
unsigned int hp[2];
|
||||
} nmv_component_counts;
|
||||
|
||||
typedef struct {
|
||||
unsigned int joints[MV_JOINTS];
|
||||
nmv_component_counts comps[2];
|
||||
} nmv_context_counts;
|
||||
|
||||
void vp9_inc_mv(const MV *mv, nmv_context_counts *counts);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_COMMON_VP9_ENTROPYMV_H_
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* 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 VPX_VP9_COMMON_VP9_ENUMS_H_
|
||||
#define VPX_VP9_COMMON_VP9_ENUMS_H_
|
||||
|
||||
#include "./vpx_config.h"
|
||||
#include "vpx/vpx_integer.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define MI_SIZE_LOG2 3
|
||||
#define MI_BLOCK_SIZE_LOG2 (6 - MI_SIZE_LOG2) // 64 = 2^6
|
||||
|
||||
#define MI_SIZE (1 << MI_SIZE_LOG2) // pixels per mi-unit
|
||||
#define MI_BLOCK_SIZE (1 << MI_BLOCK_SIZE_LOG2) // mi-units per max block
|
||||
|
||||
#define MI_MASK (MI_BLOCK_SIZE - 1)
|
||||
|
||||
// Bitstream profiles indicated by 2-3 bits in the uncompressed header.
|
||||
// 00: Profile 0. 8-bit 4:2:0 only.
|
||||
// 10: Profile 1. 8-bit 4:4:4, 4:2:2, and 4:4:0.
|
||||
// 01: Profile 2. 10-bit and 12-bit color only, with 4:2:0 sampling.
|
||||
// 110: Profile 3. 10-bit and 12-bit color only, with 4:2:2/4:4:4/4:4:0
|
||||
// sampling.
|
||||
// 111: Undefined profile.
|
||||
typedef enum BITSTREAM_PROFILE {
|
||||
PROFILE_0,
|
||||
PROFILE_1,
|
||||
PROFILE_2,
|
||||
PROFILE_3,
|
||||
MAX_PROFILES
|
||||
} BITSTREAM_PROFILE;
|
||||
|
||||
typedef enum PARSE_RECON_FLAG { PARSE = 1, RECON = 2 } PARSE_RECON_FLAG;
|
||||
|
||||
#define BLOCK_4X4 0
|
||||
#define BLOCK_4X8 1
|
||||
#define BLOCK_8X4 2
|
||||
#define BLOCK_8X8 3
|
||||
#define BLOCK_8X16 4
|
||||
#define BLOCK_16X8 5
|
||||
#define BLOCK_16X16 6
|
||||
#define BLOCK_16X32 7
|
||||
#define BLOCK_32X16 8
|
||||
#define BLOCK_32X32 9
|
||||
#define BLOCK_32X64 10
|
||||
#define BLOCK_64X32 11
|
||||
#define BLOCK_64X64 12
|
||||
#define BLOCK_SIZES 13
|
||||
#define BLOCK_INVALID BLOCK_SIZES
|
||||
typedef uint8_t BLOCK_SIZE;
|
||||
|
||||
typedef enum PARTITION_TYPE {
|
||||
PARTITION_NONE,
|
||||
PARTITION_HORZ,
|
||||
PARTITION_VERT,
|
||||
PARTITION_SPLIT,
|
||||
PARTITION_TYPES,
|
||||
PARTITION_INVALID = PARTITION_TYPES
|
||||
} PARTITION_TYPE;
|
||||
|
||||
typedef char PARTITION_CONTEXT;
|
||||
#define PARTITION_PLOFFSET 4 // number of probability models per block size
|
||||
#define PARTITION_CONTEXTS (4 * PARTITION_PLOFFSET)
|
||||
|
||||
// block transform size
|
||||
typedef uint8_t TX_SIZE;
|
||||
#define TX_4X4 ((TX_SIZE)0) // 4x4 transform
|
||||
#define TX_8X8 ((TX_SIZE)1) // 8x8 transform
|
||||
#define TX_16X16 ((TX_SIZE)2) // 16x16 transform
|
||||
#define TX_32X32 ((TX_SIZE)3) // 32x32 transform
|
||||
#define TX_SIZES ((TX_SIZE)4)
|
||||
|
||||
// frame transform mode
|
||||
typedef enum {
|
||||
ONLY_4X4 = 0, // only 4x4 transform used
|
||||
ALLOW_8X8 = 1, // allow block transform size up to 8x8
|
||||
ALLOW_16X16 = 2, // allow block transform size up to 16x16
|
||||
ALLOW_32X32 = 3, // allow block transform size up to 32x32
|
||||
TX_MODE_SELECT = 4, // transform specified for each block
|
||||
TX_MODES = 5,
|
||||
} TX_MODE;
|
||||
|
||||
typedef enum {
|
||||
DCT_DCT = 0, // DCT in both horizontal and vertical
|
||||
ADST_DCT = 1, // ADST in vertical, DCT in horizontal
|
||||
DCT_ADST = 2, // DCT in vertical, ADST in horizontal
|
||||
ADST_ADST = 3, // ADST in both directions
|
||||
TX_TYPES = 4
|
||||
} TX_TYPE;
|
||||
|
||||
typedef enum {
|
||||
VP9_LAST_FLAG = 1 << 0,
|
||||
VP9_GOLD_FLAG = 1 << 1,
|
||||
VP9_ALT_FLAG = 1 << 2,
|
||||
} VP9_REFFRAME;
|
||||
|
||||
typedef enum { PLANE_TYPE_Y = 0, PLANE_TYPE_UV = 1, PLANE_TYPES } PLANE_TYPE;
|
||||
|
||||
#define DC_PRED 0 // Average of above and left pixels
|
||||
#define V_PRED 1 // Vertical
|
||||
#define H_PRED 2 // Horizontal
|
||||
#define D45_PRED 3 // Directional 45 deg = round(arctan(1/1) * 180/pi)
|
||||
#define D135_PRED 4 // Directional 135 deg = 180 - 45
|
||||
#define D117_PRED 5 // Directional 117 deg = 180 - 63
|
||||
#define D153_PRED 6 // Directional 153 deg = 180 - 27
|
||||
#define D207_PRED 7 // Directional 207 deg = 180 + 27
|
||||
#define D63_PRED 8 // Directional 63 deg = round(arctan(2/1) * 180/pi)
|
||||
#define TM_PRED 9 // True-motion
|
||||
#define NEARESTMV 10
|
||||
#define NEARMV 11
|
||||
#define ZEROMV 12
|
||||
#define NEWMV 13
|
||||
#define MB_MODE_COUNT 14
|
||||
typedef uint8_t PREDICTION_MODE;
|
||||
|
||||
#define INTRA_MODES (TM_PRED + 1)
|
||||
|
||||
#define INTER_MODES (1 + NEWMV - NEARESTMV)
|
||||
|
||||
#define SKIP_CONTEXTS 3
|
||||
#define INTER_MODE_CONTEXTS 7
|
||||
|
||||
/* Segment Feature Masks */
|
||||
#define MAX_MV_REF_CANDIDATES 2
|
||||
|
||||
#define INTRA_INTER_CONTEXTS 4
|
||||
#define COMP_INTER_CONTEXTS 5
|
||||
#define REF_CONTEXTS 5
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_COMMON_VP9_ENUMS_H_
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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/common/vp9_filter.h"
|
||||
|
||||
DECLARE_ALIGNED(256, static const InterpKernel,
|
||||
bilinear_filters[SUBPEL_SHIFTS]) = {
|
||||
{ 0, 0, 0, 128, 0, 0, 0, 0 }, { 0, 0, 0, 120, 8, 0, 0, 0 },
|
||||
{ 0, 0, 0, 112, 16, 0, 0, 0 }, { 0, 0, 0, 104, 24, 0, 0, 0 },
|
||||
{ 0, 0, 0, 96, 32, 0, 0, 0 }, { 0, 0, 0, 88, 40, 0, 0, 0 },
|
||||
{ 0, 0, 0, 80, 48, 0, 0, 0 }, { 0, 0, 0, 72, 56, 0, 0, 0 },
|
||||
{ 0, 0, 0, 64, 64, 0, 0, 0 }, { 0, 0, 0, 56, 72, 0, 0, 0 },
|
||||
{ 0, 0, 0, 48, 80, 0, 0, 0 }, { 0, 0, 0, 40, 88, 0, 0, 0 },
|
||||
{ 0, 0, 0, 32, 96, 0, 0, 0 }, { 0, 0, 0, 24, 104, 0, 0, 0 },
|
||||
{ 0, 0, 0, 16, 112, 0, 0, 0 }, { 0, 0, 0, 8, 120, 0, 0, 0 }
|
||||
};
|
||||
|
||||
// Lagrangian interpolation filter
|
||||
DECLARE_ALIGNED(256, static const InterpKernel,
|
||||
sub_pel_filters_8[SUBPEL_SHIFTS]) = {
|
||||
{ 0, 0, 0, 128, 0, 0, 0, 0 }, { 0, 1, -5, 126, 8, -3, 1, 0 },
|
||||
{ -1, 3, -10, 122, 18, -6, 2, 0 }, { -1, 4, -13, 118, 27, -9, 3, -1 },
|
||||
{ -1, 4, -16, 112, 37, -11, 4, -1 }, { -1, 5, -18, 105, 48, -14, 4, -1 },
|
||||
{ -1, 5, -19, 97, 58, -16, 5, -1 }, { -1, 6, -19, 88, 68, -18, 5, -1 },
|
||||
{ -1, 6, -19, 78, 78, -19, 6, -1 }, { -1, 5, -18, 68, 88, -19, 6, -1 },
|
||||
{ -1, 5, -16, 58, 97, -19, 5, -1 }, { -1, 4, -14, 48, 105, -18, 5, -1 },
|
||||
{ -1, 4, -11, 37, 112, -16, 4, -1 }, { -1, 3, -9, 27, 118, -13, 4, -1 },
|
||||
{ 0, 2, -6, 18, 122, -10, 3, -1 }, { 0, 1, -3, 8, 126, -5, 1, 0 }
|
||||
};
|
||||
|
||||
// DCT based filter
|
||||
DECLARE_ALIGNED(256, static const InterpKernel,
|
||||
sub_pel_filters_8s[SUBPEL_SHIFTS]) = {
|
||||
{ 0, 0, 0, 128, 0, 0, 0, 0 }, { -1, 3, -7, 127, 8, -3, 1, 0 },
|
||||
{ -2, 5, -13, 125, 17, -6, 3, -1 }, { -3, 7, -17, 121, 27, -10, 5, -2 },
|
||||
{ -4, 9, -20, 115, 37, -13, 6, -2 }, { -4, 10, -23, 108, 48, -16, 8, -3 },
|
||||
{ -4, 10, -24, 100, 59, -19, 9, -3 }, { -4, 11, -24, 90, 70, -21, 10, -4 },
|
||||
{ -4, 11, -23, 80, 80, -23, 11, -4 }, { -4, 10, -21, 70, 90, -24, 11, -4 },
|
||||
{ -3, 9, -19, 59, 100, -24, 10, -4 }, { -3, 8, -16, 48, 108, -23, 10, -4 },
|
||||
{ -2, 6, -13, 37, 115, -20, 9, -4 }, { -2, 5, -10, 27, 121, -17, 7, -3 },
|
||||
{ -1, 3, -6, 17, 125, -13, 5, -2 }, { 0, 1, -3, 8, 127, -7, 3, -1 }
|
||||
};
|
||||
|
||||
// freqmultiplier = 0.5
|
||||
DECLARE_ALIGNED(256, static const InterpKernel,
|
||||
sub_pel_filters_8lp[SUBPEL_SHIFTS]) = {
|
||||
{ 0, 0, 0, 128, 0, 0, 0, 0 }, { -3, -1, 32, 64, 38, 1, -3, 0 },
|
||||
{ -2, -2, 29, 63, 41, 2, -3, 0 }, { -2, -2, 26, 63, 43, 4, -4, 0 },
|
||||
{ -2, -3, 24, 62, 46, 5, -4, 0 }, { -2, -3, 21, 60, 49, 7, -4, 0 },
|
||||
{ -1, -4, 18, 59, 51, 9, -4, 0 }, { -1, -4, 16, 57, 53, 12, -4, -1 },
|
||||
{ -1, -4, 14, 55, 55, 14, -4, -1 }, { -1, -4, 12, 53, 57, 16, -4, -1 },
|
||||
{ 0, -4, 9, 51, 59, 18, -4, -1 }, { 0, -4, 7, 49, 60, 21, -3, -2 },
|
||||
{ 0, -4, 5, 46, 62, 24, -3, -2 }, { 0, -4, 4, 43, 63, 26, -2, -2 },
|
||||
{ 0, -3, 2, 41, 63, 29, -2, -2 }, { 0, -3, 1, 38, 64, 32, -1, -3 }
|
||||
};
|
||||
|
||||
// 4-tap filter
|
||||
DECLARE_ALIGNED(256, static const InterpKernel,
|
||||
sub_pel_filters_4[SUBPEL_SHIFTS]) = {
|
||||
{ 0, 0, 0, 128, 0, 0, 0, 0 }, { 0, 0, -4, 126, 8, -2, 0, 0 },
|
||||
{ 0, 0, -6, 120, 18, -4, 0, 0 }, { 0, 0, -8, 114, 28, -6, 0, 0 },
|
||||
{ 0, 0, -10, 108, 36, -6, 0, 0 }, { 0, 0, -12, 102, 46, -8, 0, 0 },
|
||||
{ 0, 0, -12, 94, 56, -10, 0, 0 }, { 0, 0, -12, 84, 66, -10, 0, 0 },
|
||||
{ 0, 0, -12, 76, 76, -12, 0, 0 }, { 0, 0, -10, 66, 84, -12, 0, 0 },
|
||||
{ 0, 0, -10, 56, 94, -12, 0, 0 }, { 0, 0, -8, 46, 102, -12, 0, 0 },
|
||||
{ 0, 0, -6, 36, 108, -10, 0, 0 }, { 0, 0, -6, 28, 114, -8, 0, 0 },
|
||||
{ 0, 0, -4, 18, 120, -6, 0, 0 }, { 0, 0, -2, 8, 126, -4, 0, 0 }
|
||||
};
|
||||
|
||||
const InterpKernel *vp9_filter_kernels[5] = {
|
||||
sub_pel_filters_8, sub_pel_filters_8lp, sub_pel_filters_8s, bilinear_filters,
|
||||
sub_pel_filters_4
|
||||
};
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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 VPX_VP9_COMMON_VP9_FILTER_H_
|
||||
#define VPX_VP9_COMMON_VP9_FILTER_H_
|
||||
|
||||
#include "./vpx_config.h"
|
||||
#include "vpx/vpx_integer.h"
|
||||
#include "vpx_dsp/vpx_filter.h"
|
||||
#include "vpx_ports/mem.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define EIGHTTAP 0
|
||||
#define EIGHTTAP_SMOOTH 1
|
||||
#define EIGHTTAP_SHARP 2
|
||||
#define SWITCHABLE_FILTERS 3 /* Number of switchable filters */
|
||||
#define BILINEAR 3
|
||||
#define FOURTAP 4
|
||||
// The codec can operate in four possible inter prediction filter mode:
|
||||
// 8-tap, 8-tap-smooth, 8-tap-sharp, and switching between the three.
|
||||
#define SWITCHABLE_FILTER_CONTEXTS (SWITCHABLE_FILTERS + 1)
|
||||
#define SWITCHABLE 4 /* should be the last one */
|
||||
|
||||
typedef uint8_t INTERP_FILTER;
|
||||
|
||||
extern const InterpKernel *vp9_filter_kernels[5];
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_COMMON_VP9_FILTER_H_
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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 "vp9/common/vp9_frame_buffers.h"
|
||||
#include "vpx_mem/vpx_mem.h"
|
||||
|
||||
int vp9_alloc_internal_frame_buffers(InternalFrameBufferList *list) {
|
||||
assert(list != NULL);
|
||||
vp9_free_internal_frame_buffers(list);
|
||||
|
||||
list->num_internal_frame_buffers =
|
||||
VP9_MAXIMUM_REF_BUFFERS + VPX_MAXIMUM_WORK_BUFFERS;
|
||||
list->int_fb = (InternalFrameBuffer *)vpx_calloc(
|
||||
list->num_internal_frame_buffers, sizeof(*list->int_fb));
|
||||
return (list->int_fb == NULL);
|
||||
}
|
||||
|
||||
void vp9_free_internal_frame_buffers(InternalFrameBufferList *list) {
|
||||
int i;
|
||||
|
||||
assert(list != NULL);
|
||||
|
||||
for (i = 0; i < list->num_internal_frame_buffers; ++i) {
|
||||
vpx_free(list->int_fb[i].data);
|
||||
list->int_fb[i].data = NULL;
|
||||
}
|
||||
vpx_free(list->int_fb);
|
||||
list->int_fb = NULL;
|
||||
}
|
||||
|
||||
int vp9_get_frame_buffer(void *cb_priv, size_t min_size,
|
||||
vpx_codec_frame_buffer_t *fb) {
|
||||
int i;
|
||||
InternalFrameBufferList *const int_fb_list =
|
||||
(InternalFrameBufferList *)cb_priv;
|
||||
if (int_fb_list == NULL) return -1;
|
||||
|
||||
// Find a free frame buffer.
|
||||
for (i = 0; i < int_fb_list->num_internal_frame_buffers; ++i) {
|
||||
if (!int_fb_list->int_fb[i].in_use) break;
|
||||
}
|
||||
|
||||
if (i == int_fb_list->num_internal_frame_buffers) return -1;
|
||||
|
||||
if (int_fb_list->int_fb[i].size < min_size) {
|
||||
vpx_free(int_fb_list->int_fb[i].data);
|
||||
// The data must be zeroed to fix a valgrind error from the C loop filter
|
||||
// due to access uninitialized memory in frame border. It could be
|
||||
// skipped if border were totally removed.
|
||||
int_fb_list->int_fb[i].data = (uint8_t *)vpx_calloc(1, min_size);
|
||||
if (!int_fb_list->int_fb[i].data) return -1;
|
||||
int_fb_list->int_fb[i].size = min_size;
|
||||
}
|
||||
|
||||
fb->data = int_fb_list->int_fb[i].data;
|
||||
fb->size = int_fb_list->int_fb[i].size;
|
||||
int_fb_list->int_fb[i].in_use = 1;
|
||||
|
||||
// Set the frame buffer's private data to point at the internal frame buffer.
|
||||
fb->priv = &int_fb_list->int_fb[i];
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vp9_release_frame_buffer(void *cb_priv, vpx_codec_frame_buffer_t *fb) {
|
||||
InternalFrameBuffer *const int_fb = (InternalFrameBuffer *)fb->priv;
|
||||
(void)cb_priv;
|
||||
if (int_fb) int_fb->in_use = 0;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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 VPX_VP9_COMMON_VP9_FRAME_BUFFERS_H_
|
||||
#define VPX_VP9_COMMON_VP9_FRAME_BUFFERS_H_
|
||||
|
||||
#include "vpx/vpx_frame_buffer.h"
|
||||
#include "vpx/vpx_integer.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct InternalFrameBuffer {
|
||||
uint8_t *data;
|
||||
size_t size;
|
||||
int in_use;
|
||||
} InternalFrameBuffer;
|
||||
|
||||
typedef struct InternalFrameBufferList {
|
||||
int num_internal_frame_buffers;
|
||||
InternalFrameBuffer *int_fb;
|
||||
} InternalFrameBufferList;
|
||||
|
||||
// Initializes |list|. Returns 0 on success.
|
||||
int vp9_alloc_internal_frame_buffers(InternalFrameBufferList *list);
|
||||
|
||||
// Free any data allocated to the frame buffers.
|
||||
void vp9_free_internal_frame_buffers(InternalFrameBufferList *list);
|
||||
|
||||
// Callback used by libvpx to request an external frame buffer. |cb_priv|
|
||||
// Callback private data, which points to an InternalFrameBufferList.
|
||||
// |min_size| is the minimum size in bytes needed to decode the next frame.
|
||||
// |fb| pointer to the frame buffer.
|
||||
int vp9_get_frame_buffer(void *cb_priv, size_t min_size,
|
||||
vpx_codec_frame_buffer_t *fb);
|
||||
|
||||
// Callback used by libvpx when there are no references to the frame buffer.
|
||||
// |cb_priv| is not used. |fb| pointer to the frame buffer.
|
||||
int vp9_release_frame_buffer(void *cb_priv, vpx_codec_frame_buffer_t *fb);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_COMMON_VP9_FRAME_BUFFERS_H_
|
||||
@@ -0,0 +1,396 @@
|
||||
/*
|
||||
* 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_rtcd.h"
|
||||
#include "./vpx_dsp_rtcd.h"
|
||||
#include "vp9/common/vp9_blockd.h"
|
||||
#include "vp9/common/vp9_idct.h"
|
||||
#include "vpx_dsp/inv_txfm.h"
|
||||
#include "vpx_ports/mem.h"
|
||||
|
||||
void vp9_iht4x4_16_add_c(const tran_low_t *input, uint8_t *dest, int stride,
|
||||
int tx_type) {
|
||||
const transform_2d IHT_4[] = {
|
||||
{ idct4_c, idct4_c }, // DCT_DCT = 0
|
||||
{ iadst4_c, idct4_c }, // ADST_DCT = 1
|
||||
{ idct4_c, iadst4_c }, // DCT_ADST = 2
|
||||
{ iadst4_c, iadst4_c } // ADST_ADST = 3
|
||||
};
|
||||
|
||||
int i, j;
|
||||
tran_low_t out[4 * 4];
|
||||
tran_low_t *outptr = out;
|
||||
tran_low_t temp_in[4], temp_out[4];
|
||||
|
||||
// inverse transform row vectors
|
||||
for (i = 0; i < 4; ++i) {
|
||||
IHT_4[tx_type].rows(input, outptr);
|
||||
input += 4;
|
||||
outptr += 4;
|
||||
}
|
||||
|
||||
// inverse transform column vectors
|
||||
for (i = 0; i < 4; ++i) {
|
||||
for (j = 0; j < 4; ++j) temp_in[j] = out[j * 4 + i];
|
||||
IHT_4[tx_type].cols(temp_in, temp_out);
|
||||
for (j = 0; j < 4; ++j) {
|
||||
dest[j * stride + i] = clip_pixel_add(dest[j * stride + i],
|
||||
ROUND_POWER_OF_TWO(temp_out[j], 4));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const transform_2d IHT_8[] = {
|
||||
{ idct8_c, idct8_c }, // DCT_DCT = 0
|
||||
{ iadst8_c, idct8_c }, // ADST_DCT = 1
|
||||
{ idct8_c, iadst8_c }, // DCT_ADST = 2
|
||||
{ iadst8_c, iadst8_c } // ADST_ADST = 3
|
||||
};
|
||||
|
||||
void vp9_iht8x8_64_add_c(const tran_low_t *input, uint8_t *dest, int stride,
|
||||
int tx_type) {
|
||||
int i, j;
|
||||
tran_low_t out[8 * 8];
|
||||
tran_low_t *outptr = out;
|
||||
tran_low_t temp_in[8], temp_out[8];
|
||||
const transform_2d ht = IHT_8[tx_type];
|
||||
|
||||
// inverse transform row vectors
|
||||
for (i = 0; i < 8; ++i) {
|
||||
ht.rows(input, outptr);
|
||||
input += 8;
|
||||
outptr += 8;
|
||||
}
|
||||
|
||||
// inverse transform column vectors
|
||||
for (i = 0; i < 8; ++i) {
|
||||
for (j = 0; j < 8; ++j) temp_in[j] = out[j * 8 + i];
|
||||
ht.cols(temp_in, temp_out);
|
||||
for (j = 0; j < 8; ++j) {
|
||||
dest[j * stride + i] = clip_pixel_add(dest[j * stride + i],
|
||||
ROUND_POWER_OF_TWO(temp_out[j], 5));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const transform_2d IHT_16[] = {
|
||||
{ idct16_c, idct16_c }, // DCT_DCT = 0
|
||||
{ iadst16_c, idct16_c }, // ADST_DCT = 1
|
||||
{ idct16_c, iadst16_c }, // DCT_ADST = 2
|
||||
{ iadst16_c, iadst16_c } // ADST_ADST = 3
|
||||
};
|
||||
|
||||
void vp9_iht16x16_256_add_c(const tran_low_t *input, uint8_t *dest, int stride,
|
||||
int tx_type) {
|
||||
int i, j;
|
||||
tran_low_t out[16 * 16];
|
||||
tran_low_t *outptr = out;
|
||||
tran_low_t temp_in[16], temp_out[16];
|
||||
const transform_2d ht = IHT_16[tx_type];
|
||||
|
||||
// Rows
|
||||
for (i = 0; i < 16; ++i) {
|
||||
ht.rows(input, outptr);
|
||||
input += 16;
|
||||
outptr += 16;
|
||||
}
|
||||
|
||||
// Columns
|
||||
for (i = 0; i < 16; ++i) {
|
||||
for (j = 0; j < 16; ++j) temp_in[j] = out[j * 16 + i];
|
||||
ht.cols(temp_in, temp_out);
|
||||
for (j = 0; j < 16; ++j) {
|
||||
dest[j * stride + i] = clip_pixel_add(dest[j * stride + i],
|
||||
ROUND_POWER_OF_TWO(temp_out[j], 6));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// idct
|
||||
void vp9_idct4x4_add(const tran_low_t *input, uint8_t *dest, int stride,
|
||||
int eob) {
|
||||
if (eob > 1)
|
||||
vpx_idct4x4_16_add(input, dest, stride);
|
||||
else
|
||||
vpx_idct4x4_1_add(input, dest, stride);
|
||||
}
|
||||
|
||||
void vp9_iwht4x4_add(const tran_low_t *input, uint8_t *dest, int stride,
|
||||
int eob) {
|
||||
if (eob > 1)
|
||||
vpx_iwht4x4_16_add(input, dest, stride);
|
||||
else
|
||||
vpx_iwht4x4_1_add(input, dest, stride);
|
||||
}
|
||||
|
||||
void vp9_idct8x8_add(const tran_low_t *input, uint8_t *dest, int stride,
|
||||
int eob) {
|
||||
// If dc is 1, then input[0] is the reconstructed value, do not need
|
||||
// dequantization. Also, when dc is 1, dc is counted in eobs, namely eobs >=1.
|
||||
|
||||
// The calculation can be simplified if there are not many non-zero dct
|
||||
// coefficients. Use eobs to decide what to do.
|
||||
if (eob == 1)
|
||||
// DC only DCT coefficient
|
||||
vpx_idct8x8_1_add(input, dest, stride);
|
||||
else if (eob <= 12)
|
||||
vpx_idct8x8_12_add(input, dest, stride);
|
||||
else
|
||||
vpx_idct8x8_64_add(input, dest, stride);
|
||||
}
|
||||
|
||||
void vp9_idct16x16_add(const tran_low_t *input, uint8_t *dest, int stride,
|
||||
int eob) {
|
||||
/* The calculation can be simplified if there are not many non-zero dct
|
||||
* coefficients. Use eobs to separate different cases. */
|
||||
if (eob == 1) /* DC only DCT coefficient. */
|
||||
vpx_idct16x16_1_add(input, dest, stride);
|
||||
else if (eob <= 10)
|
||||
vpx_idct16x16_10_add(input, dest, stride);
|
||||
else if (eob <= 38)
|
||||
vpx_idct16x16_38_add(input, dest, stride);
|
||||
else
|
||||
vpx_idct16x16_256_add(input, dest, stride);
|
||||
}
|
||||
|
||||
void vp9_idct32x32_add(const tran_low_t *input, uint8_t *dest, int stride,
|
||||
int eob) {
|
||||
if (eob == 1)
|
||||
vpx_idct32x32_1_add(input, dest, stride);
|
||||
else if (eob <= 34)
|
||||
// non-zero coeff only in upper-left 8x8
|
||||
vpx_idct32x32_34_add(input, dest, stride);
|
||||
else if (eob <= 135)
|
||||
// non-zero coeff only in upper-left 16x16
|
||||
vpx_idct32x32_135_add(input, dest, stride);
|
||||
else
|
||||
vpx_idct32x32_1024_add(input, dest, stride);
|
||||
}
|
||||
|
||||
// iht
|
||||
void vp9_iht4x4_add(TX_TYPE tx_type, const tran_low_t *input, uint8_t *dest,
|
||||
int stride, int eob) {
|
||||
if (tx_type == DCT_DCT)
|
||||
vp9_idct4x4_add(input, dest, stride, eob);
|
||||
else
|
||||
vp9_iht4x4_16_add(input, dest, stride, tx_type);
|
||||
}
|
||||
|
||||
void vp9_iht8x8_add(TX_TYPE tx_type, const tran_low_t *input, uint8_t *dest,
|
||||
int stride, int eob) {
|
||||
if (tx_type == DCT_DCT) {
|
||||
vp9_idct8x8_add(input, dest, stride, eob);
|
||||
} else {
|
||||
vp9_iht8x8_64_add(input, dest, stride, tx_type);
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_iht16x16_add(TX_TYPE tx_type, const tran_low_t *input, uint8_t *dest,
|
||||
int stride, int eob) {
|
||||
if (tx_type == DCT_DCT) {
|
||||
vp9_idct16x16_add(input, dest, stride, eob);
|
||||
} else {
|
||||
vp9_iht16x16_256_add(input, dest, stride, tx_type);
|
||||
}
|
||||
}
|
||||
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
|
||||
void vp9_highbd_iht4x4_16_add_c(const tran_low_t *input, uint16_t *dest,
|
||||
int stride, int tx_type, int bd) {
|
||||
const highbd_transform_2d IHT_4[] = {
|
||||
{ vpx_highbd_idct4_c, vpx_highbd_idct4_c }, // DCT_DCT = 0
|
||||
{ vpx_highbd_iadst4_c, vpx_highbd_idct4_c }, // ADST_DCT = 1
|
||||
{ vpx_highbd_idct4_c, vpx_highbd_iadst4_c }, // DCT_ADST = 2
|
||||
{ vpx_highbd_iadst4_c, vpx_highbd_iadst4_c } // ADST_ADST = 3
|
||||
};
|
||||
|
||||
int i, j;
|
||||
tran_low_t out[4 * 4];
|
||||
tran_low_t *outptr = out;
|
||||
tran_low_t temp_in[4], temp_out[4];
|
||||
|
||||
// Inverse transform row vectors.
|
||||
for (i = 0; i < 4; ++i) {
|
||||
IHT_4[tx_type].rows(input, outptr, bd);
|
||||
input += 4;
|
||||
outptr += 4;
|
||||
}
|
||||
|
||||
// Inverse transform column vectors.
|
||||
for (i = 0; i < 4; ++i) {
|
||||
for (j = 0; j < 4; ++j) temp_in[j] = out[j * 4 + i];
|
||||
IHT_4[tx_type].cols(temp_in, temp_out, bd);
|
||||
for (j = 0; j < 4; ++j) {
|
||||
dest[j * stride + i] = highbd_clip_pixel_add(
|
||||
dest[j * stride + i], ROUND_POWER_OF_TWO(temp_out[j], 4), bd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const highbd_transform_2d HIGH_IHT_8[] = {
|
||||
{ vpx_highbd_idct8_c, vpx_highbd_idct8_c }, // DCT_DCT = 0
|
||||
{ vpx_highbd_iadst8_c, vpx_highbd_idct8_c }, // ADST_DCT = 1
|
||||
{ vpx_highbd_idct8_c, vpx_highbd_iadst8_c }, // DCT_ADST = 2
|
||||
{ vpx_highbd_iadst8_c, vpx_highbd_iadst8_c } // ADST_ADST = 3
|
||||
};
|
||||
|
||||
void vp9_highbd_iht8x8_64_add_c(const tran_low_t *input, uint16_t *dest,
|
||||
int stride, int tx_type, int bd) {
|
||||
int i, j;
|
||||
tran_low_t out[8 * 8];
|
||||
tran_low_t *outptr = out;
|
||||
tran_low_t temp_in[8], temp_out[8];
|
||||
const highbd_transform_2d ht = HIGH_IHT_8[tx_type];
|
||||
|
||||
// Inverse transform row vectors.
|
||||
for (i = 0; i < 8; ++i) {
|
||||
ht.rows(input, outptr, bd);
|
||||
input += 8;
|
||||
outptr += 8;
|
||||
}
|
||||
|
||||
// Inverse transform column vectors.
|
||||
for (i = 0; i < 8; ++i) {
|
||||
for (j = 0; j < 8; ++j) temp_in[j] = out[j * 8 + i];
|
||||
ht.cols(temp_in, temp_out, bd);
|
||||
for (j = 0; j < 8; ++j) {
|
||||
dest[j * stride + i] = highbd_clip_pixel_add(
|
||||
dest[j * stride + i], ROUND_POWER_OF_TWO(temp_out[j], 5), bd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const highbd_transform_2d HIGH_IHT_16[] = {
|
||||
{ vpx_highbd_idct16_c, vpx_highbd_idct16_c }, // DCT_DCT = 0
|
||||
{ vpx_highbd_iadst16_c, vpx_highbd_idct16_c }, // ADST_DCT = 1
|
||||
{ vpx_highbd_idct16_c, vpx_highbd_iadst16_c }, // DCT_ADST = 2
|
||||
{ vpx_highbd_iadst16_c, vpx_highbd_iadst16_c } // ADST_ADST = 3
|
||||
};
|
||||
|
||||
void vp9_highbd_iht16x16_256_add_c(const tran_low_t *input, uint16_t *dest,
|
||||
int stride, int tx_type, int bd) {
|
||||
int i, j;
|
||||
tran_low_t out[16 * 16];
|
||||
tran_low_t *outptr = out;
|
||||
tran_low_t temp_in[16], temp_out[16];
|
||||
const highbd_transform_2d ht = HIGH_IHT_16[tx_type];
|
||||
|
||||
// Rows
|
||||
for (i = 0; i < 16; ++i) {
|
||||
ht.rows(input, outptr, bd);
|
||||
input += 16;
|
||||
outptr += 16;
|
||||
}
|
||||
|
||||
// Columns
|
||||
for (i = 0; i < 16; ++i) {
|
||||
for (j = 0; j < 16; ++j) temp_in[j] = out[j * 16 + i];
|
||||
ht.cols(temp_in, temp_out, bd);
|
||||
for (j = 0; j < 16; ++j) {
|
||||
dest[j * stride + i] = highbd_clip_pixel_add(
|
||||
dest[j * stride + i], ROUND_POWER_OF_TWO(temp_out[j], 6), bd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// idct
|
||||
void vp9_highbd_idct4x4_add(const tran_low_t *input, uint16_t *dest, int stride,
|
||||
int eob, int bd) {
|
||||
if (eob > 1)
|
||||
vpx_highbd_idct4x4_16_add(input, dest, stride, bd);
|
||||
else
|
||||
vpx_highbd_idct4x4_1_add(input, dest, stride, bd);
|
||||
}
|
||||
|
||||
void vp9_highbd_iwht4x4_add(const tran_low_t *input, uint16_t *dest, int stride,
|
||||
int eob, int bd) {
|
||||
if (eob > 1)
|
||||
vpx_highbd_iwht4x4_16_add(input, dest, stride, bd);
|
||||
else
|
||||
vpx_highbd_iwht4x4_1_add(input, dest, stride, bd);
|
||||
}
|
||||
|
||||
void vp9_highbd_idct8x8_add(const tran_low_t *input, uint16_t *dest, int stride,
|
||||
int eob, int bd) {
|
||||
// If dc is 1, then input[0] is the reconstructed value, do not need
|
||||
// dequantization. Also, when dc is 1, dc is counted in eobs, namely eobs >=1.
|
||||
|
||||
// The calculation can be simplified if there are not many non-zero dct
|
||||
// coefficients. Use eobs to decide what to do.
|
||||
// DC only DCT coefficient
|
||||
if (eob == 1) {
|
||||
vpx_highbd_idct8x8_1_add(input, dest, stride, bd);
|
||||
} else if (eob <= 12) {
|
||||
vpx_highbd_idct8x8_12_add(input, dest, stride, bd);
|
||||
} else {
|
||||
vpx_highbd_idct8x8_64_add(input, dest, stride, bd);
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_highbd_idct16x16_add(const tran_low_t *input, uint16_t *dest,
|
||||
int stride, int eob, int bd) {
|
||||
// The calculation can be simplified if there are not many non-zero dct
|
||||
// coefficients. Use eobs to separate different cases.
|
||||
// DC only DCT coefficient.
|
||||
if (eob == 1) {
|
||||
vpx_highbd_idct16x16_1_add(input, dest, stride, bd);
|
||||
} else if (eob <= 10) {
|
||||
vpx_highbd_idct16x16_10_add(input, dest, stride, bd);
|
||||
} else if (eob <= 38) {
|
||||
vpx_highbd_idct16x16_38_add(input, dest, stride, bd);
|
||||
} else {
|
||||
vpx_highbd_idct16x16_256_add(input, dest, stride, bd);
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_highbd_idct32x32_add(const tran_low_t *input, uint16_t *dest,
|
||||
int stride, int eob, int bd) {
|
||||
// Non-zero coeff only in upper-left 8x8
|
||||
if (eob == 1) {
|
||||
vpx_highbd_idct32x32_1_add(input, dest, stride, bd);
|
||||
} else if (eob <= 34) {
|
||||
vpx_highbd_idct32x32_34_add(input, dest, stride, bd);
|
||||
} else if (eob <= 135) {
|
||||
vpx_highbd_idct32x32_135_add(input, dest, stride, bd);
|
||||
} else {
|
||||
vpx_highbd_idct32x32_1024_add(input, dest, stride, bd);
|
||||
}
|
||||
}
|
||||
|
||||
// iht
|
||||
void vp9_highbd_iht4x4_add(TX_TYPE tx_type, const tran_low_t *input,
|
||||
uint16_t *dest, int stride, int eob, int bd) {
|
||||
if (tx_type == DCT_DCT)
|
||||
vp9_highbd_idct4x4_add(input, dest, stride, eob, bd);
|
||||
else
|
||||
vp9_highbd_iht4x4_16_add(input, dest, stride, tx_type, bd);
|
||||
}
|
||||
|
||||
void vp9_highbd_iht8x8_add(TX_TYPE tx_type, const tran_low_t *input,
|
||||
uint16_t *dest, int stride, int eob, int bd) {
|
||||
if (tx_type == DCT_DCT) {
|
||||
vp9_highbd_idct8x8_add(input, dest, stride, eob, bd);
|
||||
} else {
|
||||
vp9_highbd_iht8x8_64_add(input, dest, stride, tx_type, bd);
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_highbd_iht16x16_add(TX_TYPE tx_type, const tran_low_t *input,
|
||||
uint16_t *dest, int stride, int eob, int bd) {
|
||||
if (tx_type == DCT_DCT) {
|
||||
vp9_highbd_idct16x16_add(input, dest, stride, eob, bd);
|
||||
} else {
|
||||
vp9_highbd_iht16x16_256_add(input, dest, stride, tx_type, bd);
|
||||
}
|
||||
}
|
||||
#endif // CONFIG_VP9_HIGHBITDEPTH
|
||||
@@ -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 VPX_VP9_COMMON_VP9_IDCT_H_
|
||||
#define VPX_VP9_COMMON_VP9_IDCT_H_
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "./vpx_config.h"
|
||||
#include "vp9/common/vp9_common.h"
|
||||
#include "vp9/common/vp9_enums.h"
|
||||
#include "vpx_dsp/inv_txfm.h"
|
||||
#include "vpx_dsp/txfm_common.h"
|
||||
#include "vpx_ports/mem.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void (*transform_1d)(const tran_low_t *, tran_low_t *);
|
||||
|
||||
typedef struct {
|
||||
transform_1d cols, rows; // vertical and horizontal
|
||||
} transform_2d;
|
||||
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
typedef void (*highbd_transform_1d)(const tran_low_t *, tran_low_t *, int bd);
|
||||
|
||||
typedef struct {
|
||||
highbd_transform_1d cols, rows; // vertical and horizontal
|
||||
} highbd_transform_2d;
|
||||
#endif // CONFIG_VP9_HIGHBITDEPTH
|
||||
|
||||
void vp9_iwht4x4_add(const tran_low_t *input, uint8_t *dest, int stride,
|
||||
int eob);
|
||||
void vp9_idct4x4_add(const tran_low_t *input, uint8_t *dest, int stride,
|
||||
int eob);
|
||||
void vp9_idct8x8_add(const tran_low_t *input, uint8_t *dest, int stride,
|
||||
int eob);
|
||||
void vp9_idct16x16_add(const tran_low_t *input, uint8_t *dest, int stride,
|
||||
int eob);
|
||||
void vp9_idct32x32_add(const tran_low_t *input, uint8_t *dest, int stride,
|
||||
int eob);
|
||||
|
||||
void vp9_iht4x4_add(TX_TYPE tx_type, const tran_low_t *input, uint8_t *dest,
|
||||
int stride, int eob);
|
||||
void vp9_iht8x8_add(TX_TYPE tx_type, const tran_low_t *input, uint8_t *dest,
|
||||
int stride, int eob);
|
||||
void vp9_iht16x16_add(TX_TYPE tx_type, const tran_low_t *input, uint8_t *dest,
|
||||
int stride, int eob);
|
||||
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
void vp9_highbd_iwht4x4_add(const tran_low_t *input, uint16_t *dest, int stride,
|
||||
int eob, int bd);
|
||||
void vp9_highbd_idct4x4_add(const tran_low_t *input, uint16_t *dest, int stride,
|
||||
int eob, int bd);
|
||||
void vp9_highbd_idct8x8_add(const tran_low_t *input, uint16_t *dest, int stride,
|
||||
int eob, int bd);
|
||||
void vp9_highbd_idct16x16_add(const tran_low_t *input, uint16_t *dest,
|
||||
int stride, int eob, int bd);
|
||||
void vp9_highbd_idct32x32_add(const tran_low_t *input, uint16_t *dest,
|
||||
int stride, int eob, int bd);
|
||||
void vp9_highbd_iht4x4_add(TX_TYPE tx_type, const tran_low_t *input,
|
||||
uint16_t *dest, int stride, int eob, int bd);
|
||||
void vp9_highbd_iht8x8_add(TX_TYPE tx_type, const tran_low_t *input,
|
||||
uint16_t *dest, int stride, int eob, int bd);
|
||||
void vp9_highbd_iht16x16_add(TX_TYPE tx_type, const tran_low_t *input,
|
||||
uint16_t *dest, int stride, int eob, int bd);
|
||||
#endif // CONFIG_VP9_HIGHBITDEPTH
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_COMMON_VP9_IDCT_H_
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* 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 VPX_VP9_COMMON_VP9_LOOPFILTER_H_
|
||||
#define VPX_VP9_COMMON_VP9_LOOPFILTER_H_
|
||||
|
||||
#include "vpx_ports/mem.h"
|
||||
#include "./vpx_config.h"
|
||||
|
||||
#include "vp9/common/vp9_blockd.h"
|
||||
#include "vp9/common/vp9_seg_common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define MAX_LOOP_FILTER 63
|
||||
#define MAX_SHARPNESS 7
|
||||
|
||||
#define SIMD_WIDTH 16
|
||||
|
||||
#define MAX_REF_LF_DELTAS 4
|
||||
#define MAX_MODE_LF_DELTAS 2
|
||||
|
||||
enum lf_path {
|
||||
LF_PATH_420,
|
||||
LF_PATH_444,
|
||||
LF_PATH_SLOW,
|
||||
};
|
||||
|
||||
// Need to align this structure so when it is declared and
|
||||
// passed it can be loaded into vector registers.
|
||||
typedef struct {
|
||||
DECLARE_ALIGNED(SIMD_WIDTH, uint8_t, mblim[SIMD_WIDTH]);
|
||||
DECLARE_ALIGNED(SIMD_WIDTH, uint8_t, lim[SIMD_WIDTH]);
|
||||
DECLARE_ALIGNED(SIMD_WIDTH, uint8_t, hev_thr[SIMD_WIDTH]);
|
||||
} loop_filter_thresh;
|
||||
|
||||
typedef struct {
|
||||
loop_filter_thresh lfthr[MAX_LOOP_FILTER + 1];
|
||||
uint8_t lvl[MAX_SEGMENTS][MAX_REF_FRAMES][MAX_MODE_LF_DELTAS];
|
||||
} loop_filter_info_n;
|
||||
|
||||
// This structure holds bit masks for all 8x8 blocks in a 64x64 region.
|
||||
// Each 1 bit represents a position in which we want to apply the loop filter.
|
||||
// Left_ entries refer to whether we apply a filter on the border to the
|
||||
// left of the block. Above_ entries refer to whether or not to apply a
|
||||
// filter on the above border. Int_ entries refer to whether or not to
|
||||
// apply borders on the 4x4 edges within the 8x8 block that each bit
|
||||
// represents.
|
||||
// Since each transform is accompanied by a potentially different type of
|
||||
// loop filter there is a different entry in the array for each transform size.
|
||||
typedef struct {
|
||||
uint64_t left_y[TX_SIZES];
|
||||
uint64_t above_y[TX_SIZES];
|
||||
uint64_t int_4x4_y;
|
||||
uint16_t left_uv[TX_SIZES];
|
||||
uint16_t above_uv[TX_SIZES];
|
||||
uint16_t int_4x4_uv;
|
||||
uint8_t lfl_y[64];
|
||||
} LOOP_FILTER_MASK;
|
||||
|
||||
struct loopfilter {
|
||||
int filter_level;
|
||||
int last_filt_level;
|
||||
|
||||
int sharpness_level;
|
||||
int last_sharpness_level;
|
||||
|
||||
uint8_t mode_ref_delta_enabled;
|
||||
uint8_t mode_ref_delta_update;
|
||||
|
||||
// 0 = Intra, Last, GF, ARF
|
||||
signed char ref_deltas[MAX_REF_LF_DELTAS];
|
||||
signed char last_ref_deltas[MAX_REF_LF_DELTAS];
|
||||
|
||||
// 0 = ZERO_MV, MV
|
||||
signed char mode_deltas[MAX_MODE_LF_DELTAS];
|
||||
signed char last_mode_deltas[MAX_MODE_LF_DELTAS];
|
||||
|
||||
LOOP_FILTER_MASK *lfm;
|
||||
int lfm_stride;
|
||||
};
|
||||
|
||||
/* assorted loopfilter functions which get used elsewhere */
|
||||
struct VP9Common;
|
||||
struct macroblockd;
|
||||
struct VP9LfSyncData;
|
||||
|
||||
// This function sets up the bit masks for the entire 64x64 region represented
|
||||
// by mi_row, mi_col.
|
||||
void vp9_setup_mask(struct VP9Common *const cm, const int mi_row,
|
||||
const int mi_col, MODE_INFO **mi8x8,
|
||||
const int mode_info_stride, LOOP_FILTER_MASK *lfm);
|
||||
|
||||
void vp9_filter_block_plane_ss00(struct VP9Common *const cm,
|
||||
struct macroblockd_plane *const plane,
|
||||
int mi_row, LOOP_FILTER_MASK *lfm);
|
||||
|
||||
void vp9_filter_block_plane_ss11(struct VP9Common *const cm,
|
||||
struct macroblockd_plane *const plane,
|
||||
int mi_row, LOOP_FILTER_MASK *lfm);
|
||||
|
||||
void vp9_filter_block_plane_non420(struct VP9Common *cm,
|
||||
struct macroblockd_plane *plane,
|
||||
MODE_INFO **mi_8x8, int mi_row, int mi_col);
|
||||
|
||||
void vp9_loop_filter_init(struct VP9Common *cm);
|
||||
|
||||
// Update the loop filter for the current frame.
|
||||
// This should be called before vp9_loop_filter_frame(), vp9_build_mask_frame()
|
||||
// calls this function directly.
|
||||
void vp9_loop_filter_frame_init(struct VP9Common *cm, int default_filt_lvl);
|
||||
|
||||
void vp9_loop_filter_frame(YV12_BUFFER_CONFIG *frame, struct VP9Common *cm,
|
||||
struct macroblockd *xd, int frame_filter_level,
|
||||
int y_only, int partial_frame);
|
||||
|
||||
// Get the superblock lfm for a given mi_row, mi_col.
|
||||
static INLINE LOOP_FILTER_MASK *get_lfm(const struct loopfilter *lf,
|
||||
const int mi_row, const int mi_col) {
|
||||
return &lf->lfm[(mi_col >> 3) + ((mi_row >> 3) * lf->lfm_stride)];
|
||||
}
|
||||
|
||||
void vp9_build_mask(struct VP9Common *cm, const MODE_INFO *mi, int mi_row,
|
||||
int mi_col, int bw, int bh);
|
||||
void vp9_adjust_mask(struct VP9Common *const cm, const int mi_row,
|
||||
const int mi_col, LOOP_FILTER_MASK *lfm);
|
||||
void vp9_build_mask_frame(struct VP9Common *cm, int frame_filter_level,
|
||||
int partial_frame);
|
||||
void vp9_reset_lfm(struct VP9Common *const cm);
|
||||
|
||||
typedef struct LoopFilterWorkerData {
|
||||
YV12_BUFFER_CONFIG *frame_buffer;
|
||||
struct VP9Common *cm;
|
||||
struct macroblockd_plane planes[MAX_MB_PLANE];
|
||||
|
||||
int start;
|
||||
int stop;
|
||||
int y_only;
|
||||
} LFWorkerData;
|
||||
|
||||
void vp9_loop_filter_data_reset(
|
||||
LFWorkerData *lf_data, YV12_BUFFER_CONFIG *frame_buffer,
|
||||
struct VP9Common *cm, const struct macroblockd_plane planes[MAX_MB_PLANE]);
|
||||
|
||||
// Operates on the rows described by 'arg1' (cast to LFWorkerData *).
|
||||
int vp9_loop_filter_worker(void *arg1, void *unused);
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_COMMON_VP9_LOOPFILTER_H_
|
||||
@@ -0,0 +1,383 @@
|
||||
/*
|
||||
* 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 "./vpx_dsp_rtcd.h"
|
||||
#include "./vpx_scale_rtcd.h"
|
||||
|
||||
#include "vp9/common/vp9_onyxc_int.h"
|
||||
#include "vp9/common/vp9_postproc.h"
|
||||
|
||||
// TODO(jackychen): Replace this function with SSE2 code. There is
|
||||
// one SSE2 implementation in vp8, so will consider how to share it
|
||||
// between vp8 and vp9.
|
||||
static void filter_by_weight(const uint8_t *src, int src_stride, uint8_t *dst,
|
||||
int dst_stride, int block_size, int src_weight) {
|
||||
const int dst_weight = (1 << MFQE_PRECISION) - src_weight;
|
||||
const int rounding_bit = 1 << (MFQE_PRECISION - 1);
|
||||
int r, c;
|
||||
|
||||
for (r = 0; r < block_size; r++) {
|
||||
for (c = 0; c < block_size; c++) {
|
||||
dst[c] = (src[c] * src_weight + dst[c] * dst_weight + rounding_bit) >>
|
||||
MFQE_PRECISION;
|
||||
}
|
||||
src += src_stride;
|
||||
dst += dst_stride;
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_filter_by_weight8x8_c(const uint8_t *src, int src_stride, uint8_t *dst,
|
||||
int dst_stride, int src_weight) {
|
||||
filter_by_weight(src, src_stride, dst, dst_stride, 8, src_weight);
|
||||
}
|
||||
|
||||
void vp9_filter_by_weight16x16_c(const uint8_t *src, int src_stride,
|
||||
uint8_t *dst, int dst_stride, int src_weight) {
|
||||
filter_by_weight(src, src_stride, dst, dst_stride, 16, src_weight);
|
||||
}
|
||||
|
||||
static void filter_by_weight32x32(const uint8_t *src, int src_stride,
|
||||
uint8_t *dst, int dst_stride, int weight) {
|
||||
vp9_filter_by_weight16x16(src, src_stride, dst, dst_stride, weight);
|
||||
vp9_filter_by_weight16x16(src + 16, src_stride, dst + 16, dst_stride, weight);
|
||||
vp9_filter_by_weight16x16(src + src_stride * 16, src_stride,
|
||||
dst + dst_stride * 16, dst_stride, weight);
|
||||
vp9_filter_by_weight16x16(src + src_stride * 16 + 16, src_stride,
|
||||
dst + dst_stride * 16 + 16, dst_stride, weight);
|
||||
}
|
||||
|
||||
static void filter_by_weight64x64(const uint8_t *src, int src_stride,
|
||||
uint8_t *dst, int dst_stride, int weight) {
|
||||
filter_by_weight32x32(src, src_stride, dst, dst_stride, weight);
|
||||
filter_by_weight32x32(src + 32, src_stride, dst + 32, dst_stride, weight);
|
||||
filter_by_weight32x32(src + src_stride * 32, src_stride,
|
||||
dst + dst_stride * 32, dst_stride, weight);
|
||||
filter_by_weight32x32(src + src_stride * 32 + 32, src_stride,
|
||||
dst + dst_stride * 32 + 32, dst_stride, weight);
|
||||
}
|
||||
|
||||
static void apply_ifactor(const uint8_t *y, int y_stride, uint8_t *yd,
|
||||
int yd_stride, const uint8_t *u, const uint8_t *v,
|
||||
int uv_stride, uint8_t *ud, uint8_t *vd,
|
||||
int uvd_stride, BLOCK_SIZE block_size, int weight) {
|
||||
if (block_size == BLOCK_16X16) {
|
||||
vp9_filter_by_weight16x16(y, y_stride, yd, yd_stride, weight);
|
||||
vp9_filter_by_weight8x8(u, uv_stride, ud, uvd_stride, weight);
|
||||
vp9_filter_by_weight8x8(v, uv_stride, vd, uvd_stride, weight);
|
||||
} else if (block_size == BLOCK_32X32) {
|
||||
filter_by_weight32x32(y, y_stride, yd, yd_stride, weight);
|
||||
vp9_filter_by_weight16x16(u, uv_stride, ud, uvd_stride, weight);
|
||||
vp9_filter_by_weight16x16(v, uv_stride, vd, uvd_stride, weight);
|
||||
} else if (block_size == BLOCK_64X64) {
|
||||
filter_by_weight64x64(y, y_stride, yd, yd_stride, weight);
|
||||
filter_by_weight32x32(u, uv_stride, ud, uvd_stride, weight);
|
||||
filter_by_weight32x32(v, uv_stride, vd, uvd_stride, weight);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(jackychen): Determine whether replace it with assembly code.
|
||||
static void copy_mem8x8(const uint8_t *src, int src_stride, uint8_t *dst,
|
||||
int dst_stride) {
|
||||
int r;
|
||||
for (r = 0; r < 8; r++) {
|
||||
memcpy(dst, src, 8);
|
||||
src += src_stride;
|
||||
dst += dst_stride;
|
||||
}
|
||||
}
|
||||
|
||||
static void copy_mem16x16(const uint8_t *src, int src_stride, uint8_t *dst,
|
||||
int dst_stride) {
|
||||
int r;
|
||||
for (r = 0; r < 16; r++) {
|
||||
memcpy(dst, src, 16);
|
||||
src += src_stride;
|
||||
dst += dst_stride;
|
||||
}
|
||||
}
|
||||
|
||||
static void copy_mem32x32(const uint8_t *src, int src_stride, uint8_t *dst,
|
||||
int dst_stride) {
|
||||
copy_mem16x16(src, src_stride, dst, dst_stride);
|
||||
copy_mem16x16(src + 16, src_stride, dst + 16, dst_stride);
|
||||
copy_mem16x16(src + src_stride * 16, src_stride, dst + dst_stride * 16,
|
||||
dst_stride);
|
||||
copy_mem16x16(src + src_stride * 16 + 16, src_stride,
|
||||
dst + dst_stride * 16 + 16, dst_stride);
|
||||
}
|
||||
|
||||
static void copy_mem64x64(const uint8_t *src, int src_stride, uint8_t *dst,
|
||||
int dst_stride) {
|
||||
copy_mem32x32(src, src_stride, dst, dst_stride);
|
||||
copy_mem32x32(src + 32, src_stride, dst + 32, dst_stride);
|
||||
copy_mem32x32(src + src_stride * 32, src_stride, dst + src_stride * 32,
|
||||
dst_stride);
|
||||
copy_mem32x32(src + src_stride * 32 + 32, src_stride,
|
||||
dst + src_stride * 32 + 32, dst_stride);
|
||||
}
|
||||
|
||||
static void copy_block(const uint8_t *y, const uint8_t *u, const uint8_t *v,
|
||||
int y_stride, int uv_stride, uint8_t *yd, uint8_t *ud,
|
||||
uint8_t *vd, int yd_stride, int uvd_stride,
|
||||
BLOCK_SIZE bs) {
|
||||
if (bs == BLOCK_16X16) {
|
||||
copy_mem16x16(y, y_stride, yd, yd_stride);
|
||||
copy_mem8x8(u, uv_stride, ud, uvd_stride);
|
||||
copy_mem8x8(v, uv_stride, vd, uvd_stride);
|
||||
} else if (bs == BLOCK_32X32) {
|
||||
copy_mem32x32(y, y_stride, yd, yd_stride);
|
||||
copy_mem16x16(u, uv_stride, ud, uvd_stride);
|
||||
copy_mem16x16(v, uv_stride, vd, uvd_stride);
|
||||
} else {
|
||||
copy_mem64x64(y, y_stride, yd, yd_stride);
|
||||
copy_mem32x32(u, uv_stride, ud, uvd_stride);
|
||||
copy_mem32x32(v, uv_stride, vd, uvd_stride);
|
||||
}
|
||||
}
|
||||
|
||||
static void get_thr(BLOCK_SIZE bs, int qdiff, int *sad_thr, int *vdiff_thr) {
|
||||
const int adj = qdiff >> MFQE_PRECISION;
|
||||
if (bs == BLOCK_16X16) {
|
||||
*sad_thr = 7 + adj;
|
||||
} else if (bs == BLOCK_32X32) {
|
||||
*sad_thr = 6 + adj;
|
||||
} else { // BLOCK_64X64
|
||||
*sad_thr = 5 + adj;
|
||||
}
|
||||
*vdiff_thr = 125 + qdiff;
|
||||
}
|
||||
|
||||
static void mfqe_block(BLOCK_SIZE bs, const uint8_t *y, const uint8_t *u,
|
||||
const uint8_t *v, int y_stride, int uv_stride,
|
||||
uint8_t *yd, uint8_t *ud, uint8_t *vd, int yd_stride,
|
||||
int uvd_stride, int qdiff) {
|
||||
int sad, sad_thr, vdiff, vdiff_thr;
|
||||
uint32_t sse;
|
||||
|
||||
get_thr(bs, qdiff, &sad_thr, &vdiff_thr);
|
||||
|
||||
if (bs == BLOCK_16X16) {
|
||||
vdiff = (vpx_variance16x16(y, y_stride, yd, yd_stride, &sse) + 128) >> 8;
|
||||
sad = (vpx_sad16x16(y, y_stride, yd, yd_stride) + 128) >> 8;
|
||||
} else if (bs == BLOCK_32X32) {
|
||||
vdiff = (vpx_variance32x32(y, y_stride, yd, yd_stride, &sse) + 512) >> 10;
|
||||
sad = (vpx_sad32x32(y, y_stride, yd, yd_stride) + 512) >> 10;
|
||||
} else /* if (bs == BLOCK_64X64) */ {
|
||||
vdiff = (vpx_variance64x64(y, y_stride, yd, yd_stride, &sse) + 2048) >> 12;
|
||||
sad = (vpx_sad64x64(y, y_stride, yd, yd_stride) + 2048) >> 12;
|
||||
}
|
||||
|
||||
// vdiff > sad * 3 means vdiff should not be too small, otherwise,
|
||||
// it might be a lighting change in smooth area. When there is a
|
||||
// lighting change in smooth area, it is dangerous to do MFQE.
|
||||
if (sad > 1 && vdiff > sad * 3) {
|
||||
const int weight = 1 << MFQE_PRECISION;
|
||||
int ifactor = weight * sad * vdiff / (sad_thr * vdiff_thr);
|
||||
// When ifactor equals weight, no MFQE is done.
|
||||
if (ifactor > weight) {
|
||||
ifactor = weight;
|
||||
}
|
||||
apply_ifactor(y, y_stride, yd, yd_stride, u, v, uv_stride, ud, vd,
|
||||
uvd_stride, bs, ifactor);
|
||||
} else {
|
||||
// Copy the block from current frame (i.e., no mfqe is done).
|
||||
copy_block(y, u, v, y_stride, uv_stride, yd, ud, vd, yd_stride, uvd_stride,
|
||||
bs);
|
||||
}
|
||||
}
|
||||
|
||||
static int mfqe_decision(MODE_INFO *mi, BLOCK_SIZE cur_bs) {
|
||||
// Check the motion in current block(for inter frame),
|
||||
// or check the motion in the correlated block in last frame (for keyframe).
|
||||
const int mv_len_square = mi->mv[0].as_mv.row * mi->mv[0].as_mv.row +
|
||||
mi->mv[0].as_mv.col * mi->mv[0].as_mv.col;
|
||||
const int mv_threshold = 100;
|
||||
return mi->mode >= NEARESTMV && // Not an intra block
|
||||
cur_bs >= BLOCK_16X16 && mv_len_square <= mv_threshold;
|
||||
}
|
||||
|
||||
// Process each partiton in a super block, recursively.
|
||||
static void mfqe_partition(VP9_COMMON *cm, MODE_INFO *mi, BLOCK_SIZE bs,
|
||||
const uint8_t *y, const uint8_t *u, const uint8_t *v,
|
||||
int y_stride, int uv_stride, uint8_t *yd,
|
||||
uint8_t *ud, uint8_t *vd, int yd_stride,
|
||||
int uvd_stride) {
|
||||
int mi_offset, y_offset, uv_offset;
|
||||
const BLOCK_SIZE cur_bs = mi->sb_type;
|
||||
const int qdiff = cm->base_qindex - cm->postproc_state.last_base_qindex;
|
||||
const int bsl = b_width_log2_lookup[bs];
|
||||
PARTITION_TYPE partition = partition_lookup[bsl][cur_bs];
|
||||
const BLOCK_SIZE subsize = get_subsize(bs, partition);
|
||||
|
||||
if (cur_bs < BLOCK_8X8) {
|
||||
// If there are blocks smaller than 8x8, it must be on the boundary.
|
||||
return;
|
||||
}
|
||||
// No MFQE on blocks smaller than 16x16
|
||||
if (bs == BLOCK_16X16) {
|
||||
partition = PARTITION_NONE;
|
||||
}
|
||||
if (bs == BLOCK_64X64) {
|
||||
mi_offset = 4;
|
||||
y_offset = 32;
|
||||
uv_offset = 16;
|
||||
} else {
|
||||
mi_offset = 2;
|
||||
y_offset = 16;
|
||||
uv_offset = 8;
|
||||
}
|
||||
switch (partition) {
|
||||
BLOCK_SIZE mfqe_bs, bs_tmp;
|
||||
case PARTITION_HORZ:
|
||||
if (bs == BLOCK_64X64) {
|
||||
mfqe_bs = BLOCK_64X32;
|
||||
bs_tmp = BLOCK_32X32;
|
||||
} else {
|
||||
mfqe_bs = BLOCK_32X16;
|
||||
bs_tmp = BLOCK_16X16;
|
||||
}
|
||||
if (mfqe_decision(mi, mfqe_bs)) {
|
||||
// Do mfqe on the first square partition.
|
||||
mfqe_block(bs_tmp, y, u, v, y_stride, uv_stride, yd, ud, vd, yd_stride,
|
||||
uvd_stride, qdiff);
|
||||
// Do mfqe on the second square partition.
|
||||
mfqe_block(bs_tmp, y + y_offset, u + uv_offset, v + uv_offset, y_stride,
|
||||
uv_stride, yd + y_offset, ud + uv_offset, vd + uv_offset,
|
||||
yd_stride, uvd_stride, qdiff);
|
||||
}
|
||||
if (mfqe_decision(mi + mi_offset * cm->mi_stride, mfqe_bs)) {
|
||||
// Do mfqe on the first square partition.
|
||||
mfqe_block(bs_tmp, y + y_offset * y_stride, u + uv_offset * uv_stride,
|
||||
v + uv_offset * uv_stride, y_stride, uv_stride,
|
||||
yd + y_offset * yd_stride, ud + uv_offset * uvd_stride,
|
||||
vd + uv_offset * uvd_stride, yd_stride, uvd_stride, qdiff);
|
||||
// Do mfqe on the second square partition.
|
||||
mfqe_block(bs_tmp, y + y_offset * y_stride + y_offset,
|
||||
u + uv_offset * uv_stride + uv_offset,
|
||||
v + uv_offset * uv_stride + uv_offset, y_stride, uv_stride,
|
||||
yd + y_offset * yd_stride + y_offset,
|
||||
ud + uv_offset * uvd_stride + uv_offset,
|
||||
vd + uv_offset * uvd_stride + uv_offset, yd_stride,
|
||||
uvd_stride, qdiff);
|
||||
}
|
||||
break;
|
||||
case PARTITION_VERT:
|
||||
if (bs == BLOCK_64X64) {
|
||||
mfqe_bs = BLOCK_32X64;
|
||||
bs_tmp = BLOCK_32X32;
|
||||
} else {
|
||||
mfqe_bs = BLOCK_16X32;
|
||||
bs_tmp = BLOCK_16X16;
|
||||
}
|
||||
if (mfqe_decision(mi, mfqe_bs)) {
|
||||
// Do mfqe on the first square partition.
|
||||
mfqe_block(bs_tmp, y, u, v, y_stride, uv_stride, yd, ud, vd, yd_stride,
|
||||
uvd_stride, qdiff);
|
||||
// Do mfqe on the second square partition.
|
||||
mfqe_block(bs_tmp, y + y_offset * y_stride, u + uv_offset * uv_stride,
|
||||
v + uv_offset * uv_stride, y_stride, uv_stride,
|
||||
yd + y_offset * yd_stride, ud + uv_offset * uvd_stride,
|
||||
vd + uv_offset * uvd_stride, yd_stride, uvd_stride, qdiff);
|
||||
}
|
||||
if (mfqe_decision(mi + mi_offset, mfqe_bs)) {
|
||||
// Do mfqe on the first square partition.
|
||||
mfqe_block(bs_tmp, y + y_offset, u + uv_offset, v + uv_offset, y_stride,
|
||||
uv_stride, yd + y_offset, ud + uv_offset, vd + uv_offset,
|
||||
yd_stride, uvd_stride, qdiff);
|
||||
// Do mfqe on the second square partition.
|
||||
mfqe_block(bs_tmp, y + y_offset * y_stride + y_offset,
|
||||
u + uv_offset * uv_stride + uv_offset,
|
||||
v + uv_offset * uv_stride + uv_offset, y_stride, uv_stride,
|
||||
yd + y_offset * yd_stride + y_offset,
|
||||
ud + uv_offset * uvd_stride + uv_offset,
|
||||
vd + uv_offset * uvd_stride + uv_offset, yd_stride,
|
||||
uvd_stride, qdiff);
|
||||
}
|
||||
break;
|
||||
case PARTITION_NONE:
|
||||
if (mfqe_decision(mi, cur_bs)) {
|
||||
// Do mfqe on this partition.
|
||||
mfqe_block(cur_bs, y, u, v, y_stride, uv_stride, yd, ud, vd, yd_stride,
|
||||
uvd_stride, qdiff);
|
||||
} else {
|
||||
// Copy the block from current frame(i.e., no mfqe is done).
|
||||
copy_block(y, u, v, y_stride, uv_stride, yd, ud, vd, yd_stride,
|
||||
uvd_stride, bs);
|
||||
}
|
||||
break;
|
||||
case PARTITION_SPLIT:
|
||||
// Recursion on four square partitions, e.g. if bs is 64X64,
|
||||
// then look into four 32X32 blocks in it.
|
||||
mfqe_partition(cm, mi, subsize, y, u, v, y_stride, uv_stride, yd, ud, vd,
|
||||
yd_stride, uvd_stride);
|
||||
mfqe_partition(cm, mi + mi_offset, subsize, y + y_offset, u + uv_offset,
|
||||
v + uv_offset, y_stride, uv_stride, yd + y_offset,
|
||||
ud + uv_offset, vd + uv_offset, yd_stride, uvd_stride);
|
||||
mfqe_partition(cm, mi + mi_offset * cm->mi_stride, subsize,
|
||||
y + y_offset * y_stride, u + uv_offset * uv_stride,
|
||||
v + uv_offset * uv_stride, y_stride, uv_stride,
|
||||
yd + y_offset * yd_stride, ud + uv_offset * uvd_stride,
|
||||
vd + uv_offset * uvd_stride, yd_stride, uvd_stride);
|
||||
mfqe_partition(cm, mi + mi_offset * cm->mi_stride + mi_offset, subsize,
|
||||
y + y_offset * y_stride + y_offset,
|
||||
u + uv_offset * uv_stride + uv_offset,
|
||||
v + uv_offset * uv_stride + uv_offset, y_stride, uv_stride,
|
||||
yd + y_offset * yd_stride + y_offset,
|
||||
ud + uv_offset * uvd_stride + uv_offset,
|
||||
vd + uv_offset * uvd_stride + uv_offset, yd_stride,
|
||||
uvd_stride);
|
||||
break;
|
||||
default: assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_mfqe(VP9_COMMON *cm) {
|
||||
int mi_row, mi_col;
|
||||
// Current decoded frame.
|
||||
const YV12_BUFFER_CONFIG *show = cm->frame_to_show;
|
||||
// Last decoded frame and will store the MFQE result.
|
||||
YV12_BUFFER_CONFIG *dest = &cm->post_proc_buffer;
|
||||
// Loop through each super block.
|
||||
for (mi_row = 0; mi_row < cm->mi_rows; mi_row += MI_BLOCK_SIZE) {
|
||||
for (mi_col = 0; mi_col < cm->mi_cols; mi_col += MI_BLOCK_SIZE) {
|
||||
MODE_INFO *mi;
|
||||
MODE_INFO *mi_local = cm->mi + (mi_row * cm->mi_stride + mi_col);
|
||||
// Motion Info in last frame.
|
||||
MODE_INFO *mi_prev =
|
||||
cm->postproc_state.prev_mi + (mi_row * cm->mi_stride + mi_col);
|
||||
const uint32_t y_stride = show->y_stride;
|
||||
const uint32_t uv_stride = show->uv_stride;
|
||||
const uint32_t yd_stride = dest->y_stride;
|
||||
const uint32_t uvd_stride = dest->uv_stride;
|
||||
const uint32_t row_offset_y = mi_row << 3;
|
||||
const uint32_t row_offset_uv = mi_row << 2;
|
||||
const uint32_t col_offset_y = mi_col << 3;
|
||||
const uint32_t col_offset_uv = mi_col << 2;
|
||||
const uint8_t *y =
|
||||
show->y_buffer + row_offset_y * y_stride + col_offset_y;
|
||||
const uint8_t *u =
|
||||
show->u_buffer + row_offset_uv * uv_stride + col_offset_uv;
|
||||
const uint8_t *v =
|
||||
show->v_buffer + row_offset_uv * uv_stride + col_offset_uv;
|
||||
uint8_t *yd = dest->y_buffer + row_offset_y * yd_stride + col_offset_y;
|
||||
uint8_t *ud = dest->u_buffer + row_offset_uv * uvd_stride + col_offset_uv;
|
||||
uint8_t *vd = dest->v_buffer + row_offset_uv * uvd_stride + col_offset_uv;
|
||||
if (frame_is_intra_only(cm)) {
|
||||
mi = mi_prev;
|
||||
} else {
|
||||
mi = mi_local;
|
||||
}
|
||||
mfqe_partition(cm, mi, BLOCK_64X64, y, u, v, y_stride, uv_stride, yd, ud,
|
||||
vd, yd_stride, uvd_stride);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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 VPX_VP9_COMMON_VP9_MFQE_H_
|
||||
#define VPX_VP9_COMMON_VP9_MFQE_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Multiframe Quality Enhancement.
|
||||
// The aim for MFQE is to replace pixel blocks in the current frame with
|
||||
// the correlated pixel blocks (with higher quality) in the last frame.
|
||||
// The replacement can only be taken in stationary blocks by checking
|
||||
// the motion of the blocks and other conditions such as the SAD of
|
||||
// the current block and correlated block, the variance of the block
|
||||
// difference, etc.
|
||||
void vp9_mfqe(struct VP9Common *cm);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_COMMON_VP9_MFQE_H_
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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 VPX_VP9_COMMON_VP9_MV_H_
|
||||
#define VPX_VP9_COMMON_VP9_MV_H_
|
||||
|
||||
#include "vpx/vpx_integer.h"
|
||||
|
||||
#include "vp9/common/vp9_common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define INVALID_MV 0x80008000
|
||||
|
||||
typedef struct mv {
|
||||
int16_t row;
|
||||
int16_t col;
|
||||
} MV;
|
||||
|
||||
typedef union int_mv {
|
||||
uint32_t as_int;
|
||||
MV as_mv;
|
||||
} int_mv; /* facilitates faster equality tests and copies */
|
||||
|
||||
typedef struct mv32 {
|
||||
int32_t row;
|
||||
int32_t col;
|
||||
} MV32;
|
||||
|
||||
static INLINE int is_zero_mv(const MV *mv) {
|
||||
return *((const uint32_t *)mv) == 0;
|
||||
}
|
||||
|
||||
static INLINE int is_equal_mv(const MV *a, const MV *b) {
|
||||
return *((const uint32_t *)a) == *((const uint32_t *)b);
|
||||
}
|
||||
|
||||
static INLINE void clamp_mv(MV *mv, int min_col, int max_col, int min_row,
|
||||
int max_row) {
|
||||
mv->col = clamp(mv->col, min_col, max_col);
|
||||
mv->row = clamp(mv->row, min_row, max_row);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_COMMON_VP9_MV_H_
|
||||
@@ -0,0 +1,199 @@
|
||||
|
||||
/*
|
||||
* 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 "vp9/common/vp9_mvref_common.h"
|
||||
|
||||
// This function searches the neighborhood of a given MB/SB
|
||||
// to try and find candidate reference vectors.
|
||||
static void find_mv_refs_idx(const VP9_COMMON *cm, const MACROBLOCKD *xd,
|
||||
MODE_INFO *mi, MV_REFERENCE_FRAME ref_frame,
|
||||
int_mv *mv_ref_list, int block, int mi_row,
|
||||
int mi_col, uint8_t *mode_context) {
|
||||
const int *ref_sign_bias = cm->ref_frame_sign_bias;
|
||||
int i, refmv_count = 0;
|
||||
const POSITION *const mv_ref_search = mv_ref_blocks[mi->sb_type];
|
||||
int different_ref_found = 0;
|
||||
int context_counter = 0;
|
||||
const MV_REF *const prev_frame_mvs =
|
||||
cm->use_prev_frame_mvs
|
||||
? cm->prev_frame->mvs + mi_row * cm->mi_cols + mi_col
|
||||
: NULL;
|
||||
const TileInfo *const tile = &xd->tile;
|
||||
|
||||
// Blank the reference vector list
|
||||
memset(mv_ref_list, 0, sizeof(*mv_ref_list) * MAX_MV_REF_CANDIDATES);
|
||||
|
||||
// The nearest 2 blocks are treated differently
|
||||
// if the size < 8x8 we get the mv from the bmi substructure,
|
||||
// and we also need to keep a mode count.
|
||||
for (i = 0; i < 2; ++i) {
|
||||
const POSITION *const mv_ref = &mv_ref_search[i];
|
||||
if (is_inside(tile, mi_col, mi_row, cm->mi_rows, mv_ref)) {
|
||||
const MODE_INFO *const candidate_mi =
|
||||
xd->mi[mv_ref->col + mv_ref->row * xd->mi_stride];
|
||||
// Keep counts for entropy encoding.
|
||||
context_counter += mode_2_counter[candidate_mi->mode];
|
||||
different_ref_found = 1;
|
||||
|
||||
if (candidate_mi->ref_frame[0] == ref_frame)
|
||||
ADD_MV_REF_LIST(get_sub_block_mv(candidate_mi, 0, mv_ref->col, block),
|
||||
refmv_count, mv_ref_list, Done);
|
||||
else if (candidate_mi->ref_frame[1] == ref_frame)
|
||||
ADD_MV_REF_LIST(get_sub_block_mv(candidate_mi, 1, mv_ref->col, block),
|
||||
refmv_count, mv_ref_list, Done);
|
||||
}
|
||||
}
|
||||
|
||||
// Check the rest of the neighbors in much the same way
|
||||
// as before except we don't need to keep track of sub blocks or
|
||||
// mode counts.
|
||||
for (; i < MVREF_NEIGHBOURS; ++i) {
|
||||
const POSITION *const mv_ref = &mv_ref_search[i];
|
||||
if (is_inside(tile, mi_col, mi_row, cm->mi_rows, mv_ref)) {
|
||||
const MODE_INFO *const candidate_mi =
|
||||
xd->mi[mv_ref->col + mv_ref->row * xd->mi_stride];
|
||||
different_ref_found = 1;
|
||||
|
||||
if (candidate_mi->ref_frame[0] == ref_frame)
|
||||
ADD_MV_REF_LIST(candidate_mi->mv[0], refmv_count, mv_ref_list, Done);
|
||||
else if (candidate_mi->ref_frame[1] == ref_frame)
|
||||
ADD_MV_REF_LIST(candidate_mi->mv[1], refmv_count, mv_ref_list, Done);
|
||||
}
|
||||
}
|
||||
|
||||
// Check the last frame's mode and mv info.
|
||||
if (cm->use_prev_frame_mvs) {
|
||||
if (prev_frame_mvs->ref_frame[0] == ref_frame) {
|
||||
ADD_MV_REF_LIST(prev_frame_mvs->mv[0], refmv_count, mv_ref_list, Done);
|
||||
} else if (prev_frame_mvs->ref_frame[1] == ref_frame) {
|
||||
ADD_MV_REF_LIST(prev_frame_mvs->mv[1], refmv_count, mv_ref_list, Done);
|
||||
}
|
||||
}
|
||||
|
||||
// Since we couldn't find 2 mvs from the same reference frame
|
||||
// go back through the neighbors and find motion vectors from
|
||||
// different reference frames.
|
||||
if (different_ref_found) {
|
||||
for (i = 0; i < MVREF_NEIGHBOURS; ++i) {
|
||||
const POSITION *mv_ref = &mv_ref_search[i];
|
||||
if (is_inside(tile, mi_col, mi_row, cm->mi_rows, mv_ref)) {
|
||||
const MODE_INFO *const candidate_mi =
|
||||
xd->mi[mv_ref->col + mv_ref->row * xd->mi_stride];
|
||||
|
||||
// If the candidate is INTRA we don't want to consider its mv.
|
||||
IF_DIFF_REF_FRAME_ADD_MV(candidate_mi, ref_frame, ref_sign_bias,
|
||||
refmv_count, mv_ref_list, Done);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Since we still don't have a candidate we'll try the last frame.
|
||||
if (cm->use_prev_frame_mvs) {
|
||||
if (prev_frame_mvs->ref_frame[0] != ref_frame &&
|
||||
prev_frame_mvs->ref_frame[0] > INTRA_FRAME) {
|
||||
int_mv mv = prev_frame_mvs->mv[0];
|
||||
if (ref_sign_bias[prev_frame_mvs->ref_frame[0]] !=
|
||||
ref_sign_bias[ref_frame]) {
|
||||
mv.as_mv.row *= -1;
|
||||
mv.as_mv.col *= -1;
|
||||
}
|
||||
ADD_MV_REF_LIST(mv, refmv_count, mv_ref_list, Done);
|
||||
}
|
||||
|
||||
if (prev_frame_mvs->ref_frame[1] > INTRA_FRAME &&
|
||||
prev_frame_mvs->ref_frame[1] != ref_frame &&
|
||||
prev_frame_mvs->mv[1].as_int != prev_frame_mvs->mv[0].as_int) {
|
||||
int_mv mv = prev_frame_mvs->mv[1];
|
||||
if (ref_sign_bias[prev_frame_mvs->ref_frame[1]] !=
|
||||
ref_sign_bias[ref_frame]) {
|
||||
mv.as_mv.row *= -1;
|
||||
mv.as_mv.col *= -1;
|
||||
}
|
||||
ADD_MV_REF_LIST(mv, refmv_count, mv_ref_list, Done);
|
||||
}
|
||||
}
|
||||
|
||||
Done:
|
||||
|
||||
mode_context[ref_frame] = counter_to_context[context_counter];
|
||||
|
||||
// Clamp vectors
|
||||
for (i = 0; i < MAX_MV_REF_CANDIDATES; ++i)
|
||||
clamp_mv_ref(&mv_ref_list[i].as_mv, xd);
|
||||
}
|
||||
|
||||
void vp9_find_mv_refs(const VP9_COMMON *cm, const MACROBLOCKD *xd,
|
||||
MODE_INFO *mi, MV_REFERENCE_FRAME ref_frame,
|
||||
int_mv *mv_ref_list, int mi_row, int mi_col,
|
||||
uint8_t *mode_context) {
|
||||
find_mv_refs_idx(cm, xd, mi, ref_frame, mv_ref_list, -1, mi_row, mi_col,
|
||||
mode_context);
|
||||
}
|
||||
|
||||
void vp9_find_best_ref_mvs(MACROBLOCKD *xd, int allow_hp, int_mv *mvlist,
|
||||
int_mv *nearest_mv, int_mv *near_mv) {
|
||||
int i;
|
||||
// Make sure all the candidates are properly clamped etc
|
||||
for (i = 0; i < MAX_MV_REF_CANDIDATES; ++i) {
|
||||
lower_mv_precision(&mvlist[i].as_mv, allow_hp);
|
||||
clamp_mv2(&mvlist[i].as_mv, xd);
|
||||
}
|
||||
*nearest_mv = mvlist[0];
|
||||
*near_mv = mvlist[1];
|
||||
}
|
||||
|
||||
void vp9_append_sub8x8_mvs_for_idx(VP9_COMMON *cm, MACROBLOCKD *xd, int block,
|
||||
int ref, int mi_row, int mi_col,
|
||||
int_mv *nearest_mv, int_mv *near_mv,
|
||||
uint8_t *mode_context) {
|
||||
int_mv mv_list[MAX_MV_REF_CANDIDATES];
|
||||
MODE_INFO *const mi = xd->mi[0];
|
||||
b_mode_info *bmi = mi->bmi;
|
||||
int n;
|
||||
|
||||
assert(MAX_MV_REF_CANDIDATES == 2);
|
||||
|
||||
find_mv_refs_idx(cm, xd, mi, mi->ref_frame[ref], mv_list, block, mi_row,
|
||||
mi_col, mode_context);
|
||||
|
||||
near_mv->as_int = 0;
|
||||
switch (block) {
|
||||
case 0:
|
||||
nearest_mv->as_int = mv_list[0].as_int;
|
||||
near_mv->as_int = mv_list[1].as_int;
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
nearest_mv->as_int = bmi[0].as_mv[ref].as_int;
|
||||
for (n = 0; n < MAX_MV_REF_CANDIDATES; ++n)
|
||||
if (nearest_mv->as_int != mv_list[n].as_int) {
|
||||
near_mv->as_int = mv_list[n].as_int;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 3: {
|
||||
int_mv candidates[2 + MAX_MV_REF_CANDIDATES];
|
||||
candidates[0] = bmi[1].as_mv[ref];
|
||||
candidates[1] = bmi[0].as_mv[ref];
|
||||
candidates[2] = mv_list[0];
|
||||
candidates[3] = mv_list[1];
|
||||
|
||||
nearest_mv->as_int = bmi[2].as_mv[ref].as_int;
|
||||
for (n = 0; n < 2 + MAX_MV_REF_CANDIDATES; ++n)
|
||||
if (nearest_mv->as_int != candidates[n].as_int) {
|
||||
near_mv->as_int = candidates[n].as_int;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: assert(0 && "Invalid block index.");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,323 @@
|
||||
/*
|
||||
* 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 VPX_VP9_COMMON_VP9_MVREF_COMMON_H_
|
||||
#define VPX_VP9_COMMON_VP9_MVREF_COMMON_H_
|
||||
|
||||
#include "vp9/common/vp9_onyxc_int.h"
|
||||
#include "vp9/common/vp9_blockd.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define LEFT_TOP_MARGIN ((VP9_ENC_BORDER_IN_PIXELS - VP9_INTERP_EXTEND) << 3)
|
||||
#define RIGHT_BOTTOM_MARGIN \
|
||||
((VP9_ENC_BORDER_IN_PIXELS - VP9_INTERP_EXTEND) << 3)
|
||||
|
||||
#define MVREF_NEIGHBOURS 8
|
||||
|
||||
typedef struct position {
|
||||
int row;
|
||||
int col;
|
||||
} POSITION;
|
||||
|
||||
typedef enum {
|
||||
BOTH_ZERO = 0,
|
||||
ZERO_PLUS_PREDICTED = 1,
|
||||
BOTH_PREDICTED = 2,
|
||||
NEW_PLUS_NON_INTRA = 3,
|
||||
BOTH_NEW = 4,
|
||||
INTRA_PLUS_NON_INTRA = 5,
|
||||
BOTH_INTRA = 6,
|
||||
INVALID_CASE = 9
|
||||
} motion_vector_context;
|
||||
|
||||
// This is used to figure out a context for the ref blocks. The code flattens
|
||||
// an array that would have 3 possible counts (0, 1 & 2) for 3 choices by
|
||||
// adding 9 for each intra block, 3 for each zero mv and 1 for each new
|
||||
// motion vector. This single number is then converted into a context
|
||||
// with a single lookup ( counter_to_context ).
|
||||
static const int mode_2_counter[MB_MODE_COUNT] = {
|
||||
9, // DC_PRED
|
||||
9, // V_PRED
|
||||
9, // H_PRED
|
||||
9, // D45_PRED
|
||||
9, // D135_PRED
|
||||
9, // D117_PRED
|
||||
9, // D153_PRED
|
||||
9, // D207_PRED
|
||||
9, // D63_PRED
|
||||
9, // TM_PRED
|
||||
0, // NEARESTMV
|
||||
0, // NEARMV
|
||||
3, // ZEROMV
|
||||
1, // NEWMV
|
||||
};
|
||||
|
||||
// There are 3^3 different combinations of 3 counts that can be either 0,1 or
|
||||
// 2. However the actual count can never be greater than 2 so the highest
|
||||
// counter we need is 18. 9 is an invalid counter that's never used.
|
||||
static const int counter_to_context[19] = {
|
||||
BOTH_PREDICTED, // 0
|
||||
NEW_PLUS_NON_INTRA, // 1
|
||||
BOTH_NEW, // 2
|
||||
ZERO_PLUS_PREDICTED, // 3
|
||||
NEW_PLUS_NON_INTRA, // 4
|
||||
INVALID_CASE, // 5
|
||||
BOTH_ZERO, // 6
|
||||
INVALID_CASE, // 7
|
||||
INVALID_CASE, // 8
|
||||
INTRA_PLUS_NON_INTRA, // 9
|
||||
INTRA_PLUS_NON_INTRA, // 10
|
||||
INVALID_CASE, // 11
|
||||
INTRA_PLUS_NON_INTRA, // 12
|
||||
INVALID_CASE, // 13
|
||||
INVALID_CASE, // 14
|
||||
INVALID_CASE, // 15
|
||||
INVALID_CASE, // 16
|
||||
INVALID_CASE, // 17
|
||||
BOTH_INTRA // 18
|
||||
};
|
||||
|
||||
static const POSITION mv_ref_blocks[BLOCK_SIZES][MVREF_NEIGHBOURS] = {
|
||||
// 4X4
|
||||
{ { -1, 0 },
|
||||
{ 0, -1 },
|
||||
{ -1, -1 },
|
||||
{ -2, 0 },
|
||||
{ 0, -2 },
|
||||
{ -2, -1 },
|
||||
{ -1, -2 },
|
||||
{ -2, -2 } },
|
||||
// 4X8
|
||||
{ { -1, 0 },
|
||||
{ 0, -1 },
|
||||
{ -1, -1 },
|
||||
{ -2, 0 },
|
||||
{ 0, -2 },
|
||||
{ -2, -1 },
|
||||
{ -1, -2 },
|
||||
{ -2, -2 } },
|
||||
// 8X4
|
||||
{ { -1, 0 },
|
||||
{ 0, -1 },
|
||||
{ -1, -1 },
|
||||
{ -2, 0 },
|
||||
{ 0, -2 },
|
||||
{ -2, -1 },
|
||||
{ -1, -2 },
|
||||
{ -2, -2 } },
|
||||
// 8X8
|
||||
{ { -1, 0 },
|
||||
{ 0, -1 },
|
||||
{ -1, -1 },
|
||||
{ -2, 0 },
|
||||
{ 0, -2 },
|
||||
{ -2, -1 },
|
||||
{ -1, -2 },
|
||||
{ -2, -2 } },
|
||||
// 8X16
|
||||
{ { 0, -1 },
|
||||
{ -1, 0 },
|
||||
{ 1, -1 },
|
||||
{ -1, -1 },
|
||||
{ 0, -2 },
|
||||
{ -2, 0 },
|
||||
{ -2, -1 },
|
||||
{ -1, -2 } },
|
||||
// 16X8
|
||||
{ { -1, 0 },
|
||||
{ 0, -1 },
|
||||
{ -1, 1 },
|
||||
{ -1, -1 },
|
||||
{ -2, 0 },
|
||||
{ 0, -2 },
|
||||
{ -1, -2 },
|
||||
{ -2, -1 } },
|
||||
// 16X16
|
||||
{ { -1, 0 },
|
||||
{ 0, -1 },
|
||||
{ -1, 1 },
|
||||
{ 1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -3, 0 },
|
||||
{ 0, -3 },
|
||||
{ -3, -3 } },
|
||||
// 16X32
|
||||
{ { 0, -1 },
|
||||
{ -1, 0 },
|
||||
{ 2, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, 1 },
|
||||
{ 0, -3 },
|
||||
{ -3, 0 },
|
||||
{ -3, -3 } },
|
||||
// 32X16
|
||||
{ { -1, 0 },
|
||||
{ 0, -1 },
|
||||
{ -1, 2 },
|
||||
{ -1, -1 },
|
||||
{ 1, -1 },
|
||||
{ -3, 0 },
|
||||
{ 0, -3 },
|
||||
{ -3, -3 } },
|
||||
// 32X32
|
||||
{ { -1, 1 },
|
||||
{ 1, -1 },
|
||||
{ -1, 2 },
|
||||
{ 2, -1 },
|
||||
{ -1, -1 },
|
||||
{ -3, 0 },
|
||||
{ 0, -3 },
|
||||
{ -3, -3 } },
|
||||
// 32X64
|
||||
{ { 0, -1 },
|
||||
{ -1, 0 },
|
||||
{ 4, -1 },
|
||||
{ -1, 2 },
|
||||
{ -1, -1 },
|
||||
{ 0, -3 },
|
||||
{ -3, 0 },
|
||||
{ 2, -1 } },
|
||||
// 64X32
|
||||
{ { -1, 0 },
|
||||
{ 0, -1 },
|
||||
{ -1, 4 },
|
||||
{ 2, -1 },
|
||||
{ -1, -1 },
|
||||
{ -3, 0 },
|
||||
{ 0, -3 },
|
||||
{ -1, 2 } },
|
||||
// 64X64
|
||||
{ { -1, 3 },
|
||||
{ 3, -1 },
|
||||
{ -1, 4 },
|
||||
{ 4, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, 0 },
|
||||
{ 0, -1 },
|
||||
{ -1, 6 } }
|
||||
};
|
||||
|
||||
static const int idx_n_column_to_subblock[4][2] = {
|
||||
{ 1, 2 }, { 1, 3 }, { 3, 2 }, { 3, 3 }
|
||||
};
|
||||
|
||||
// clamp_mv_ref
|
||||
#define MV_BORDER (16 << 3) // Allow 16 pels in 1/8th pel units
|
||||
|
||||
static INLINE void clamp_mv_ref(MV *mv, const MACROBLOCKD *xd) {
|
||||
clamp_mv(mv, xd->mb_to_left_edge - MV_BORDER,
|
||||
xd->mb_to_right_edge + MV_BORDER, xd->mb_to_top_edge - MV_BORDER,
|
||||
xd->mb_to_bottom_edge + MV_BORDER);
|
||||
}
|
||||
|
||||
// This function returns either the appropriate sub block or block's mv
|
||||
// on whether the block_size < 8x8 and we have check_sub_blocks set.
|
||||
static INLINE int_mv get_sub_block_mv(const MODE_INFO *candidate, int which_mv,
|
||||
int search_col, int block_idx) {
|
||||
return block_idx >= 0 && candidate->sb_type < BLOCK_8X8
|
||||
? candidate
|
||||
->bmi[idx_n_column_to_subblock[block_idx][search_col == 0]]
|
||||
.as_mv[which_mv]
|
||||
: candidate->mv[which_mv];
|
||||
}
|
||||
|
||||
// Performs mv sign inversion if indicated by the reference frame combination.
|
||||
static INLINE int_mv scale_mv(const MODE_INFO *mi, int ref,
|
||||
const MV_REFERENCE_FRAME this_ref_frame,
|
||||
const int *ref_sign_bias) {
|
||||
int_mv mv = mi->mv[ref];
|
||||
if (ref_sign_bias[mi->ref_frame[ref]] != ref_sign_bias[this_ref_frame]) {
|
||||
mv.as_mv.row *= -1;
|
||||
mv.as_mv.col *= -1;
|
||||
}
|
||||
return mv;
|
||||
}
|
||||
|
||||
// This macro is used to add a motion vector mv_ref list if it isn't
|
||||
// already in the list. If it's the second motion vector it will also
|
||||
// skip all additional processing and jump to Done!
|
||||
#define ADD_MV_REF_LIST(mv, refmv_count, mv_ref_list, Done) \
|
||||
do { \
|
||||
if (refmv_count) { \
|
||||
if ((mv).as_int != (mv_ref_list)[0].as_int) { \
|
||||
(mv_ref_list)[(refmv_count)] = (mv); \
|
||||
goto Done; \
|
||||
} \
|
||||
} else { \
|
||||
(mv_ref_list)[(refmv_count)++] = (mv); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// If either reference frame is different, not INTRA, and they
|
||||
// are different from each other scale and add the mv to our list.
|
||||
#define IF_DIFF_REF_FRAME_ADD_MV(mbmi, ref_frame, ref_sign_bias, refmv_count, \
|
||||
mv_ref_list, Done) \
|
||||
do { \
|
||||
if (is_inter_block(mbmi)) { \
|
||||
if ((mbmi)->ref_frame[0] != (ref_frame)) \
|
||||
ADD_MV_REF_LIST(scale_mv((mbmi), 0, ref_frame, ref_sign_bias), \
|
||||
refmv_count, mv_ref_list, Done); \
|
||||
if (has_second_ref(mbmi) && (mbmi)->ref_frame[1] != (ref_frame) && \
|
||||
(mbmi)->mv[1].as_int != (mbmi)->mv[0].as_int) \
|
||||
ADD_MV_REF_LIST(scale_mv((mbmi), 1, ref_frame, ref_sign_bias), \
|
||||
refmv_count, mv_ref_list, Done); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// Checks that the given mi_row, mi_col and search point
|
||||
// are inside the borders of the tile.
|
||||
static INLINE int is_inside(const TileInfo *const tile, int mi_col, int mi_row,
|
||||
int mi_rows, const POSITION *mi_pos) {
|
||||
return !(mi_row + mi_pos->row < 0 ||
|
||||
mi_col + mi_pos->col < tile->mi_col_start ||
|
||||
mi_row + mi_pos->row >= mi_rows ||
|
||||
mi_col + mi_pos->col >= tile->mi_col_end);
|
||||
}
|
||||
|
||||
// TODO(jingning): this mv clamping function should be block size dependent.
|
||||
static INLINE void clamp_mv2(MV *mv, const MACROBLOCKD *xd) {
|
||||
clamp_mv(mv, xd->mb_to_left_edge - LEFT_TOP_MARGIN,
|
||||
xd->mb_to_right_edge + RIGHT_BOTTOM_MARGIN,
|
||||
xd->mb_to_top_edge - LEFT_TOP_MARGIN,
|
||||
xd->mb_to_bottom_edge + RIGHT_BOTTOM_MARGIN);
|
||||
}
|
||||
|
||||
static INLINE void lower_mv_precision(MV *mv, int allow_hp) {
|
||||
const int use_hp = allow_hp && use_mv_hp(mv);
|
||||
if (!use_hp) {
|
||||
if (mv->row & 1) mv->row += (mv->row > 0 ? -1 : 1);
|
||||
if (mv->col & 1) mv->col += (mv->col > 0 ? -1 : 1);
|
||||
}
|
||||
}
|
||||
|
||||
typedef void (*find_mv_refs_sync)(void *const data, int mi_row);
|
||||
void vp9_find_mv_refs(const VP9_COMMON *cm, const MACROBLOCKD *xd,
|
||||
MODE_INFO *mi, MV_REFERENCE_FRAME ref_frame,
|
||||
int_mv *mv_ref_list, int mi_row, int mi_col,
|
||||
uint8_t *mode_context);
|
||||
|
||||
// check a list of motion vectors by sad score using a number rows of pixels
|
||||
// above and a number cols of pixels in the left to select the one with best
|
||||
// score to use as ref motion vector
|
||||
void vp9_find_best_ref_mvs(MACROBLOCKD *xd, int allow_hp, int_mv *mvlist,
|
||||
int_mv *nearest_mv, int_mv *near_mv);
|
||||
|
||||
void vp9_append_sub8x8_mvs_for_idx(VP9_COMMON *cm, MACROBLOCKD *xd, int block,
|
||||
int ref, int mi_row, int mi_col,
|
||||
int_mv *nearest_mv, int_mv *near_mv,
|
||||
uint8_t *mode_context);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_COMMON_VP9_MVREF_COMMON_H_
|
||||
@@ -0,0 +1,438 @@
|
||||
/*
|
||||
* 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 VPX_VP9_COMMON_VP9_ONYXC_INT_H_
|
||||
#define VPX_VP9_COMMON_VP9_ONYXC_INT_H_
|
||||
|
||||
#include "./vpx_config.h"
|
||||
#include "vpx/internal/vpx_codec_internal.h"
|
||||
#include "vpx_util/vpx_thread.h"
|
||||
#include "./vp9_rtcd.h"
|
||||
#include "vp9/common/vp9_alloccommon.h"
|
||||
#include "vp9/common/vp9_loopfilter.h"
|
||||
#include "vp9/common/vp9_entropymv.h"
|
||||
#include "vp9/common/vp9_entropy.h"
|
||||
#include "vp9/common/vp9_entropymode.h"
|
||||
#include "vp9/common/vp9_frame_buffers.h"
|
||||
#include "vp9/common/vp9_quant_common.h"
|
||||
#include "vp9/common/vp9_tile_common.h"
|
||||
|
||||
#if CONFIG_VP9_POSTPROC
|
||||
#include "vp9/common/vp9_postproc.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define REFS_PER_FRAME 3
|
||||
|
||||
#define REF_FRAMES_LOG2 3
|
||||
#define REF_FRAMES (1 << REF_FRAMES_LOG2)
|
||||
|
||||
// 1 scratch frame for the new frame, REFS_PER_FRAME for scaled references on
|
||||
// the encoder.
|
||||
#define FRAME_BUFFERS (REF_FRAMES + 1 + REFS_PER_FRAME)
|
||||
|
||||
#define FRAME_CONTEXTS_LOG2 2
|
||||
#define FRAME_CONTEXTS (1 << FRAME_CONTEXTS_LOG2)
|
||||
|
||||
#define NUM_PING_PONG_BUFFERS 2
|
||||
|
||||
extern const struct {
|
||||
PARTITION_CONTEXT above;
|
||||
PARTITION_CONTEXT left;
|
||||
} partition_context_lookup[BLOCK_SIZES];
|
||||
|
||||
typedef enum {
|
||||
SINGLE_REFERENCE = 0,
|
||||
COMPOUND_REFERENCE = 1,
|
||||
REFERENCE_MODE_SELECT = 2,
|
||||
REFERENCE_MODES = 3,
|
||||
} REFERENCE_MODE;
|
||||
|
||||
typedef struct {
|
||||
int_mv mv[2];
|
||||
MV_REFERENCE_FRAME ref_frame[2];
|
||||
} MV_REF;
|
||||
|
||||
typedef struct {
|
||||
int ref_count;
|
||||
MV_REF *mvs;
|
||||
int mi_rows;
|
||||
int mi_cols;
|
||||
uint8_t released;
|
||||
int frame_index;
|
||||
vpx_codec_frame_buffer_t raw_frame_buffer;
|
||||
YV12_BUFFER_CONFIG buf;
|
||||
} RefCntBuffer;
|
||||
|
||||
typedef struct BufferPool {
|
||||
// Private data associated with the frame buffer callbacks.
|
||||
void *cb_priv;
|
||||
|
||||
vpx_get_frame_buffer_cb_fn_t get_fb_cb;
|
||||
vpx_release_frame_buffer_cb_fn_t release_fb_cb;
|
||||
|
||||
RefCntBuffer frame_bufs[FRAME_BUFFERS];
|
||||
|
||||
// Frame buffers allocated internally by the codec.
|
||||
InternalFrameBufferList int_frame_buffers;
|
||||
} BufferPool;
|
||||
|
||||
typedef struct VP9Common {
|
||||
struct vpx_internal_error_info error;
|
||||
vpx_color_space_t color_space;
|
||||
vpx_color_range_t color_range;
|
||||
int width;
|
||||
int height;
|
||||
int render_width;
|
||||
int render_height;
|
||||
int last_width;
|
||||
int last_height;
|
||||
|
||||
// TODO(jkoleszar): this implies chroma ss right now, but could vary per
|
||||
// plane. Revisit as part of the future change to YV12_BUFFER_CONFIG to
|
||||
// support additional planes.
|
||||
int subsampling_x;
|
||||
int subsampling_y;
|
||||
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
int use_highbitdepth; // Marks if we need to use 16bit frame buffers.
|
||||
#endif
|
||||
|
||||
YV12_BUFFER_CONFIG *frame_to_show;
|
||||
RefCntBuffer *prev_frame;
|
||||
|
||||
// TODO(hkuang): Combine this with cur_buf in macroblockd.
|
||||
RefCntBuffer *cur_frame;
|
||||
|
||||
int ref_frame_map[REF_FRAMES]; /* maps fb_idx to reference slot */
|
||||
|
||||
// Prepare ref_frame_map for the next frame.
|
||||
// Only used in frame parallel decode.
|
||||
int next_ref_frame_map[REF_FRAMES];
|
||||
|
||||
// TODO(jkoleszar): could expand active_ref_idx to 4, with 0 as intra, and
|
||||
// roll new_fb_idx into it.
|
||||
|
||||
// Each frame can reference REFS_PER_FRAME buffers
|
||||
RefBuffer frame_refs[REFS_PER_FRAME];
|
||||
|
||||
int new_fb_idx;
|
||||
|
||||
int cur_show_frame_fb_idx;
|
||||
|
||||
#if CONFIG_VP9_POSTPROC
|
||||
YV12_BUFFER_CONFIG post_proc_buffer;
|
||||
YV12_BUFFER_CONFIG post_proc_buffer_int;
|
||||
#endif
|
||||
|
||||
FRAME_TYPE last_frame_type; /* last frame's frame type for motion search.*/
|
||||
FRAME_TYPE frame_type;
|
||||
|
||||
int show_frame;
|
||||
int last_show_frame;
|
||||
int show_existing_frame;
|
||||
|
||||
// Flag signaling that the frame is encoded using only INTRA modes.
|
||||
uint8_t intra_only;
|
||||
uint8_t last_intra_only;
|
||||
|
||||
int allow_high_precision_mv;
|
||||
|
||||
// Flag signaling that the frame context should be reset to default values.
|
||||
// 0 or 1 implies don't reset, 2 reset just the context specified in the
|
||||
// frame header, 3 reset all contexts.
|
||||
int reset_frame_context;
|
||||
|
||||
// MBs, mb_rows/cols is in 16-pixel units; mi_rows/cols is in
|
||||
// MODE_INFO (8-pixel) units.
|
||||
int MBs;
|
||||
int mb_rows, mi_rows;
|
||||
int mb_cols, mi_cols;
|
||||
int mi_stride;
|
||||
|
||||
/* profile settings */
|
||||
TX_MODE tx_mode;
|
||||
|
||||
int base_qindex;
|
||||
int y_dc_delta_q;
|
||||
int uv_dc_delta_q;
|
||||
int uv_ac_delta_q;
|
||||
int16_t y_dequant[MAX_SEGMENTS][2];
|
||||
int16_t uv_dequant[MAX_SEGMENTS][2];
|
||||
|
||||
/* We allocate a MODE_INFO struct for each macroblock, together with
|
||||
an extra row on top and column on the left to simplify prediction. */
|
||||
int mi_alloc_size;
|
||||
MODE_INFO *mip; /* Base of allocated array */
|
||||
MODE_INFO *mi; /* Corresponds to upper left visible macroblock */
|
||||
|
||||
// TODO(agrange): Move prev_mi into encoder structure.
|
||||
// prev_mip and prev_mi will only be allocated in VP9 encoder.
|
||||
MODE_INFO *prev_mip; /* MODE_INFO array 'mip' from last decoded frame */
|
||||
MODE_INFO *prev_mi; /* 'mi' from last frame (points into prev_mip) */
|
||||
|
||||
// Separate mi functions between encoder and decoder.
|
||||
int (*alloc_mi)(struct VP9Common *cm, int mi_size);
|
||||
void (*free_mi)(struct VP9Common *cm);
|
||||
void (*setup_mi)(struct VP9Common *cm);
|
||||
|
||||
// Grid of pointers to 8x8 MODE_INFO structs. Any 8x8 not in the visible
|
||||
// area will be NULL.
|
||||
MODE_INFO **mi_grid_base;
|
||||
MODE_INFO **mi_grid_visible;
|
||||
MODE_INFO **prev_mi_grid_base;
|
||||
MODE_INFO **prev_mi_grid_visible;
|
||||
|
||||
// Whether to use previous frame's motion vectors for prediction.
|
||||
int use_prev_frame_mvs;
|
||||
|
||||
// Persistent mb segment id map used in prediction.
|
||||
int seg_map_idx;
|
||||
int prev_seg_map_idx;
|
||||
|
||||
uint8_t *seg_map_array[NUM_PING_PONG_BUFFERS];
|
||||
uint8_t *last_frame_seg_map;
|
||||
uint8_t *current_frame_seg_map;
|
||||
int seg_map_alloc_size;
|
||||
|
||||
INTERP_FILTER interp_filter;
|
||||
|
||||
loop_filter_info_n lf_info;
|
||||
|
||||
int refresh_frame_context; /* Two state 0 = NO, 1 = YES */
|
||||
|
||||
int ref_frame_sign_bias[MAX_REF_FRAMES]; /* Two state 0, 1 */
|
||||
|
||||
struct loopfilter lf;
|
||||
struct segmentation seg;
|
||||
|
||||
// Context probabilities for reference frame prediction
|
||||
MV_REFERENCE_FRAME comp_fixed_ref;
|
||||
MV_REFERENCE_FRAME comp_var_ref[2];
|
||||
REFERENCE_MODE reference_mode;
|
||||
|
||||
FRAME_CONTEXT *fc; /* this frame entropy */
|
||||
FRAME_CONTEXT *frame_contexts; // FRAME_CONTEXTS
|
||||
unsigned int frame_context_idx; /* Context to use/update */
|
||||
FRAME_COUNTS counts;
|
||||
|
||||
unsigned int current_video_frame;
|
||||
BITSTREAM_PROFILE profile;
|
||||
|
||||
// VPX_BITS_8 in profile 0 or 1, VPX_BITS_10 or VPX_BITS_12 in profile 2 or 3.
|
||||
vpx_bit_depth_t bit_depth;
|
||||
vpx_bit_depth_t dequant_bit_depth; // bit_depth of current dequantizer
|
||||
|
||||
#if CONFIG_VP9_POSTPROC
|
||||
struct postproc_state postproc_state;
|
||||
#endif
|
||||
|
||||
int error_resilient_mode;
|
||||
int frame_parallel_decoding_mode;
|
||||
|
||||
int log2_tile_cols, log2_tile_rows;
|
||||
int byte_alignment;
|
||||
int skip_loop_filter;
|
||||
|
||||
// External BufferPool passed from outside.
|
||||
BufferPool *buffer_pool;
|
||||
|
||||
PARTITION_CONTEXT *above_seg_context;
|
||||
ENTROPY_CONTEXT *above_context;
|
||||
int above_context_alloc_cols;
|
||||
|
||||
int lf_row;
|
||||
} VP9_COMMON;
|
||||
|
||||
typedef struct {
|
||||
int frame_width;
|
||||
int frame_height;
|
||||
int render_frame_width;
|
||||
int render_frame_height;
|
||||
int mi_rows;
|
||||
int mi_cols;
|
||||
int mb_rows;
|
||||
int mb_cols;
|
||||
int num_mbs;
|
||||
vpx_bit_depth_t bit_depth;
|
||||
} FRAME_INFO;
|
||||
|
||||
static INLINE void init_frame_info(FRAME_INFO *frame_info,
|
||||
const VP9_COMMON *cm) {
|
||||
frame_info->frame_width = cm->width;
|
||||
frame_info->frame_height = cm->height;
|
||||
frame_info->render_frame_width = cm->render_width;
|
||||
frame_info->render_frame_height = cm->render_height;
|
||||
frame_info->mi_cols = cm->mi_cols;
|
||||
frame_info->mi_rows = cm->mi_rows;
|
||||
frame_info->mb_cols = cm->mb_cols;
|
||||
frame_info->mb_rows = cm->mb_rows;
|
||||
frame_info->num_mbs = cm->MBs;
|
||||
frame_info->bit_depth = cm->bit_depth;
|
||||
// TODO(angiebird): Figure out how to get subsampling_x/y here
|
||||
}
|
||||
|
||||
static INLINE YV12_BUFFER_CONFIG *get_buf_frame(VP9_COMMON *cm, int index) {
|
||||
if (index < 0 || index >= FRAME_BUFFERS) return NULL;
|
||||
if (cm->error.error_code != VPX_CODEC_OK) return NULL;
|
||||
return &cm->buffer_pool->frame_bufs[index].buf;
|
||||
}
|
||||
|
||||
static INLINE YV12_BUFFER_CONFIG *get_ref_frame(VP9_COMMON *cm, int index) {
|
||||
if (index < 0 || index >= REF_FRAMES) return NULL;
|
||||
if (cm->ref_frame_map[index] < 0) return NULL;
|
||||
assert(cm->ref_frame_map[index] < FRAME_BUFFERS);
|
||||
return &cm->buffer_pool->frame_bufs[cm->ref_frame_map[index]].buf;
|
||||
}
|
||||
|
||||
static INLINE YV12_BUFFER_CONFIG *get_frame_new_buffer(VP9_COMMON *cm) {
|
||||
return &cm->buffer_pool->frame_bufs[cm->new_fb_idx].buf;
|
||||
}
|
||||
|
||||
static INLINE int get_free_fb(VP9_COMMON *cm) {
|
||||
RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < FRAME_BUFFERS; ++i)
|
||||
if (frame_bufs[i].ref_count == 0) break;
|
||||
|
||||
if (i != FRAME_BUFFERS) {
|
||||
frame_bufs[i].ref_count = 1;
|
||||
} else {
|
||||
// Reset i to be INVALID_IDX to indicate no free buffer found.
|
||||
i = INVALID_IDX;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static INLINE void ref_cnt_fb(RefCntBuffer *bufs, int *idx, int new_idx) {
|
||||
const int ref_index = *idx;
|
||||
|
||||
if (ref_index >= 0 && bufs[ref_index].ref_count > 0)
|
||||
bufs[ref_index].ref_count--;
|
||||
|
||||
*idx = new_idx;
|
||||
|
||||
bufs[new_idx].ref_count++;
|
||||
}
|
||||
|
||||
static INLINE int mi_cols_aligned_to_sb(int n_mis) {
|
||||
return ALIGN_POWER_OF_TWO(n_mis, MI_BLOCK_SIZE_LOG2);
|
||||
}
|
||||
|
||||
static INLINE int frame_is_intra_only(const VP9_COMMON *const cm) {
|
||||
return cm->frame_type == KEY_FRAME || cm->intra_only;
|
||||
}
|
||||
|
||||
static INLINE void set_partition_probs(const VP9_COMMON *const cm,
|
||||
MACROBLOCKD *const xd) {
|
||||
xd->partition_probs =
|
||||
frame_is_intra_only(cm)
|
||||
? &vp9_kf_partition_probs[0]
|
||||
: (const vpx_prob(*)[PARTITION_TYPES - 1]) cm->fc->partition_prob;
|
||||
}
|
||||
|
||||
static INLINE void vp9_init_macroblockd(VP9_COMMON *cm, MACROBLOCKD *xd,
|
||||
tran_low_t *dqcoeff) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_MB_PLANE; ++i) {
|
||||
xd->plane[i].dqcoeff = dqcoeff;
|
||||
xd->above_context[i] =
|
||||
cm->above_context +
|
||||
i * sizeof(*cm->above_context) * 2 * mi_cols_aligned_to_sb(cm->mi_cols);
|
||||
|
||||
if (get_plane_type(i) == PLANE_TYPE_Y) {
|
||||
memcpy(xd->plane[i].seg_dequant, cm->y_dequant, sizeof(cm->y_dequant));
|
||||
} else {
|
||||
memcpy(xd->plane[i].seg_dequant, cm->uv_dequant, sizeof(cm->uv_dequant));
|
||||
}
|
||||
xd->fc = cm->fc;
|
||||
}
|
||||
|
||||
xd->above_seg_context = cm->above_seg_context;
|
||||
xd->mi_stride = cm->mi_stride;
|
||||
xd->error_info = &cm->error;
|
||||
|
||||
set_partition_probs(cm, xd);
|
||||
}
|
||||
|
||||
static INLINE const vpx_prob *get_partition_probs(const MACROBLOCKD *xd,
|
||||
int ctx) {
|
||||
return xd->partition_probs[ctx];
|
||||
}
|
||||
|
||||
static INLINE void set_skip_context(MACROBLOCKD *xd, int mi_row, int mi_col) {
|
||||
const int above_idx = mi_col * 2;
|
||||
const int left_idx = (mi_row * 2) & 15;
|
||||
int i;
|
||||
for (i = 0; i < MAX_MB_PLANE; ++i) {
|
||||
struct macroblockd_plane *const pd = &xd->plane[i];
|
||||
pd->above_context = &xd->above_context[i][above_idx >> pd->subsampling_x];
|
||||
pd->left_context = &xd->left_context[i][left_idx >> pd->subsampling_y];
|
||||
}
|
||||
}
|
||||
|
||||
static INLINE int calc_mi_size(int len) {
|
||||
// len is in mi units.
|
||||
return len + MI_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
static INLINE void set_mi_row_col(MACROBLOCKD *xd, const TileInfo *const tile,
|
||||
int mi_row, int bh, int mi_col, int bw,
|
||||
int mi_rows, int mi_cols) {
|
||||
xd->mb_to_top_edge = -((mi_row * MI_SIZE) * 8);
|
||||
xd->mb_to_bottom_edge = ((mi_rows - bh - mi_row) * MI_SIZE) * 8;
|
||||
xd->mb_to_left_edge = -((mi_col * MI_SIZE) * 8);
|
||||
xd->mb_to_right_edge = ((mi_cols - bw - mi_col) * MI_SIZE) * 8;
|
||||
|
||||
// Are edges available for intra prediction?
|
||||
xd->above_mi = (mi_row != 0) ? xd->mi[-xd->mi_stride] : NULL;
|
||||
xd->left_mi = (mi_col > tile->mi_col_start) ? xd->mi[-1] : NULL;
|
||||
}
|
||||
|
||||
static INLINE void update_partition_context(MACROBLOCKD *xd, int mi_row,
|
||||
int mi_col, BLOCK_SIZE subsize,
|
||||
BLOCK_SIZE bsize) {
|
||||
PARTITION_CONTEXT *const above_ctx = xd->above_seg_context + mi_col;
|
||||
PARTITION_CONTEXT *const left_ctx = xd->left_seg_context + (mi_row & MI_MASK);
|
||||
|
||||
// num_4x4_blocks_wide_lookup[bsize] / 2
|
||||
const int bs = num_8x8_blocks_wide_lookup[bsize];
|
||||
|
||||
// update the partition context at the end notes. set partition bits
|
||||
// of block sizes larger than the current one to be one, and partition
|
||||
// bits of smaller block sizes to be zero.
|
||||
memset(above_ctx, partition_context_lookup[subsize].above, bs);
|
||||
memset(left_ctx, partition_context_lookup[subsize].left, bs);
|
||||
}
|
||||
|
||||
static INLINE int partition_plane_context(const MACROBLOCKD *xd, int mi_row,
|
||||
int mi_col, BLOCK_SIZE bsize) {
|
||||
const PARTITION_CONTEXT *above_ctx = xd->above_seg_context + mi_col;
|
||||
const PARTITION_CONTEXT *left_ctx = xd->left_seg_context + (mi_row & MI_MASK);
|
||||
const int bsl = mi_width_log2_lookup[bsize];
|
||||
int above = (*above_ctx >> bsl) & 1, left = (*left_ctx >> bsl) & 1;
|
||||
|
||||
assert(b_width_log2_lookup[bsize] == b_height_log2_lookup[bsize]);
|
||||
assert(bsl >= 0);
|
||||
|
||||
return (left * 2 + above) + bsl * PARTITION_PLOFFSET;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_COMMON_VP9_ONYXC_INT_H_
|
||||
@@ -0,0 +1,434 @@
|
||||
/*
|
||||
* 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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "./vpx_dsp_rtcd.h"
|
||||
#include "./vpx_config.h"
|
||||
#include "./vpx_scale_rtcd.h"
|
||||
#include "./vp9_rtcd.h"
|
||||
|
||||
#include "vpx_dsp/vpx_dsp_common.h"
|
||||
#include "vpx_dsp/postproc.h"
|
||||
#include "vpx_ports/mem.h"
|
||||
#include "vpx_ports/system_state.h"
|
||||
#include "vpx_scale/vpx_scale.h"
|
||||
#include "vpx_scale/yv12config.h"
|
||||
|
||||
#include "vp9/common/vp9_onyxc_int.h"
|
||||
#include "vp9/common/vp9_postproc.h"
|
||||
|
||||
#if CONFIG_VP9_POSTPROC
|
||||
|
||||
static const uint8_t q_diff_thresh = 20;
|
||||
static const uint8_t last_q_thresh = 170;
|
||||
extern const int16_t vpx_rv[];
|
||||
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
static const int16_t kernel5[] = { 1, 1, 4, 1, 1 };
|
||||
|
||||
void vp9_highbd_post_proc_down_and_across_c(const uint16_t *src_ptr,
|
||||
uint16_t *dst_ptr,
|
||||
int src_pixels_per_line,
|
||||
int dst_pixels_per_line, int rows,
|
||||
int cols, int flimit) {
|
||||
uint16_t const *p_src;
|
||||
uint16_t *p_dst;
|
||||
int row, col, i, v, kernel;
|
||||
int pitch = src_pixels_per_line;
|
||||
uint16_t d[8];
|
||||
|
||||
for (row = 0; row < rows; row++) {
|
||||
// post_proc_down for one row.
|
||||
p_src = src_ptr;
|
||||
p_dst = dst_ptr;
|
||||
|
||||
for (col = 0; col < cols; col++) {
|
||||
kernel = 4;
|
||||
v = p_src[col];
|
||||
|
||||
for (i = -2; i <= 2; i++) {
|
||||
if (abs(v - p_src[col + i * pitch]) > flimit) goto down_skip_convolve;
|
||||
|
||||
kernel += kernel5[2 + i] * p_src[col + i * pitch];
|
||||
}
|
||||
|
||||
v = (kernel >> 3);
|
||||
|
||||
down_skip_convolve:
|
||||
p_dst[col] = v;
|
||||
}
|
||||
|
||||
/* now post_proc_across */
|
||||
p_src = dst_ptr;
|
||||
p_dst = dst_ptr;
|
||||
|
||||
for (i = 0; i < 8; i++) d[i] = p_src[i];
|
||||
|
||||
for (col = 0; col < cols; col++) {
|
||||
kernel = 4;
|
||||
v = p_src[col];
|
||||
|
||||
d[col & 7] = v;
|
||||
|
||||
for (i = -2; i <= 2; i++) {
|
||||
if (abs(v - p_src[col + i]) > flimit) goto across_skip_convolve;
|
||||
|
||||
kernel += kernel5[2 + i] * p_src[col + i];
|
||||
}
|
||||
|
||||
d[col & 7] = (kernel >> 3);
|
||||
|
||||
across_skip_convolve:
|
||||
if (col >= 2) p_dst[col - 2] = d[(col - 2) & 7];
|
||||
}
|
||||
|
||||
/* handle the last two pixels */
|
||||
p_dst[col - 2] = d[(col - 2) & 7];
|
||||
p_dst[col - 1] = d[(col - 1) & 7];
|
||||
|
||||
/* next row */
|
||||
src_ptr += pitch;
|
||||
dst_ptr += dst_pixels_per_line;
|
||||
}
|
||||
}
|
||||
#endif // CONFIG_VP9_HIGHBITDEPTH
|
||||
|
||||
static int q2mbl(int x) {
|
||||
if (x < 20) x = 20;
|
||||
|
||||
x = 50 + (x - 50) * 10 / 8;
|
||||
return x * x / 3;
|
||||
}
|
||||
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
void vp9_highbd_mbpost_proc_across_ip_c(uint16_t *src, int pitch, int rows,
|
||||
int cols, int flimit) {
|
||||
int r, c, i;
|
||||
|
||||
uint16_t *s = src;
|
||||
uint16_t d[16];
|
||||
|
||||
for (r = 0; r < rows; r++) {
|
||||
int sumsq = 0;
|
||||
int sum = 0;
|
||||
|
||||
for (i = -8; i <= 6; i++) {
|
||||
sumsq += s[i] * s[i];
|
||||
sum += s[i];
|
||||
d[i + 8] = 0;
|
||||
}
|
||||
|
||||
for (c = 0; c < cols + 8; c++) {
|
||||
int x = s[c + 7] - s[c - 8];
|
||||
int y = s[c + 7] + s[c - 8];
|
||||
|
||||
sum += x;
|
||||
sumsq += x * y;
|
||||
|
||||
d[c & 15] = s[c];
|
||||
|
||||
if (sumsq * 15 - sum * sum < flimit) {
|
||||
d[c & 15] = (8 + sum + s[c]) >> 4;
|
||||
}
|
||||
|
||||
s[c - 8] = d[(c - 8) & 15];
|
||||
}
|
||||
|
||||
s += pitch;
|
||||
}
|
||||
}
|
||||
#endif // CONFIG_VP9_HIGHBITDEPTH
|
||||
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
void vp9_highbd_mbpost_proc_down_c(uint16_t *dst, int pitch, int rows, int cols,
|
||||
int flimit) {
|
||||
int r, c, i;
|
||||
const int16_t *rv3 = &vpx_rv[63 & rand()]; // NOLINT
|
||||
|
||||
for (c = 0; c < cols; c++) {
|
||||
uint16_t *s = &dst[c];
|
||||
int sumsq = 0;
|
||||
int sum = 0;
|
||||
uint16_t d[16];
|
||||
const int16_t *rv2 = rv3 + ((c * 17) & 127);
|
||||
|
||||
for (i = -8; i <= 6; i++) {
|
||||
sumsq += s[i * pitch] * s[i * pitch];
|
||||
sum += s[i * pitch];
|
||||
}
|
||||
|
||||
for (r = 0; r < rows + 8; r++) {
|
||||
sumsq += s[7 * pitch] * s[7 * pitch] - s[-8 * pitch] * s[-8 * pitch];
|
||||
sum += s[7 * pitch] - s[-8 * pitch];
|
||||
d[r & 15] = s[0];
|
||||
|
||||
if (sumsq * 15 - sum * sum < flimit) {
|
||||
d[r & 15] = (rv2[r & 127] + sum + s[0]) >> 4;
|
||||
}
|
||||
|
||||
s[-8 * pitch] = d[(r - 8) & 15];
|
||||
s += pitch;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // CONFIG_VP9_HIGHBITDEPTH
|
||||
|
||||
static void deblock_and_de_macro_block(VP9_COMMON *cm,
|
||||
YV12_BUFFER_CONFIG *source,
|
||||
YV12_BUFFER_CONFIG *post, int q,
|
||||
int low_var_thresh, int flag,
|
||||
uint8_t *limits) {
|
||||
(void)low_var_thresh;
|
||||
(void)flag;
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
if (source->flags & YV12_FLAG_HIGHBITDEPTH) {
|
||||
double level = 6.0e-05 * q * q * q - .0067 * q * q + .306 * q + .0065;
|
||||
int ppl = (int)(level + .5);
|
||||
vp9_highbd_post_proc_down_and_across(
|
||||
CONVERT_TO_SHORTPTR(source->y_buffer),
|
||||
CONVERT_TO_SHORTPTR(post->y_buffer), source->y_stride, post->y_stride,
|
||||
source->y_height, source->y_width, ppl);
|
||||
|
||||
vp9_highbd_mbpost_proc_across_ip(CONVERT_TO_SHORTPTR(post->y_buffer),
|
||||
post->y_stride, post->y_height,
|
||||
post->y_width, q2mbl(q));
|
||||
|
||||
vp9_highbd_mbpost_proc_down(CONVERT_TO_SHORTPTR(post->y_buffer),
|
||||
post->y_stride, post->y_height, post->y_width,
|
||||
q2mbl(q));
|
||||
|
||||
vp9_highbd_post_proc_down_and_across(
|
||||
CONVERT_TO_SHORTPTR(source->u_buffer),
|
||||
CONVERT_TO_SHORTPTR(post->u_buffer), source->uv_stride, post->uv_stride,
|
||||
source->uv_height, source->uv_width, ppl);
|
||||
vp9_highbd_post_proc_down_and_across(
|
||||
CONVERT_TO_SHORTPTR(source->v_buffer),
|
||||
CONVERT_TO_SHORTPTR(post->v_buffer), source->uv_stride, post->uv_stride,
|
||||
source->uv_height, source->uv_width, ppl);
|
||||
} else {
|
||||
#endif // CONFIG_VP9_HIGHBITDEPTH
|
||||
vp9_deblock(cm, source, post, q, limits);
|
||||
vpx_mbpost_proc_across_ip(post->y_buffer, post->y_stride, post->y_height,
|
||||
post->y_width, q2mbl(q));
|
||||
vpx_mbpost_proc_down(post->y_buffer, post->y_stride, post->y_height,
|
||||
post->y_width, q2mbl(q));
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
}
|
||||
#endif // CONFIG_VP9_HIGHBITDEPTH
|
||||
}
|
||||
|
||||
void vp9_deblock(struct VP9Common *cm, const YV12_BUFFER_CONFIG *src,
|
||||
YV12_BUFFER_CONFIG *dst, int q, uint8_t *limits) {
|
||||
const int ppl =
|
||||
(int)(6.0e-05 * q * q * q - 0.0067 * q * q + 0.306 * q + 0.0065 + 0.5);
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
if (src->flags & YV12_FLAG_HIGHBITDEPTH) {
|
||||
int i;
|
||||
const uint8_t *const srcs[3] = { src->y_buffer, src->u_buffer,
|
||||
src->v_buffer };
|
||||
const int src_strides[3] = { src->y_stride, src->uv_stride,
|
||||
src->uv_stride };
|
||||
const int src_widths[3] = { src->y_width, src->uv_width, src->uv_width };
|
||||
const int src_heights[3] = { src->y_height, src->uv_height,
|
||||
src->uv_height };
|
||||
|
||||
uint8_t *const dsts[3] = { dst->y_buffer, dst->u_buffer, dst->v_buffer };
|
||||
const int dst_strides[3] = { dst->y_stride, dst->uv_stride,
|
||||
dst->uv_stride };
|
||||
for (i = 0; i < MAX_MB_PLANE; ++i) {
|
||||
vp9_highbd_post_proc_down_and_across(
|
||||
CONVERT_TO_SHORTPTR(srcs[i]), CONVERT_TO_SHORTPTR(dsts[i]),
|
||||
src_strides[i], dst_strides[i], src_heights[i], src_widths[i], ppl);
|
||||
}
|
||||
} else {
|
||||
#endif // CONFIG_VP9_HIGHBITDEPTH
|
||||
int mbr;
|
||||
const int mb_rows = cm->mb_rows;
|
||||
const int mb_cols = cm->mb_cols;
|
||||
memset(limits, (unsigned char)ppl, 16 * mb_cols);
|
||||
|
||||
for (mbr = 0; mbr < mb_rows; mbr++) {
|
||||
vpx_post_proc_down_and_across_mb_row(
|
||||
src->y_buffer + 16 * mbr * src->y_stride,
|
||||
dst->y_buffer + 16 * mbr * dst->y_stride, src->y_stride,
|
||||
dst->y_stride, src->y_width, limits, 16);
|
||||
vpx_post_proc_down_and_across_mb_row(
|
||||
src->u_buffer + 8 * mbr * src->uv_stride,
|
||||
dst->u_buffer + 8 * mbr * dst->uv_stride, src->uv_stride,
|
||||
dst->uv_stride, src->uv_width, limits, 8);
|
||||
vpx_post_proc_down_and_across_mb_row(
|
||||
src->v_buffer + 8 * mbr * src->uv_stride,
|
||||
dst->v_buffer + 8 * mbr * dst->uv_stride, src->uv_stride,
|
||||
dst->uv_stride, src->uv_width, limits, 8);
|
||||
}
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
}
|
||||
#endif // CONFIG_VP9_HIGHBITDEPTH
|
||||
}
|
||||
|
||||
void vp9_denoise(struct VP9Common *cm, const YV12_BUFFER_CONFIG *src,
|
||||
YV12_BUFFER_CONFIG *dst, int q, uint8_t *limits) {
|
||||
vp9_deblock(cm, src, dst, q, limits);
|
||||
}
|
||||
|
||||
static void swap_mi_and_prev_mi(VP9_COMMON *cm) {
|
||||
// Current mip will be the prev_mip for the next frame.
|
||||
MODE_INFO *temp = cm->postproc_state.prev_mip;
|
||||
cm->postproc_state.prev_mip = cm->mip;
|
||||
cm->mip = temp;
|
||||
|
||||
// Update the upper left visible macroblock ptrs.
|
||||
cm->mi = cm->mip + cm->mi_stride + 1;
|
||||
cm->postproc_state.prev_mi = cm->postproc_state.prev_mip + cm->mi_stride + 1;
|
||||
}
|
||||
|
||||
int vp9_post_proc_frame(struct VP9Common *cm, YV12_BUFFER_CONFIG *dest,
|
||||
vp9_ppflags_t *ppflags, int unscaled_width) {
|
||||
const int q = VPXMIN(105, cm->lf.filter_level * 2);
|
||||
const int flags = ppflags->post_proc_flag;
|
||||
YV12_BUFFER_CONFIG *const ppbuf = &cm->post_proc_buffer;
|
||||
struct postproc_state *const ppstate = &cm->postproc_state;
|
||||
|
||||
if (!cm->frame_to_show) return -1;
|
||||
|
||||
if (!flags) {
|
||||
*dest = *cm->frame_to_show;
|
||||
return 0;
|
||||
}
|
||||
|
||||
vpx_clear_system_state();
|
||||
|
||||
// Alloc memory for prev_mip in the first frame.
|
||||
if (cm->current_video_frame == 1) {
|
||||
ppstate->last_base_qindex = cm->base_qindex;
|
||||
ppstate->last_frame_valid = 1;
|
||||
}
|
||||
|
||||
if ((flags & VP9D_MFQE) && ppstate->prev_mip == NULL) {
|
||||
ppstate->prev_mip = vpx_calloc(cm->mi_alloc_size, sizeof(*cm->mip));
|
||||
if (!ppstate->prev_mip) {
|
||||
return 1;
|
||||
}
|
||||
ppstate->prev_mi = ppstate->prev_mip + cm->mi_stride + 1;
|
||||
}
|
||||
|
||||
// Allocate post_proc_buffer_int if needed.
|
||||
if ((flags & VP9D_MFQE) && !cm->post_proc_buffer_int.buffer_alloc) {
|
||||
if ((flags & VP9D_DEMACROBLOCK) || (flags & VP9D_DEBLOCK)) {
|
||||
const int width = ALIGN_POWER_OF_TWO(cm->width, 4);
|
||||
const int height = ALIGN_POWER_OF_TWO(cm->height, 4);
|
||||
|
||||
if (vpx_alloc_frame_buffer(&cm->post_proc_buffer_int, width, height,
|
||||
cm->subsampling_x, cm->subsampling_y,
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
cm->use_highbitdepth,
|
||||
#endif // CONFIG_VP9_HIGHBITDEPTH
|
||||
VP9_ENC_BORDER_IN_PIXELS,
|
||||
cm->byte_alignment) < 0) {
|
||||
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
|
||||
"Failed to allocate MFQE framebuffer");
|
||||
}
|
||||
|
||||
// Ensure that postproc is set to all 0s so that post proc
|
||||
// doesn't pull random data in from edge.
|
||||
memset(cm->post_proc_buffer_int.buffer_alloc, 128,
|
||||
cm->post_proc_buffer.frame_size);
|
||||
}
|
||||
}
|
||||
|
||||
if (vpx_realloc_frame_buffer(&cm->post_proc_buffer, cm->width, cm->height,
|
||||
cm->subsampling_x, cm->subsampling_y,
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
cm->use_highbitdepth,
|
||||
#endif
|
||||
VP9_DEC_BORDER_IN_PIXELS, cm->byte_alignment,
|
||||
NULL, NULL, NULL) < 0)
|
||||
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
|
||||
"Failed to allocate post-processing buffer");
|
||||
|
||||
if (flags & (VP9D_DEMACROBLOCK | VP9D_DEBLOCK)) {
|
||||
if (!cm->postproc_state.limits) {
|
||||
cm->postproc_state.limits =
|
||||
vpx_calloc(unscaled_width, sizeof(*cm->postproc_state.limits));
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & VP9D_ADDNOISE) {
|
||||
if (!cm->postproc_state.generated_noise) {
|
||||
cm->postproc_state.generated_noise = vpx_calloc(
|
||||
cm->width + 256, sizeof(*cm->postproc_state.generated_noise));
|
||||
if (!cm->postproc_state.generated_noise) return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ((flags & VP9D_MFQE) && cm->current_video_frame >= 2 &&
|
||||
ppstate->last_frame_valid && cm->bit_depth == 8 &&
|
||||
ppstate->last_base_qindex <= last_q_thresh &&
|
||||
cm->base_qindex - ppstate->last_base_qindex >= q_diff_thresh) {
|
||||
vp9_mfqe(cm);
|
||||
// TODO(jackychen): Consider whether enable deblocking by default
|
||||
// if mfqe is enabled. Need to take both the quality and the speed
|
||||
// into consideration.
|
||||
if ((flags & VP9D_DEMACROBLOCK) || (flags & VP9D_DEBLOCK)) {
|
||||
vpx_yv12_copy_frame(ppbuf, &cm->post_proc_buffer_int);
|
||||
}
|
||||
if ((flags & VP9D_DEMACROBLOCK) && cm->post_proc_buffer_int.buffer_alloc) {
|
||||
deblock_and_de_macro_block(cm, &cm->post_proc_buffer_int, ppbuf,
|
||||
q + (ppflags->deblocking_level - 5) * 10, 1, 0,
|
||||
cm->postproc_state.limits);
|
||||
} else if (flags & VP9D_DEBLOCK) {
|
||||
vp9_deblock(cm, &cm->post_proc_buffer_int, ppbuf, q,
|
||||
cm->postproc_state.limits);
|
||||
} else {
|
||||
vpx_yv12_copy_frame(&cm->post_proc_buffer_int, ppbuf);
|
||||
}
|
||||
} else if (flags & VP9D_DEMACROBLOCK) {
|
||||
deblock_and_de_macro_block(cm, cm->frame_to_show, ppbuf,
|
||||
q + (ppflags->deblocking_level - 5) * 10, 1, 0,
|
||||
cm->postproc_state.limits);
|
||||
} else if (flags & VP9D_DEBLOCK) {
|
||||
vp9_deblock(cm, cm->frame_to_show, ppbuf, q, cm->postproc_state.limits);
|
||||
} else {
|
||||
vpx_yv12_copy_frame(cm->frame_to_show, ppbuf);
|
||||
}
|
||||
|
||||
ppstate->last_base_qindex = cm->base_qindex;
|
||||
ppstate->last_frame_valid = 1;
|
||||
if (flags & VP9D_ADDNOISE) {
|
||||
const int noise_level = ppflags->noise_level;
|
||||
if (ppstate->last_q != q || ppstate->last_noise != noise_level) {
|
||||
double sigma;
|
||||
vpx_clear_system_state();
|
||||
sigma = noise_level + .5 + .6 * q / 63.0;
|
||||
ppstate->clamp =
|
||||
vpx_setup_noise(sigma, ppstate->generated_noise, cm->width + 256);
|
||||
ppstate->last_q = q;
|
||||
ppstate->last_noise = noise_level;
|
||||
}
|
||||
vpx_plane_add_noise(ppbuf->y_buffer, ppstate->generated_noise,
|
||||
ppstate->clamp, ppstate->clamp, ppbuf->y_width,
|
||||
ppbuf->y_height, ppbuf->y_stride);
|
||||
}
|
||||
|
||||
*dest = *ppbuf;
|
||||
|
||||
/* handle problem with extending borders */
|
||||
dest->y_width = cm->width;
|
||||
dest->y_height = cm->height;
|
||||
dest->uv_width = dest->y_width >> cm->subsampling_x;
|
||||
dest->uv_height = dest->y_height >> cm->subsampling_y;
|
||||
|
||||
if (flags & VP9D_MFQE) swap_mi_and_prev_mi(cm);
|
||||
return 0;
|
||||
}
|
||||
#endif // CONFIG_VP9_POSTPROC
|
||||
@@ -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 VPX_VP9_COMMON_VP9_POSTPROC_H_
|
||||
#define VPX_VP9_COMMON_VP9_POSTPROC_H_
|
||||
|
||||
#include "vpx_ports/mem.h"
|
||||
#include "vpx_scale/yv12config.h"
|
||||
#include "vp9/common/vp9_blockd.h"
|
||||
#include "vp9/common/vp9_mfqe.h"
|
||||
#include "vp9/common/vp9_ppflags.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct postproc_state {
|
||||
int last_q;
|
||||
int last_noise;
|
||||
int last_base_qindex;
|
||||
int last_frame_valid;
|
||||
MODE_INFO *prev_mip;
|
||||
MODE_INFO *prev_mi;
|
||||
int clamp;
|
||||
uint8_t *limits;
|
||||
int8_t *generated_noise;
|
||||
};
|
||||
|
||||
struct VP9Common;
|
||||
|
||||
#define MFQE_PRECISION 4
|
||||
|
||||
int vp9_post_proc_frame(struct VP9Common *cm, YV12_BUFFER_CONFIG *dest,
|
||||
vp9_ppflags_t *ppflags, int unscaled_width);
|
||||
|
||||
void vp9_denoise(struct VP9Common *cm, const YV12_BUFFER_CONFIG *src,
|
||||
YV12_BUFFER_CONFIG *dst, int q, uint8_t *limits);
|
||||
|
||||
void vp9_deblock(struct VP9Common *cm, const YV12_BUFFER_CONFIG *src,
|
||||
YV12_BUFFER_CONFIG *dst, int q, uint8_t *limits);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_COMMON_VP9_POSTPROC_H_
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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 VPX_VP9_COMMON_VP9_PPFLAGS_H_
|
||||
#define VPX_VP9_COMMON_VP9_PPFLAGS_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum {
|
||||
VP9D_NOFILTERING = 0,
|
||||
VP9D_DEBLOCK = 1 << 0,
|
||||
VP9D_DEMACROBLOCK = 1 << 1,
|
||||
VP9D_ADDNOISE = 1 << 2,
|
||||
VP9D_MFQE = 1 << 3
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
int post_proc_flag;
|
||||
int deblocking_level;
|
||||
int noise_level;
|
||||
} vp9_ppflags_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_COMMON_VP9_PPFLAGS_H_
|
||||
@@ -0,0 +1,316 @@
|
||||
|
||||
/*
|
||||
* 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 "vp9/common/vp9_common.h"
|
||||
#include "vp9/common/vp9_pred_common.h"
|
||||
#include "vp9/common/vp9_seg_common.h"
|
||||
|
||||
int vp9_compound_reference_allowed(const VP9_COMMON *cm) {
|
||||
int i;
|
||||
for (i = 1; i < REFS_PER_FRAME; ++i)
|
||||
if (cm->ref_frame_sign_bias[i + 1] != cm->ref_frame_sign_bias[1]) return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vp9_setup_compound_reference_mode(VP9_COMMON *cm) {
|
||||
if (cm->ref_frame_sign_bias[LAST_FRAME] ==
|
||||
cm->ref_frame_sign_bias[GOLDEN_FRAME]) {
|
||||
cm->comp_fixed_ref = ALTREF_FRAME;
|
||||
cm->comp_var_ref[0] = LAST_FRAME;
|
||||
cm->comp_var_ref[1] = GOLDEN_FRAME;
|
||||
} else if (cm->ref_frame_sign_bias[LAST_FRAME] ==
|
||||
cm->ref_frame_sign_bias[ALTREF_FRAME]) {
|
||||
cm->comp_fixed_ref = GOLDEN_FRAME;
|
||||
cm->comp_var_ref[0] = LAST_FRAME;
|
||||
cm->comp_var_ref[1] = ALTREF_FRAME;
|
||||
} else {
|
||||
cm->comp_fixed_ref = LAST_FRAME;
|
||||
cm->comp_var_ref[0] = GOLDEN_FRAME;
|
||||
cm->comp_var_ref[1] = ALTREF_FRAME;
|
||||
}
|
||||
}
|
||||
|
||||
int vp9_get_reference_mode_context(const VP9_COMMON *cm,
|
||||
const MACROBLOCKD *xd) {
|
||||
int ctx;
|
||||
const MODE_INFO *const above_mi = xd->above_mi;
|
||||
const MODE_INFO *const left_mi = xd->left_mi;
|
||||
const int has_above = !!above_mi;
|
||||
const int has_left = !!left_mi;
|
||||
// Note:
|
||||
// The mode info data structure has a one element border above and to the
|
||||
// left of the entries corresponding to real macroblocks.
|
||||
// The prediction flags in these dummy entries are initialized to 0.
|
||||
if (has_above && has_left) { // both edges available
|
||||
if (!has_second_ref(above_mi) && !has_second_ref(left_mi))
|
||||
// neither edge uses comp pred (0/1)
|
||||
ctx = (above_mi->ref_frame[0] == cm->comp_fixed_ref) ^
|
||||
(left_mi->ref_frame[0] == cm->comp_fixed_ref);
|
||||
else if (!has_second_ref(above_mi))
|
||||
// one of two edges uses comp pred (2/3)
|
||||
ctx = 2 + (above_mi->ref_frame[0] == cm->comp_fixed_ref ||
|
||||
!is_inter_block(above_mi));
|
||||
else if (!has_second_ref(left_mi))
|
||||
// one of two edges uses comp pred (2/3)
|
||||
ctx = 2 + (left_mi->ref_frame[0] == cm->comp_fixed_ref ||
|
||||
!is_inter_block(left_mi));
|
||||
else // both edges use comp pred (4)
|
||||
ctx = 4;
|
||||
} else if (has_above || has_left) { // one edge available
|
||||
const MODE_INFO *edge_mi = has_above ? above_mi : left_mi;
|
||||
|
||||
if (!has_second_ref(edge_mi))
|
||||
// edge does not use comp pred (0/1)
|
||||
ctx = edge_mi->ref_frame[0] == cm->comp_fixed_ref;
|
||||
else
|
||||
// edge uses comp pred (3)
|
||||
ctx = 3;
|
||||
} else { // no edges available (1)
|
||||
ctx = 1;
|
||||
}
|
||||
assert(ctx >= 0 && ctx < COMP_INTER_CONTEXTS);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
// Returns a context number for the given MB prediction signal
|
||||
int vp9_get_pred_context_comp_ref_p(const VP9_COMMON *cm,
|
||||
const MACROBLOCKD *xd) {
|
||||
int pred_context;
|
||||
const MODE_INFO *const above_mi = xd->above_mi;
|
||||
const MODE_INFO *const left_mi = xd->left_mi;
|
||||
const int above_in_image = !!above_mi;
|
||||
const int left_in_image = !!left_mi;
|
||||
|
||||
// Note:
|
||||
// The mode info data structure has a one element border above and to the
|
||||
// left of the entries corresponding to real macroblocks.
|
||||
// The prediction flags in these dummy entries are initialized to 0.
|
||||
const int fix_ref_idx = cm->ref_frame_sign_bias[cm->comp_fixed_ref];
|
||||
const int var_ref_idx = !fix_ref_idx;
|
||||
|
||||
if (above_in_image && left_in_image) { // both edges available
|
||||
const int above_intra = !is_inter_block(above_mi);
|
||||
const int left_intra = !is_inter_block(left_mi);
|
||||
|
||||
if (above_intra && left_intra) { // intra/intra (2)
|
||||
pred_context = 2;
|
||||
} else if (above_intra || left_intra) { // intra/inter
|
||||
const MODE_INFO *edge_mi = above_intra ? left_mi : above_mi;
|
||||
|
||||
if (!has_second_ref(edge_mi)) // single pred (1/3)
|
||||
pred_context = 1 + 2 * (edge_mi->ref_frame[0] != cm->comp_var_ref[1]);
|
||||
else // comp pred (1/3)
|
||||
pred_context =
|
||||
1 + 2 * (edge_mi->ref_frame[var_ref_idx] != cm->comp_var_ref[1]);
|
||||
} else { // inter/inter
|
||||
const int l_sg = !has_second_ref(left_mi);
|
||||
const int a_sg = !has_second_ref(above_mi);
|
||||
const MV_REFERENCE_FRAME vrfa =
|
||||
a_sg ? above_mi->ref_frame[0] : above_mi->ref_frame[var_ref_idx];
|
||||
const MV_REFERENCE_FRAME vrfl =
|
||||
l_sg ? left_mi->ref_frame[0] : left_mi->ref_frame[var_ref_idx];
|
||||
|
||||
if (vrfa == vrfl && cm->comp_var_ref[1] == vrfa) {
|
||||
pred_context = 0;
|
||||
} else if (l_sg && a_sg) { // single/single
|
||||
if ((vrfa == cm->comp_fixed_ref && vrfl == cm->comp_var_ref[0]) ||
|
||||
(vrfl == cm->comp_fixed_ref && vrfa == cm->comp_var_ref[0]))
|
||||
pred_context = 4;
|
||||
else if (vrfa == vrfl)
|
||||
pred_context = 3;
|
||||
else
|
||||
pred_context = 1;
|
||||
} else if (l_sg || a_sg) { // single/comp
|
||||
const MV_REFERENCE_FRAME vrfc = l_sg ? vrfa : vrfl;
|
||||
const MV_REFERENCE_FRAME rfs = a_sg ? vrfa : vrfl;
|
||||
if (vrfc == cm->comp_var_ref[1] && rfs != cm->comp_var_ref[1])
|
||||
pred_context = 1;
|
||||
else if (rfs == cm->comp_var_ref[1] && vrfc != cm->comp_var_ref[1])
|
||||
pred_context = 2;
|
||||
else
|
||||
pred_context = 4;
|
||||
} else if (vrfa == vrfl) { // comp/comp
|
||||
pred_context = 4;
|
||||
} else {
|
||||
pred_context = 2;
|
||||
}
|
||||
}
|
||||
} else if (above_in_image || left_in_image) { // one edge available
|
||||
const MODE_INFO *edge_mi = above_in_image ? above_mi : left_mi;
|
||||
|
||||
if (!is_inter_block(edge_mi)) {
|
||||
pred_context = 2;
|
||||
} else {
|
||||
if (has_second_ref(edge_mi))
|
||||
pred_context =
|
||||
4 * (edge_mi->ref_frame[var_ref_idx] != cm->comp_var_ref[1]);
|
||||
else
|
||||
pred_context = 3 * (edge_mi->ref_frame[0] != cm->comp_var_ref[1]);
|
||||
}
|
||||
} else { // no edges available (2)
|
||||
pred_context = 2;
|
||||
}
|
||||
assert(pred_context >= 0 && pred_context < REF_CONTEXTS);
|
||||
|
||||
return pred_context;
|
||||
}
|
||||
|
||||
int vp9_get_pred_context_single_ref_p1(const MACROBLOCKD *xd) {
|
||||
int pred_context;
|
||||
const MODE_INFO *const above_mi = xd->above_mi;
|
||||
const MODE_INFO *const left_mi = xd->left_mi;
|
||||
const int has_above = !!above_mi;
|
||||
const int has_left = !!left_mi;
|
||||
// Note:
|
||||
// The mode info data structure has a one element border above and to the
|
||||
// left of the entries corresponding to real macroblocks.
|
||||
// The prediction flags in these dummy entries are initialized to 0.
|
||||
if (has_above && has_left) { // both edges available
|
||||
const int above_intra = !is_inter_block(above_mi);
|
||||
const int left_intra = !is_inter_block(left_mi);
|
||||
|
||||
if (above_intra && left_intra) { // intra/intra
|
||||
pred_context = 2;
|
||||
} else if (above_intra || left_intra) { // intra/inter or inter/intra
|
||||
const MODE_INFO *edge_mi = above_intra ? left_mi : above_mi;
|
||||
if (!has_second_ref(edge_mi))
|
||||
pred_context = 4 * (edge_mi->ref_frame[0] == LAST_FRAME);
|
||||
else
|
||||
pred_context = 1 + (edge_mi->ref_frame[0] == LAST_FRAME ||
|
||||
edge_mi->ref_frame[1] == LAST_FRAME);
|
||||
} else { // inter/inter
|
||||
const int above_has_second = has_second_ref(above_mi);
|
||||
const int left_has_second = has_second_ref(left_mi);
|
||||
const MV_REFERENCE_FRAME above0 = above_mi->ref_frame[0];
|
||||
const MV_REFERENCE_FRAME above1 = above_mi->ref_frame[1];
|
||||
const MV_REFERENCE_FRAME left0 = left_mi->ref_frame[0];
|
||||
const MV_REFERENCE_FRAME left1 = left_mi->ref_frame[1];
|
||||
|
||||
if (above_has_second && left_has_second) {
|
||||
pred_context = 1 + (above0 == LAST_FRAME || above1 == LAST_FRAME ||
|
||||
left0 == LAST_FRAME || left1 == LAST_FRAME);
|
||||
} else if (above_has_second || left_has_second) {
|
||||
const MV_REFERENCE_FRAME rfs = !above_has_second ? above0 : left0;
|
||||
const MV_REFERENCE_FRAME crf1 = above_has_second ? above0 : left0;
|
||||
const MV_REFERENCE_FRAME crf2 = above_has_second ? above1 : left1;
|
||||
|
||||
if (rfs == LAST_FRAME)
|
||||
pred_context = 3 + (crf1 == LAST_FRAME || crf2 == LAST_FRAME);
|
||||
else
|
||||
pred_context = (crf1 == LAST_FRAME || crf2 == LAST_FRAME);
|
||||
} else {
|
||||
pred_context = 2 * (above0 == LAST_FRAME) + 2 * (left0 == LAST_FRAME);
|
||||
}
|
||||
}
|
||||
} else if (has_above || has_left) { // one edge available
|
||||
const MODE_INFO *edge_mi = has_above ? above_mi : left_mi;
|
||||
if (!is_inter_block(edge_mi)) { // intra
|
||||
pred_context = 2;
|
||||
} else { // inter
|
||||
if (!has_second_ref(edge_mi))
|
||||
pred_context = 4 * (edge_mi->ref_frame[0] == LAST_FRAME);
|
||||
else
|
||||
pred_context = 1 + (edge_mi->ref_frame[0] == LAST_FRAME ||
|
||||
edge_mi->ref_frame[1] == LAST_FRAME);
|
||||
}
|
||||
} else { // no edges available
|
||||
pred_context = 2;
|
||||
}
|
||||
|
||||
assert(pred_context >= 0 && pred_context < REF_CONTEXTS);
|
||||
return pred_context;
|
||||
}
|
||||
|
||||
int vp9_get_pred_context_single_ref_p2(const MACROBLOCKD *xd) {
|
||||
int pred_context;
|
||||
const MODE_INFO *const above_mi = xd->above_mi;
|
||||
const MODE_INFO *const left_mi = xd->left_mi;
|
||||
const int has_above = !!above_mi;
|
||||
const int has_left = !!left_mi;
|
||||
|
||||
// Note:
|
||||
// The mode info data structure has a one element border above and to the
|
||||
// left of the entries corresponding to real macroblocks.
|
||||
// The prediction flags in these dummy entries are initialized to 0.
|
||||
if (has_above && has_left) { // both edges available
|
||||
const int above_intra = !is_inter_block(above_mi);
|
||||
const int left_intra = !is_inter_block(left_mi);
|
||||
|
||||
if (above_intra && left_intra) { // intra/intra
|
||||
pred_context = 2;
|
||||
} else if (above_intra || left_intra) { // intra/inter or inter/intra
|
||||
const MODE_INFO *edge_mi = above_intra ? left_mi : above_mi;
|
||||
if (!has_second_ref(edge_mi)) {
|
||||
if (edge_mi->ref_frame[0] == LAST_FRAME)
|
||||
pred_context = 3;
|
||||
else
|
||||
pred_context = 4 * (edge_mi->ref_frame[0] == GOLDEN_FRAME);
|
||||
} else {
|
||||
pred_context = 1 + 2 * (edge_mi->ref_frame[0] == GOLDEN_FRAME ||
|
||||
edge_mi->ref_frame[1] == GOLDEN_FRAME);
|
||||
}
|
||||
} else { // inter/inter
|
||||
const int above_has_second = has_second_ref(above_mi);
|
||||
const int left_has_second = has_second_ref(left_mi);
|
||||
const MV_REFERENCE_FRAME above0 = above_mi->ref_frame[0];
|
||||
const MV_REFERENCE_FRAME above1 = above_mi->ref_frame[1];
|
||||
const MV_REFERENCE_FRAME left0 = left_mi->ref_frame[0];
|
||||
const MV_REFERENCE_FRAME left1 = left_mi->ref_frame[1];
|
||||
|
||||
if (above_has_second && left_has_second) {
|
||||
if (above0 == left0 && above1 == left1)
|
||||
pred_context =
|
||||
3 * (above0 == GOLDEN_FRAME || above1 == GOLDEN_FRAME ||
|
||||
left0 == GOLDEN_FRAME || left1 == GOLDEN_FRAME);
|
||||
else
|
||||
pred_context = 2;
|
||||
} else if (above_has_second || left_has_second) {
|
||||
const MV_REFERENCE_FRAME rfs = !above_has_second ? above0 : left0;
|
||||
const MV_REFERENCE_FRAME crf1 = above_has_second ? above0 : left0;
|
||||
const MV_REFERENCE_FRAME crf2 = above_has_second ? above1 : left1;
|
||||
|
||||
if (rfs == GOLDEN_FRAME)
|
||||
pred_context = 3 + (crf1 == GOLDEN_FRAME || crf2 == GOLDEN_FRAME);
|
||||
else if (rfs == ALTREF_FRAME)
|
||||
pred_context = crf1 == GOLDEN_FRAME || crf2 == GOLDEN_FRAME;
|
||||
else
|
||||
pred_context = 1 + 2 * (crf1 == GOLDEN_FRAME || crf2 == GOLDEN_FRAME);
|
||||
} else {
|
||||
if (above0 == LAST_FRAME && left0 == LAST_FRAME) {
|
||||
pred_context = 3;
|
||||
} else if (above0 == LAST_FRAME || left0 == LAST_FRAME) {
|
||||
const MV_REFERENCE_FRAME edge0 =
|
||||
(above0 == LAST_FRAME) ? left0 : above0;
|
||||
pred_context = 4 * (edge0 == GOLDEN_FRAME);
|
||||
} else {
|
||||
pred_context =
|
||||
2 * (above0 == GOLDEN_FRAME) + 2 * (left0 == GOLDEN_FRAME);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (has_above || has_left) { // one edge available
|
||||
const MODE_INFO *edge_mi = has_above ? above_mi : left_mi;
|
||||
|
||||
if (!is_inter_block(edge_mi) ||
|
||||
(edge_mi->ref_frame[0] == LAST_FRAME && !has_second_ref(edge_mi)))
|
||||
pred_context = 2;
|
||||
else if (!has_second_ref(edge_mi))
|
||||
pred_context = 4 * (edge_mi->ref_frame[0] == GOLDEN_FRAME);
|
||||
else
|
||||
pred_context = 3 * (edge_mi->ref_frame[0] == GOLDEN_FRAME ||
|
||||
edge_mi->ref_frame[1] == GOLDEN_FRAME);
|
||||
} else { // no edges available (2)
|
||||
pred_context = 2;
|
||||
}
|
||||
assert(pred_context >= 0 && pred_context < REF_CONTEXTS);
|
||||
return pred_context;
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
* 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 VPX_VP9_COMMON_VP9_PRED_COMMON_H_
|
||||
#define VPX_VP9_COMMON_VP9_PRED_COMMON_H_
|
||||
|
||||
#include "vp9/common/vp9_blockd.h"
|
||||
#include "vp9/common/vp9_onyxc_int.h"
|
||||
#include "vpx_dsp/vpx_dsp_common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static INLINE int get_segment_id(const VP9_COMMON *cm,
|
||||
const uint8_t *segment_ids, BLOCK_SIZE bsize,
|
||||
int mi_row, int mi_col) {
|
||||
const int mi_offset = mi_row * cm->mi_cols + mi_col;
|
||||
const int bw = num_8x8_blocks_wide_lookup[bsize];
|
||||
const int bh = num_8x8_blocks_high_lookup[bsize];
|
||||
const int xmis = VPXMIN(cm->mi_cols - mi_col, bw);
|
||||
const int ymis = VPXMIN(cm->mi_rows - mi_row, bh);
|
||||
int x, y, segment_id = MAX_SEGMENTS;
|
||||
|
||||
for (y = 0; y < ymis; ++y)
|
||||
for (x = 0; x < xmis; ++x)
|
||||
segment_id =
|
||||
VPXMIN(segment_id, segment_ids[mi_offset + y * cm->mi_cols + x]);
|
||||
|
||||
assert(segment_id >= 0 && segment_id < MAX_SEGMENTS);
|
||||
return segment_id;
|
||||
}
|
||||
|
||||
static INLINE int vp9_get_pred_context_seg_id(const MACROBLOCKD *xd) {
|
||||
const MODE_INFO *const above_mi = xd->above_mi;
|
||||
const MODE_INFO *const left_mi = xd->left_mi;
|
||||
const int above_sip = (above_mi != NULL) ? above_mi->seg_id_predicted : 0;
|
||||
const int left_sip = (left_mi != NULL) ? left_mi->seg_id_predicted : 0;
|
||||
|
||||
return above_sip + left_sip;
|
||||
}
|
||||
|
||||
static INLINE vpx_prob vp9_get_pred_prob_seg_id(const struct segmentation *seg,
|
||||
const MACROBLOCKD *xd) {
|
||||
return seg->pred_probs[vp9_get_pred_context_seg_id(xd)];
|
||||
}
|
||||
|
||||
static INLINE int vp9_get_skip_context(const MACROBLOCKD *xd) {
|
||||
const MODE_INFO *const above_mi = xd->above_mi;
|
||||
const MODE_INFO *const left_mi = xd->left_mi;
|
||||
const int above_skip = (above_mi != NULL) ? above_mi->skip : 0;
|
||||
const int left_skip = (left_mi != NULL) ? left_mi->skip : 0;
|
||||
return above_skip + left_skip;
|
||||
}
|
||||
|
||||
static INLINE vpx_prob vp9_get_skip_prob(const VP9_COMMON *cm,
|
||||
const MACROBLOCKD *xd) {
|
||||
return cm->fc->skip_probs[vp9_get_skip_context(xd)];
|
||||
}
|
||||
|
||||
// Returns a context number for the given MB prediction signal
|
||||
static INLINE int get_pred_context_switchable_interp(const MACROBLOCKD *xd) {
|
||||
// Note:
|
||||
// The mode info data structure has a one element border above and to the
|
||||
// left of the entries corresponding to real macroblocks.
|
||||
// The prediction flags in these dummy entries are initialized to 0.
|
||||
const MODE_INFO *const left_mi = xd->left_mi;
|
||||
const int left_type = left_mi ? left_mi->interp_filter : SWITCHABLE_FILTERS;
|
||||
const MODE_INFO *const above_mi = xd->above_mi;
|
||||
const int above_type =
|
||||
above_mi ? above_mi->interp_filter : SWITCHABLE_FILTERS;
|
||||
|
||||
if (left_type == above_type)
|
||||
return left_type;
|
||||
else if (left_type == SWITCHABLE_FILTERS)
|
||||
return above_type;
|
||||
else if (above_type == SWITCHABLE_FILTERS)
|
||||
return left_type;
|
||||
else
|
||||
return SWITCHABLE_FILTERS;
|
||||
}
|
||||
|
||||
// The mode info data structure has a one element border above and to the
|
||||
// left of the entries corresponding to real macroblocks.
|
||||
// The prediction flags in these dummy entries are initialized to 0.
|
||||
// 0 - inter/inter, inter/--, --/inter, --/--
|
||||
// 1 - intra/inter, inter/intra
|
||||
// 2 - intra/--, --/intra
|
||||
// 3 - intra/intra
|
||||
static INLINE int get_intra_inter_context(const MACROBLOCKD *xd) {
|
||||
const MODE_INFO *const above_mi = xd->above_mi;
|
||||
const MODE_INFO *const left_mi = xd->left_mi;
|
||||
const int has_above = !!above_mi;
|
||||
const int has_left = !!left_mi;
|
||||
|
||||
if (has_above && has_left) { // both edges available
|
||||
const int above_intra = !is_inter_block(above_mi);
|
||||
const int left_intra = !is_inter_block(left_mi);
|
||||
return left_intra && above_intra ? 3 : left_intra || above_intra;
|
||||
} else if (has_above || has_left) { // one edge available
|
||||
return 2 * !is_inter_block(has_above ? above_mi : left_mi);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static INLINE vpx_prob vp9_get_intra_inter_prob(const VP9_COMMON *cm,
|
||||
const MACROBLOCKD *xd) {
|
||||
return cm->fc->intra_inter_prob[get_intra_inter_context(xd)];
|
||||
}
|
||||
|
||||
int vp9_get_reference_mode_context(const VP9_COMMON *cm, const MACROBLOCKD *xd);
|
||||
|
||||
static INLINE vpx_prob vp9_get_reference_mode_prob(const VP9_COMMON *cm,
|
||||
const MACROBLOCKD *xd) {
|
||||
return cm->fc->comp_inter_prob[vp9_get_reference_mode_context(cm, xd)];
|
||||
}
|
||||
|
||||
int vp9_get_pred_context_comp_ref_p(const VP9_COMMON *cm,
|
||||
const MACROBLOCKD *xd);
|
||||
|
||||
static INLINE vpx_prob vp9_get_pred_prob_comp_ref_p(const VP9_COMMON *cm,
|
||||
const MACROBLOCKD *xd) {
|
||||
const int pred_context = vp9_get_pred_context_comp_ref_p(cm, xd);
|
||||
return cm->fc->comp_ref_prob[pred_context];
|
||||
}
|
||||
|
||||
int vp9_get_pred_context_single_ref_p1(const MACROBLOCKD *xd);
|
||||
|
||||
static INLINE vpx_prob vp9_get_pred_prob_single_ref_p1(const VP9_COMMON *cm,
|
||||
const MACROBLOCKD *xd) {
|
||||
return cm->fc->single_ref_prob[vp9_get_pred_context_single_ref_p1(xd)][0];
|
||||
}
|
||||
|
||||
int vp9_get_pred_context_single_ref_p2(const MACROBLOCKD *xd);
|
||||
|
||||
static INLINE vpx_prob vp9_get_pred_prob_single_ref_p2(const VP9_COMMON *cm,
|
||||
const MACROBLOCKD *xd) {
|
||||
return cm->fc->single_ref_prob[vp9_get_pred_context_single_ref_p2(xd)][1];
|
||||
}
|
||||
|
||||
int vp9_compound_reference_allowed(const VP9_COMMON *cm);
|
||||
|
||||
void vp9_setup_compound_reference_mode(VP9_COMMON *cm);
|
||||
|
||||
// Returns a context number for the given MB prediction signal
|
||||
// The mode info data structure has a one element border above and to the
|
||||
// left of the entries corresponding to real blocks.
|
||||
// The prediction flags in these dummy entries are initialized to 0.
|
||||
static INLINE int get_tx_size_context(const MACROBLOCKD *xd) {
|
||||
const int max_tx_size = max_txsize_lookup[xd->mi[0]->sb_type];
|
||||
const MODE_INFO *const above_mi = xd->above_mi;
|
||||
const MODE_INFO *const left_mi = xd->left_mi;
|
||||
const int has_above = !!above_mi;
|
||||
const int has_left = !!left_mi;
|
||||
int above_ctx =
|
||||
(has_above && !above_mi->skip) ? (int)above_mi->tx_size : max_tx_size;
|
||||
int left_ctx =
|
||||
(has_left && !left_mi->skip) ? (int)left_mi->tx_size : max_tx_size;
|
||||
if (!has_left) left_ctx = above_ctx;
|
||||
|
||||
if (!has_above) above_ctx = left_ctx;
|
||||
|
||||
return (above_ctx + left_ctx) > max_tx_size;
|
||||
}
|
||||
|
||||
static INLINE const vpx_prob *get_tx_probs(TX_SIZE max_tx_size, int ctx,
|
||||
const struct tx_probs *tx_probs) {
|
||||
switch (max_tx_size) {
|
||||
case TX_8X8: return tx_probs->p8x8[ctx];
|
||||
case TX_16X16: return tx_probs->p16x16[ctx];
|
||||
case TX_32X32: return tx_probs->p32x32[ctx];
|
||||
default: assert(0 && "Invalid max_tx_size."); return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static INLINE unsigned int *get_tx_counts(TX_SIZE max_tx_size, int ctx,
|
||||
struct tx_counts *tx_counts) {
|
||||
switch (max_tx_size) {
|
||||
case TX_8X8: return tx_counts->p8x8[ctx];
|
||||
case TX_16X16: return tx_counts->p16x16[ctx];
|
||||
case TX_32X32: return tx_counts->p32x32[ctx];
|
||||
default: assert(0 && "Invalid max_tx_size."); return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_COMMON_VP9_PRED_COMMON_H_
|
||||
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* 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/common/vp9_common.h"
|
||||
#include "vp9/common/vp9_quant_common.h"
|
||||
#include "vp9/common/vp9_seg_common.h"
|
||||
|
||||
static const int16_t dc_qlookup[QINDEX_RANGE] = {
|
||||
4, 8, 8, 9, 10, 11, 12, 12, 13, 14, 15, 16, 17, 18,
|
||||
19, 19, 20, 21, 22, 23, 24, 25, 26, 26, 27, 28, 29, 30,
|
||||
31, 32, 32, 33, 34, 35, 36, 37, 38, 38, 39, 40, 41, 42,
|
||||
43, 43, 44, 45, 46, 47, 48, 48, 49, 50, 51, 52, 53, 53,
|
||||
54, 55, 56, 57, 57, 58, 59, 60, 61, 62, 62, 63, 64, 65,
|
||||
66, 66, 67, 68, 69, 70, 70, 71, 72, 73, 74, 74, 75, 76,
|
||||
77, 78, 78, 79, 80, 81, 81, 82, 83, 84, 85, 85, 87, 88,
|
||||
90, 92, 93, 95, 96, 98, 99, 101, 102, 104, 105, 107, 108, 110,
|
||||
111, 113, 114, 116, 117, 118, 120, 121, 123, 125, 127, 129, 131, 134,
|
||||
136, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158, 161, 164,
|
||||
166, 169, 172, 174, 177, 180, 182, 185, 187, 190, 192, 195, 199, 202,
|
||||
205, 208, 211, 214, 217, 220, 223, 226, 230, 233, 237, 240, 243, 247,
|
||||
250, 253, 257, 261, 265, 269, 272, 276, 280, 284, 288, 292, 296, 300,
|
||||
304, 309, 313, 317, 322, 326, 330, 335, 340, 344, 349, 354, 359, 364,
|
||||
369, 374, 379, 384, 389, 395, 400, 406, 411, 417, 423, 429, 435, 441,
|
||||
447, 454, 461, 467, 475, 482, 489, 497, 505, 513, 522, 530, 539, 549,
|
||||
559, 569, 579, 590, 602, 614, 626, 640, 654, 668, 684, 700, 717, 736,
|
||||
755, 775, 796, 819, 843, 869, 896, 925, 955, 988, 1022, 1058, 1098, 1139,
|
||||
1184, 1232, 1282, 1336,
|
||||
};
|
||||
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
static const int16_t dc_qlookup_10[QINDEX_RANGE] = {
|
||||
4, 9, 10, 13, 15, 17, 20, 22, 25, 28, 31, 34, 37,
|
||||
40, 43, 47, 50, 53, 57, 60, 64, 68, 71, 75, 78, 82,
|
||||
86, 90, 93, 97, 101, 105, 109, 113, 116, 120, 124, 128, 132,
|
||||
136, 140, 143, 147, 151, 155, 159, 163, 166, 170, 174, 178, 182,
|
||||
185, 189, 193, 197, 200, 204, 208, 212, 215, 219, 223, 226, 230,
|
||||
233, 237, 241, 244, 248, 251, 255, 259, 262, 266, 269, 273, 276,
|
||||
280, 283, 287, 290, 293, 297, 300, 304, 307, 310, 314, 317, 321,
|
||||
324, 327, 331, 334, 337, 343, 350, 356, 362, 369, 375, 381, 387,
|
||||
394, 400, 406, 412, 418, 424, 430, 436, 442, 448, 454, 460, 466,
|
||||
472, 478, 484, 490, 499, 507, 516, 525, 533, 542, 550, 559, 567,
|
||||
576, 584, 592, 601, 609, 617, 625, 634, 644, 655, 666, 676, 687,
|
||||
698, 708, 718, 729, 739, 749, 759, 770, 782, 795, 807, 819, 831,
|
||||
844, 856, 868, 880, 891, 906, 920, 933, 947, 961, 975, 988, 1001,
|
||||
1015, 1030, 1045, 1061, 1076, 1090, 1105, 1120, 1137, 1153, 1170, 1186, 1202,
|
||||
1218, 1236, 1253, 1271, 1288, 1306, 1323, 1342, 1361, 1379, 1398, 1416, 1436,
|
||||
1456, 1476, 1496, 1516, 1537, 1559, 1580, 1601, 1624, 1647, 1670, 1692, 1717,
|
||||
1741, 1766, 1791, 1817, 1844, 1871, 1900, 1929, 1958, 1990, 2021, 2054, 2088,
|
||||
2123, 2159, 2197, 2236, 2276, 2319, 2363, 2410, 2458, 2508, 2561, 2616, 2675,
|
||||
2737, 2802, 2871, 2944, 3020, 3102, 3188, 3280, 3375, 3478, 3586, 3702, 3823,
|
||||
3953, 4089, 4236, 4394, 4559, 4737, 4929, 5130, 5347,
|
||||
};
|
||||
|
||||
static const int16_t dc_qlookup_12[QINDEX_RANGE] = {
|
||||
4, 12, 18, 25, 33, 41, 50, 60, 70, 80, 91,
|
||||
103, 115, 127, 140, 153, 166, 180, 194, 208, 222, 237,
|
||||
251, 266, 281, 296, 312, 327, 343, 358, 374, 390, 405,
|
||||
421, 437, 453, 469, 484, 500, 516, 532, 548, 564, 580,
|
||||
596, 611, 627, 643, 659, 674, 690, 706, 721, 737, 752,
|
||||
768, 783, 798, 814, 829, 844, 859, 874, 889, 904, 919,
|
||||
934, 949, 964, 978, 993, 1008, 1022, 1037, 1051, 1065, 1080,
|
||||
1094, 1108, 1122, 1136, 1151, 1165, 1179, 1192, 1206, 1220, 1234,
|
||||
1248, 1261, 1275, 1288, 1302, 1315, 1329, 1342, 1368, 1393, 1419,
|
||||
1444, 1469, 1494, 1519, 1544, 1569, 1594, 1618, 1643, 1668, 1692,
|
||||
1717, 1741, 1765, 1789, 1814, 1838, 1862, 1885, 1909, 1933, 1957,
|
||||
1992, 2027, 2061, 2096, 2130, 2165, 2199, 2233, 2267, 2300, 2334,
|
||||
2367, 2400, 2434, 2467, 2499, 2532, 2575, 2618, 2661, 2704, 2746,
|
||||
2788, 2830, 2872, 2913, 2954, 2995, 3036, 3076, 3127, 3177, 3226,
|
||||
3275, 3324, 3373, 3421, 3469, 3517, 3565, 3621, 3677, 3733, 3788,
|
||||
3843, 3897, 3951, 4005, 4058, 4119, 4181, 4241, 4301, 4361, 4420,
|
||||
4479, 4546, 4612, 4677, 4742, 4807, 4871, 4942, 5013, 5083, 5153,
|
||||
5222, 5291, 5367, 5442, 5517, 5591, 5665, 5745, 5825, 5905, 5984,
|
||||
6063, 6149, 6234, 6319, 6404, 6495, 6587, 6678, 6769, 6867, 6966,
|
||||
7064, 7163, 7269, 7376, 7483, 7599, 7715, 7832, 7958, 8085, 8214,
|
||||
8352, 8492, 8635, 8788, 8945, 9104, 9275, 9450, 9639, 9832, 10031,
|
||||
10245, 10465, 10702, 10946, 11210, 11482, 11776, 12081, 12409, 12750, 13118,
|
||||
13501, 13913, 14343, 14807, 15290, 15812, 16356, 16943, 17575, 18237, 18949,
|
||||
19718, 20521, 21387,
|
||||
};
|
||||
#endif
|
||||
|
||||
static const int16_t ac_qlookup[QINDEX_RANGE] = {
|
||||
4, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
|
||||
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
|
||||
33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45,
|
||||
46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
|
||||
59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
|
||||
72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
|
||||
85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97,
|
||||
98, 99, 100, 101, 102, 104, 106, 108, 110, 112, 114, 116, 118,
|
||||
120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 142, 144,
|
||||
146, 148, 150, 152, 155, 158, 161, 164, 167, 170, 173, 176, 179,
|
||||
182, 185, 188, 191, 194, 197, 200, 203, 207, 211, 215, 219, 223,
|
||||
227, 231, 235, 239, 243, 247, 251, 255, 260, 265, 270, 275, 280,
|
||||
285, 290, 295, 300, 305, 311, 317, 323, 329, 335, 341, 347, 353,
|
||||
359, 366, 373, 380, 387, 394, 401, 408, 416, 424, 432, 440, 448,
|
||||
456, 465, 474, 483, 492, 501, 510, 520, 530, 540, 550, 560, 571,
|
||||
582, 593, 604, 615, 627, 639, 651, 663, 676, 689, 702, 715, 729,
|
||||
743, 757, 771, 786, 801, 816, 832, 848, 864, 881, 898, 915, 933,
|
||||
951, 969, 988, 1007, 1026, 1046, 1066, 1087, 1108, 1129, 1151, 1173, 1196,
|
||||
1219, 1243, 1267, 1292, 1317, 1343, 1369, 1396, 1423, 1451, 1479, 1508, 1537,
|
||||
1567, 1597, 1628, 1660, 1692, 1725, 1759, 1793, 1828,
|
||||
};
|
||||
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
static const int16_t ac_qlookup_10[QINDEX_RANGE] = {
|
||||
4, 9, 11, 13, 16, 18, 21, 24, 27, 30, 33, 37, 40,
|
||||
44, 48, 51, 55, 59, 63, 67, 71, 75, 79, 83, 88, 92,
|
||||
96, 100, 105, 109, 114, 118, 122, 127, 131, 136, 140, 145, 149,
|
||||
154, 158, 163, 168, 172, 177, 181, 186, 190, 195, 199, 204, 208,
|
||||
213, 217, 222, 226, 231, 235, 240, 244, 249, 253, 258, 262, 267,
|
||||
271, 275, 280, 284, 289, 293, 297, 302, 306, 311, 315, 319, 324,
|
||||
328, 332, 337, 341, 345, 349, 354, 358, 362, 367, 371, 375, 379,
|
||||
384, 388, 392, 396, 401, 409, 417, 425, 433, 441, 449, 458, 466,
|
||||
474, 482, 490, 498, 506, 514, 523, 531, 539, 547, 555, 563, 571,
|
||||
579, 588, 596, 604, 616, 628, 640, 652, 664, 676, 688, 700, 713,
|
||||
725, 737, 749, 761, 773, 785, 797, 809, 825, 841, 857, 873, 889,
|
||||
905, 922, 938, 954, 970, 986, 1002, 1018, 1038, 1058, 1078, 1098, 1118,
|
||||
1138, 1158, 1178, 1198, 1218, 1242, 1266, 1290, 1314, 1338, 1362, 1386, 1411,
|
||||
1435, 1463, 1491, 1519, 1547, 1575, 1603, 1631, 1663, 1695, 1727, 1759, 1791,
|
||||
1823, 1859, 1895, 1931, 1967, 2003, 2039, 2079, 2119, 2159, 2199, 2239, 2283,
|
||||
2327, 2371, 2415, 2459, 2507, 2555, 2603, 2651, 2703, 2755, 2807, 2859, 2915,
|
||||
2971, 3027, 3083, 3143, 3203, 3263, 3327, 3391, 3455, 3523, 3591, 3659, 3731,
|
||||
3803, 3876, 3952, 4028, 4104, 4184, 4264, 4348, 4432, 4516, 4604, 4692, 4784,
|
||||
4876, 4972, 5068, 5168, 5268, 5372, 5476, 5584, 5692, 5804, 5916, 6032, 6148,
|
||||
6268, 6388, 6512, 6640, 6768, 6900, 7036, 7172, 7312,
|
||||
};
|
||||
|
||||
static const int16_t ac_qlookup_12[QINDEX_RANGE] = {
|
||||
4, 13, 19, 27, 35, 44, 54, 64, 75, 87, 99,
|
||||
112, 126, 139, 154, 168, 183, 199, 214, 230, 247, 263,
|
||||
280, 297, 314, 331, 349, 366, 384, 402, 420, 438, 456,
|
||||
475, 493, 511, 530, 548, 567, 586, 604, 623, 642, 660,
|
||||
679, 698, 716, 735, 753, 772, 791, 809, 828, 846, 865,
|
||||
884, 902, 920, 939, 957, 976, 994, 1012, 1030, 1049, 1067,
|
||||
1085, 1103, 1121, 1139, 1157, 1175, 1193, 1211, 1229, 1246, 1264,
|
||||
1282, 1299, 1317, 1335, 1352, 1370, 1387, 1405, 1422, 1440, 1457,
|
||||
1474, 1491, 1509, 1526, 1543, 1560, 1577, 1595, 1627, 1660, 1693,
|
||||
1725, 1758, 1791, 1824, 1856, 1889, 1922, 1954, 1987, 2020, 2052,
|
||||
2085, 2118, 2150, 2183, 2216, 2248, 2281, 2313, 2346, 2378, 2411,
|
||||
2459, 2508, 2556, 2605, 2653, 2701, 2750, 2798, 2847, 2895, 2943,
|
||||
2992, 3040, 3088, 3137, 3185, 3234, 3298, 3362, 3426, 3491, 3555,
|
||||
3619, 3684, 3748, 3812, 3876, 3941, 4005, 4069, 4149, 4230, 4310,
|
||||
4390, 4470, 4550, 4631, 4711, 4791, 4871, 4967, 5064, 5160, 5256,
|
||||
5352, 5448, 5544, 5641, 5737, 5849, 5961, 6073, 6185, 6297, 6410,
|
||||
6522, 6650, 6778, 6906, 7034, 7162, 7290, 7435, 7579, 7723, 7867,
|
||||
8011, 8155, 8315, 8475, 8635, 8795, 8956, 9132, 9308, 9484, 9660,
|
||||
9836, 10028, 10220, 10412, 10604, 10812, 11020, 11228, 11437, 11661, 11885,
|
||||
12109, 12333, 12573, 12813, 13053, 13309, 13565, 13821, 14093, 14365, 14637,
|
||||
14925, 15213, 15502, 15806, 16110, 16414, 16734, 17054, 17390, 17726, 18062,
|
||||
18414, 18766, 19134, 19502, 19886, 20270, 20670, 21070, 21486, 21902, 22334,
|
||||
22766, 23214, 23662, 24126, 24590, 25070, 25551, 26047, 26559, 27071, 27599,
|
||||
28143, 28687, 29247,
|
||||
};
|
||||
#endif
|
||||
|
||||
int16_t vp9_dc_quant(int qindex, int delta, vpx_bit_depth_t bit_depth) {
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
switch (bit_depth) {
|
||||
case VPX_BITS_8: return dc_qlookup[clamp(qindex + delta, 0, MAXQ)];
|
||||
case VPX_BITS_10: return dc_qlookup_10[clamp(qindex + delta, 0, MAXQ)];
|
||||
case VPX_BITS_12: return dc_qlookup_12[clamp(qindex + delta, 0, MAXQ)];
|
||||
default:
|
||||
assert(0 && "bit_depth should be VPX_BITS_8, VPX_BITS_10 or VPX_BITS_12");
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
(void)bit_depth;
|
||||
return dc_qlookup[clamp(qindex + delta, 0, MAXQ)];
|
||||
#endif
|
||||
}
|
||||
|
||||
int16_t vp9_ac_quant(int qindex, int delta, vpx_bit_depth_t bit_depth) {
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
switch (bit_depth) {
|
||||
case VPX_BITS_8: return ac_qlookup[clamp(qindex + delta, 0, MAXQ)];
|
||||
case VPX_BITS_10: return ac_qlookup_10[clamp(qindex + delta, 0, MAXQ)];
|
||||
case VPX_BITS_12: return ac_qlookup_12[clamp(qindex + delta, 0, MAXQ)];
|
||||
default:
|
||||
assert(0 && "bit_depth should be VPX_BITS_8, VPX_BITS_10 or VPX_BITS_12");
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
(void)bit_depth;
|
||||
return ac_qlookup[clamp(qindex + delta, 0, MAXQ)];
|
||||
#endif
|
||||
}
|
||||
|
||||
int vp9_get_qindex(const struct segmentation *seg, int segment_id,
|
||||
int base_qindex) {
|
||||
if (segfeature_active(seg, segment_id, SEG_LVL_ALT_Q)) {
|
||||
const int data = get_segdata(seg, segment_id, SEG_LVL_ALT_Q);
|
||||
const int seg_qindex =
|
||||
seg->abs_delta == SEGMENT_ABSDATA ? data : base_qindex + data;
|
||||
return clamp(seg_qindex, 0, MAXQ);
|
||||
} else {
|
||||
return base_qindex;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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 VPX_VP9_COMMON_VP9_QUANT_COMMON_H_
|
||||
#define VPX_VP9_COMMON_VP9_QUANT_COMMON_H_
|
||||
|
||||
#include "vpx/vpx_codec.h"
|
||||
#include "vp9/common/vp9_seg_common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define MINQ 0
|
||||
#define MAXQ 255
|
||||
#define QINDEX_RANGE (MAXQ - MINQ + 1)
|
||||
#define QINDEX_BITS 8
|
||||
|
||||
int16_t vp9_dc_quant(int qindex, int delta, vpx_bit_depth_t bit_depth);
|
||||
int16_t vp9_ac_quant(int qindex, int delta, vpx_bit_depth_t bit_depth);
|
||||
|
||||
int vp9_get_qindex(const struct segmentation *seg, int segment_id,
|
||||
int base_qindex);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_COMMON_VP9_QUANT_COMMON_H_
|
||||
@@ -0,0 +1,288 @@
|
||||
/*
|
||||
* 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 "./vpx_scale_rtcd.h"
|
||||
#include "./vpx_config.h"
|
||||
|
||||
#include "vpx/vpx_integer.h"
|
||||
|
||||
#include "vp9/common/vp9_blockd.h"
|
||||
#include "vp9/common/vp9_reconinter.h"
|
||||
#include "vp9/common/vp9_reconintra.h"
|
||||
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
void vp9_highbd_build_inter_predictor(
|
||||
const uint16_t *src, int src_stride, uint16_t *dst, int dst_stride,
|
||||
const MV *src_mv, const struct scale_factors *sf, int w, int h, int ref,
|
||||
const InterpKernel *kernel, enum mv_precision precision, int x, int y,
|
||||
int bd) {
|
||||
const int is_q4 = precision == MV_PRECISION_Q4;
|
||||
const MV mv_q4 = { is_q4 ? src_mv->row : src_mv->row * 2,
|
||||
is_q4 ? src_mv->col : src_mv->col * 2 };
|
||||
MV32 mv = vp9_scale_mv(&mv_q4, x, y, sf);
|
||||
const int subpel_x = mv.col & SUBPEL_MASK;
|
||||
const int subpel_y = mv.row & SUBPEL_MASK;
|
||||
|
||||
src += (mv.row >> SUBPEL_BITS) * src_stride + (mv.col >> SUBPEL_BITS);
|
||||
|
||||
highbd_inter_predictor(src, src_stride, dst, dst_stride, subpel_x, subpel_y,
|
||||
sf, w, h, ref, kernel, sf->x_step_q4, sf->y_step_q4,
|
||||
bd);
|
||||
}
|
||||
#endif // CONFIG_VP9_HIGHBITDEPTH
|
||||
|
||||
void vp9_build_inter_predictor(const uint8_t *src, int src_stride, uint8_t *dst,
|
||||
int dst_stride, const MV *src_mv,
|
||||
const struct scale_factors *sf, int w, int h,
|
||||
int ref, const InterpKernel *kernel,
|
||||
enum mv_precision precision, int x, int y) {
|
||||
const int is_q4 = precision == MV_PRECISION_Q4;
|
||||
const MV mv_q4 = { is_q4 ? src_mv->row : src_mv->row * 2,
|
||||
is_q4 ? src_mv->col : src_mv->col * 2 };
|
||||
MV32 mv = vp9_scale_mv(&mv_q4, x, y, sf);
|
||||
const int subpel_x = mv.col & SUBPEL_MASK;
|
||||
const int subpel_y = mv.row & SUBPEL_MASK;
|
||||
|
||||
src += (mv.row >> SUBPEL_BITS) * src_stride + (mv.col >> SUBPEL_BITS);
|
||||
|
||||
inter_predictor(src, src_stride, dst, dst_stride, subpel_x, subpel_y, sf, w,
|
||||
h, ref, kernel, sf->x_step_q4, sf->y_step_q4);
|
||||
}
|
||||
|
||||
static INLINE int round_mv_comp_q4(int value) {
|
||||
return (value < 0 ? value - 2 : value + 2) / 4;
|
||||
}
|
||||
|
||||
static MV mi_mv_pred_q4(const MODE_INFO *mi, int idx) {
|
||||
MV res = { round_mv_comp_q4(mi->bmi[0].as_mv[idx].as_mv.row +
|
||||
mi->bmi[1].as_mv[idx].as_mv.row +
|
||||
mi->bmi[2].as_mv[idx].as_mv.row +
|
||||
mi->bmi[3].as_mv[idx].as_mv.row),
|
||||
round_mv_comp_q4(mi->bmi[0].as_mv[idx].as_mv.col +
|
||||
mi->bmi[1].as_mv[idx].as_mv.col +
|
||||
mi->bmi[2].as_mv[idx].as_mv.col +
|
||||
mi->bmi[3].as_mv[idx].as_mv.col) };
|
||||
return res;
|
||||
}
|
||||
|
||||
static INLINE int round_mv_comp_q2(int value) {
|
||||
return (value < 0 ? value - 1 : value + 1) / 2;
|
||||
}
|
||||
|
||||
static MV mi_mv_pred_q2(const MODE_INFO *mi, int idx, int block0, int block1) {
|
||||
MV res = { round_mv_comp_q2(mi->bmi[block0].as_mv[idx].as_mv.row +
|
||||
mi->bmi[block1].as_mv[idx].as_mv.row),
|
||||
round_mv_comp_q2(mi->bmi[block0].as_mv[idx].as_mv.col +
|
||||
mi->bmi[block1].as_mv[idx].as_mv.col) };
|
||||
return res;
|
||||
}
|
||||
|
||||
// TODO(jkoleszar): yet another mv clamping function :-(
|
||||
MV clamp_mv_to_umv_border_sb(const MACROBLOCKD *xd, const MV *src_mv, int bw,
|
||||
int bh, int ss_x, int ss_y) {
|
||||
// If the MV points so far into the UMV border that no visible pixels
|
||||
// are used for reconstruction, the subpel part of the MV can be
|
||||
// discarded and the MV limited to 16 pixels with equivalent results.
|
||||
const int spel_left = (VP9_INTERP_EXTEND + bw) << SUBPEL_BITS;
|
||||
const int spel_right = spel_left - SUBPEL_SHIFTS;
|
||||
const int spel_top = (VP9_INTERP_EXTEND + bh) << SUBPEL_BITS;
|
||||
const int spel_bottom = spel_top - SUBPEL_SHIFTS;
|
||||
MV clamped_mv = { (short)(src_mv->row * (1 << (1 - ss_y))),
|
||||
(short)(src_mv->col * (1 << (1 - ss_x))) };
|
||||
assert(ss_x <= 1);
|
||||
assert(ss_y <= 1);
|
||||
|
||||
clamp_mv(&clamped_mv, xd->mb_to_left_edge * (1 << (1 - ss_x)) - spel_left,
|
||||
xd->mb_to_right_edge * (1 << (1 - ss_x)) + spel_right,
|
||||
xd->mb_to_top_edge * (1 << (1 - ss_y)) - spel_top,
|
||||
xd->mb_to_bottom_edge * (1 << (1 - ss_y)) + spel_bottom);
|
||||
|
||||
return clamped_mv;
|
||||
}
|
||||
|
||||
MV average_split_mvs(const struct macroblockd_plane *pd, const MODE_INFO *mi,
|
||||
int ref, int block) {
|
||||
const int ss_idx = ((pd->subsampling_x > 0) << 1) | (pd->subsampling_y > 0);
|
||||
MV res = { 0, 0 };
|
||||
switch (ss_idx) {
|
||||
case 0: res = mi->bmi[block].as_mv[ref].as_mv; break;
|
||||
case 1: res = mi_mv_pred_q2(mi, ref, block, block + 2); break;
|
||||
case 2: res = mi_mv_pred_q2(mi, ref, block, block + 1); break;
|
||||
case 3: res = mi_mv_pred_q4(mi, ref); break;
|
||||
default: assert(ss_idx <= 3 && ss_idx >= 0);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static void build_inter_predictors(MACROBLOCKD *xd, int plane, int block,
|
||||
int bw, int bh, int x, int y, int w, int h,
|
||||
int mi_x, int mi_y) {
|
||||
struct macroblockd_plane *const pd = &xd->plane[plane];
|
||||
const MODE_INFO *mi = xd->mi[0];
|
||||
const int is_compound = has_second_ref(mi);
|
||||
const InterpKernel *kernel = vp9_filter_kernels[mi->interp_filter];
|
||||
int ref;
|
||||
|
||||
for (ref = 0; ref < 1 + is_compound; ++ref) {
|
||||
const struct scale_factors *const sf = &xd->block_refs[ref]->sf;
|
||||
struct buf_2d *const pre_buf = &pd->pre[ref];
|
||||
struct buf_2d *const dst_buf = &pd->dst;
|
||||
uint8_t *const dst = dst_buf->buf + (int64_t)dst_buf->stride * y + x;
|
||||
const MV mv = mi->sb_type < BLOCK_8X8
|
||||
? average_split_mvs(pd, mi, ref, block)
|
||||
: mi->mv[ref].as_mv;
|
||||
|
||||
// TODO(jkoleszar): This clamping is done in the incorrect place for the
|
||||
// scaling case. It needs to be done on the scaled MV, not the pre-scaling
|
||||
// MV. Note however that it performs the subsampling aware scaling so
|
||||
// that the result is always q4.
|
||||
// mv_precision precision is MV_PRECISION_Q4.
|
||||
const MV mv_q4 = clamp_mv_to_umv_border_sb(
|
||||
xd, &mv, bw, bh, pd->subsampling_x, pd->subsampling_y);
|
||||
|
||||
uint8_t *pre;
|
||||
MV32 scaled_mv;
|
||||
int xs, ys, subpel_x, subpel_y;
|
||||
const int is_scaled = vp9_is_scaled(sf);
|
||||
|
||||
if (is_scaled) {
|
||||
// Co-ordinate of containing block to pixel precision.
|
||||
const int x_start = (-xd->mb_to_left_edge >> (3 + pd->subsampling_x));
|
||||
const int y_start = (-xd->mb_to_top_edge >> (3 + pd->subsampling_y));
|
||||
#if 0 // CONFIG_BETTER_HW_COMPATIBILITY
|
||||
assert(xd->mi[0]->sb_type != BLOCK_4X8 &&
|
||||
xd->mi[0]->sb_type != BLOCK_8X4);
|
||||
assert(mv_q4.row == mv.row * (1 << (1 - pd->subsampling_y)) &&
|
||||
mv_q4.col == mv.col * (1 << (1 - pd->subsampling_x)));
|
||||
#endif
|
||||
if (plane == 0)
|
||||
pre_buf->buf = xd->block_refs[ref]->buf->y_buffer;
|
||||
else if (plane == 1)
|
||||
pre_buf->buf = xd->block_refs[ref]->buf->u_buffer;
|
||||
else
|
||||
pre_buf->buf = xd->block_refs[ref]->buf->v_buffer;
|
||||
|
||||
pre_buf->buf +=
|
||||
scaled_buffer_offset(x_start + x, y_start + y, pre_buf->stride, sf);
|
||||
pre = pre_buf->buf;
|
||||
scaled_mv = vp9_scale_mv(&mv_q4, mi_x + x, mi_y + y, sf);
|
||||
xs = sf->x_step_q4;
|
||||
ys = sf->y_step_q4;
|
||||
} else {
|
||||
pre = pre_buf->buf + ((int64_t)y * pre_buf->stride + x);
|
||||
scaled_mv.row = mv_q4.row;
|
||||
scaled_mv.col = mv_q4.col;
|
||||
xs = ys = 16;
|
||||
}
|
||||
subpel_x = scaled_mv.col & SUBPEL_MASK;
|
||||
subpel_y = scaled_mv.row & SUBPEL_MASK;
|
||||
pre += (scaled_mv.row >> SUBPEL_BITS) * pre_buf->stride +
|
||||
(scaled_mv.col >> SUBPEL_BITS);
|
||||
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) {
|
||||
highbd_inter_predictor(CONVERT_TO_SHORTPTR(pre), pre_buf->stride,
|
||||
CONVERT_TO_SHORTPTR(dst), dst_buf->stride,
|
||||
subpel_x, subpel_y, sf, w, h, ref, kernel, xs, ys,
|
||||
xd->bd);
|
||||
} else {
|
||||
inter_predictor(pre, pre_buf->stride, dst, dst_buf->stride, subpel_x,
|
||||
subpel_y, sf, w, h, ref, kernel, xs, ys);
|
||||
}
|
||||
#else
|
||||
inter_predictor(pre, pre_buf->stride, dst, dst_buf->stride, subpel_x,
|
||||
subpel_y, sf, w, h, ref, kernel, xs, ys);
|
||||
#endif // CONFIG_VP9_HIGHBITDEPTH
|
||||
}
|
||||
}
|
||||
|
||||
static void build_inter_predictors_for_planes(MACROBLOCKD *xd, BLOCK_SIZE bsize,
|
||||
int mi_row, int mi_col,
|
||||
int plane_from, int plane_to) {
|
||||
int plane;
|
||||
const int mi_x = mi_col * MI_SIZE;
|
||||
const int mi_y = mi_row * MI_SIZE;
|
||||
for (plane = plane_from; plane <= plane_to; ++plane) {
|
||||
const BLOCK_SIZE plane_bsize =
|
||||
get_plane_block_size(bsize, &xd->plane[plane]);
|
||||
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 int bw = 4 * num_4x4_w;
|
||||
const int bh = 4 * num_4x4_h;
|
||||
|
||||
if (xd->mi[0]->sb_type < BLOCK_8X8) {
|
||||
int i = 0, x, y;
|
||||
assert(bsize == BLOCK_8X8);
|
||||
for (y = 0; y < num_4x4_h; ++y)
|
||||
for (x = 0; x < num_4x4_w; ++x)
|
||||
build_inter_predictors(xd, plane, i++, bw, bh, 4 * x, 4 * y, 4, 4,
|
||||
mi_x, mi_y);
|
||||
} else {
|
||||
build_inter_predictors(xd, plane, 0, bw, bh, 0, 0, bw, bh, mi_x, mi_y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_build_inter_predictors_sby(MACROBLOCKD *xd, int mi_row, int mi_col,
|
||||
BLOCK_SIZE bsize) {
|
||||
build_inter_predictors_for_planes(xd, bsize, mi_row, mi_col, 0, 0);
|
||||
}
|
||||
|
||||
void vp9_build_inter_predictors_sbp(MACROBLOCKD *xd, int mi_row, int mi_col,
|
||||
BLOCK_SIZE bsize, int plane) {
|
||||
build_inter_predictors_for_planes(xd, bsize, mi_row, mi_col, plane, plane);
|
||||
}
|
||||
|
||||
void vp9_build_inter_predictors_sbuv(MACROBLOCKD *xd, int mi_row, int mi_col,
|
||||
BLOCK_SIZE bsize) {
|
||||
build_inter_predictors_for_planes(xd, bsize, mi_row, mi_col, 1,
|
||||
MAX_MB_PLANE - 1);
|
||||
}
|
||||
|
||||
void vp9_build_inter_predictors_sb(MACROBLOCKD *xd, int mi_row, int mi_col,
|
||||
BLOCK_SIZE bsize) {
|
||||
build_inter_predictors_for_planes(xd, bsize, mi_row, mi_col, 0,
|
||||
MAX_MB_PLANE - 1);
|
||||
}
|
||||
|
||||
void vp9_setup_dst_planes(struct macroblockd_plane planes[MAX_MB_PLANE],
|
||||
const YV12_BUFFER_CONFIG *src, int mi_row,
|
||||
int mi_col) {
|
||||
uint8_t *const buffers[MAX_MB_PLANE] = { src->y_buffer, src->u_buffer,
|
||||
src->v_buffer };
|
||||
const int strides[MAX_MB_PLANE] = { src->y_stride, src->uv_stride,
|
||||
src->uv_stride };
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_MB_PLANE; ++i) {
|
||||
struct macroblockd_plane *const pd = &planes[i];
|
||||
setup_pred_plane(&pd->dst, buffers[i], strides[i], mi_row, mi_col, NULL,
|
||||
pd->subsampling_x, pd->subsampling_y);
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_setup_pre_planes(MACROBLOCKD *xd, int idx,
|
||||
const YV12_BUFFER_CONFIG *src, int mi_row, int mi_col,
|
||||
const struct scale_factors *sf) {
|
||||
if (src != NULL) {
|
||||
int i;
|
||||
uint8_t *const buffers[MAX_MB_PLANE] = { src->y_buffer, src->u_buffer,
|
||||
src->v_buffer };
|
||||
const int strides[MAX_MB_PLANE] = { src->y_stride, src->uv_stride,
|
||||
src->uv_stride };
|
||||
for (i = 0; i < MAX_MB_PLANE; ++i) {
|
||||
struct macroblockd_plane *const pd = &xd->plane[i];
|
||||
setup_pred_plane(&pd->pre[idx], buffers[i], strides[i], mi_row, mi_col,
|
||||
sf, pd->subsampling_x, pd->subsampling_y);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* 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 VPX_VP9_COMMON_VP9_RECONINTER_H_
|
||||
#define VPX_VP9_COMMON_VP9_RECONINTER_H_
|
||||
|
||||
#include "vp9/common/vp9_filter.h"
|
||||
#include "vp9/common/vp9_onyxc_int.h"
|
||||
#include "vpx/vpx_integer.h"
|
||||
#include "vpx_dsp/vpx_filter.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static INLINE void inter_predictor(const uint8_t *src, int src_stride,
|
||||
uint8_t *dst, int dst_stride,
|
||||
const int subpel_x, const int subpel_y,
|
||||
const struct scale_factors *sf, int w, int h,
|
||||
int ref, const InterpKernel *kernel, int xs,
|
||||
int ys) {
|
||||
sf->predict[subpel_x != 0][subpel_y != 0][ref](src, src_stride, dst,
|
||||
dst_stride, kernel, subpel_x,
|
||||
xs, subpel_y, ys, w, h);
|
||||
}
|
||||
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
static INLINE void highbd_inter_predictor(
|
||||
const uint16_t *src, int src_stride, uint16_t *dst, int dst_stride,
|
||||
const int subpel_x, const int subpel_y, const struct scale_factors *sf,
|
||||
int w, int h, int ref, const InterpKernel *kernel, int xs, int ys, int bd) {
|
||||
sf->highbd_predict[subpel_x != 0][subpel_y != 0][ref](
|
||||
src, src_stride, dst, dst_stride, kernel, subpel_x, xs, subpel_y, ys, w,
|
||||
h, bd);
|
||||
}
|
||||
#endif // CONFIG_VP9_HIGHBITDEPTH
|
||||
|
||||
MV average_split_mvs(const struct macroblockd_plane *pd, const MODE_INFO *mi,
|
||||
int ref, int block);
|
||||
|
||||
MV clamp_mv_to_umv_border_sb(const MACROBLOCKD *xd, const MV *src_mv, int bw,
|
||||
int bh, int ss_x, int ss_y);
|
||||
|
||||
void vp9_build_inter_predictors_sby(MACROBLOCKD *xd, int mi_row, int mi_col,
|
||||
BLOCK_SIZE bsize);
|
||||
|
||||
void vp9_build_inter_predictors_sbp(MACROBLOCKD *xd, int mi_row, int mi_col,
|
||||
BLOCK_SIZE bsize, int plane);
|
||||
|
||||
void vp9_build_inter_predictors_sbuv(MACROBLOCKD *xd, int mi_row, int mi_col,
|
||||
BLOCK_SIZE bsize);
|
||||
|
||||
void vp9_build_inter_predictors_sb(MACROBLOCKD *xd, int mi_row, int mi_col,
|
||||
BLOCK_SIZE bsize);
|
||||
|
||||
void vp9_build_inter_predictor(const uint8_t *src, int src_stride, uint8_t *dst,
|
||||
int dst_stride, const MV *src_mv,
|
||||
const struct scale_factors *sf, int w, int h,
|
||||
int ref, const InterpKernel *kernel,
|
||||
enum mv_precision precision, int x, int y);
|
||||
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
void vp9_highbd_build_inter_predictor(
|
||||
const uint16_t *src, int src_stride, uint16_t *dst, int dst_stride,
|
||||
const MV *src_mv, const struct scale_factors *sf, int w, int h, int ref,
|
||||
const InterpKernel *kernel, enum mv_precision precision, int x, int y,
|
||||
int bd);
|
||||
#endif
|
||||
|
||||
static INLINE int64_t scaled_buffer_offset(int x_offset, int y_offset,
|
||||
int stride,
|
||||
const struct scale_factors *sf) {
|
||||
const int x = sf ? sf->scale_value_x(x_offset, sf) : x_offset;
|
||||
const int y = sf ? sf->scale_value_y(y_offset, sf) : y_offset;
|
||||
return (int64_t)y * stride + x;
|
||||
}
|
||||
|
||||
static INLINE void setup_pred_plane(struct buf_2d *dst, uint8_t *src,
|
||||
int stride, int mi_row, int mi_col,
|
||||
const struct scale_factors *scale,
|
||||
int subsampling_x, int subsampling_y) {
|
||||
const int x = (MI_SIZE * mi_col) >> subsampling_x;
|
||||
const int y = (MI_SIZE * mi_row) >> subsampling_y;
|
||||
dst->buf = src + scaled_buffer_offset(x, y, stride, scale);
|
||||
dst->stride = stride;
|
||||
}
|
||||
|
||||
void vp9_setup_dst_planes(struct macroblockd_plane planes[MAX_MB_PLANE],
|
||||
const YV12_BUFFER_CONFIG *src, int mi_row,
|
||||
int mi_col);
|
||||
|
||||
void vp9_setup_pre_planes(MACROBLOCKD *xd, int idx,
|
||||
const YV12_BUFFER_CONFIG *src, int mi_row, int mi_col,
|
||||
const struct scale_factors *sf);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_COMMON_VP9_RECONINTER_H_
|
||||
@@ -0,0 +1,431 @@
|
||||
/*
|
||||
* 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_config.h"
|
||||
#include "./vpx_dsp_rtcd.h"
|
||||
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
#include "vpx_dsp/vpx_dsp_common.h"
|
||||
#endif // CONFIG_VP9_HIGHBITDEPTH
|
||||
#include "vpx_mem/vpx_mem.h"
|
||||
#include "vpx_ports/mem.h"
|
||||
#include "vpx_ports/vpx_once.h"
|
||||
|
||||
#include "vp9/common/vp9_reconintra.h"
|
||||
#include "vp9/common/vp9_onyxc_int.h"
|
||||
|
||||
const TX_TYPE intra_mode_to_tx_type_lookup[INTRA_MODES] = {
|
||||
DCT_DCT, // DC
|
||||
ADST_DCT, // V
|
||||
DCT_ADST, // H
|
||||
DCT_DCT, // D45
|
||||
ADST_ADST, // D135
|
||||
ADST_DCT, // D117
|
||||
DCT_ADST, // D153
|
||||
DCT_ADST, // D207
|
||||
ADST_DCT, // D63
|
||||
ADST_ADST, // TM
|
||||
};
|
||||
|
||||
enum {
|
||||
NEED_LEFT = 1 << 1,
|
||||
NEED_ABOVE = 1 << 2,
|
||||
NEED_ABOVERIGHT = 1 << 3,
|
||||
};
|
||||
|
||||
static const uint8_t extend_modes[INTRA_MODES] = {
|
||||
NEED_ABOVE | NEED_LEFT, // DC
|
||||
NEED_ABOVE, // V
|
||||
NEED_LEFT, // H
|
||||
NEED_ABOVERIGHT, // D45
|
||||
NEED_LEFT | NEED_ABOVE, // D135
|
||||
NEED_LEFT | NEED_ABOVE, // D117
|
||||
NEED_LEFT | NEED_ABOVE, // D153
|
||||
NEED_LEFT, // D207
|
||||
NEED_ABOVERIGHT, // D63
|
||||
NEED_LEFT | NEED_ABOVE, // TM
|
||||
};
|
||||
|
||||
typedef void (*intra_pred_fn)(uint8_t *dst, ptrdiff_t stride,
|
||||
const uint8_t *above, const uint8_t *left);
|
||||
|
||||
static intra_pred_fn pred[INTRA_MODES][TX_SIZES];
|
||||
static intra_pred_fn dc_pred[2][2][TX_SIZES];
|
||||
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
typedef void (*intra_high_pred_fn)(uint16_t *dst, ptrdiff_t stride,
|
||||
const uint16_t *above, const uint16_t *left,
|
||||
int bd);
|
||||
static intra_high_pred_fn pred_high[INTRA_MODES][4];
|
||||
static intra_high_pred_fn dc_pred_high[2][2][4];
|
||||
#endif // CONFIG_VP9_HIGHBITDEPTH
|
||||
|
||||
static void vp9_init_intra_predictors_internal(void) {
|
||||
#define INIT_ALL_SIZES(p, type) \
|
||||
p[TX_4X4] = vpx_##type##_predictor_4x4; \
|
||||
p[TX_8X8] = vpx_##type##_predictor_8x8; \
|
||||
p[TX_16X16] = vpx_##type##_predictor_16x16; \
|
||||
p[TX_32X32] = vpx_##type##_predictor_32x32
|
||||
|
||||
INIT_ALL_SIZES(pred[V_PRED], v);
|
||||
INIT_ALL_SIZES(pred[H_PRED], h);
|
||||
INIT_ALL_SIZES(pred[D207_PRED], d207);
|
||||
INIT_ALL_SIZES(pred[D45_PRED], d45);
|
||||
INIT_ALL_SIZES(pred[D63_PRED], d63);
|
||||
INIT_ALL_SIZES(pred[D117_PRED], d117);
|
||||
INIT_ALL_SIZES(pred[D135_PRED], d135);
|
||||
INIT_ALL_SIZES(pred[D153_PRED], d153);
|
||||
INIT_ALL_SIZES(pred[TM_PRED], tm);
|
||||
|
||||
INIT_ALL_SIZES(dc_pred[0][0], dc_128);
|
||||
INIT_ALL_SIZES(dc_pred[0][1], dc_top);
|
||||
INIT_ALL_SIZES(dc_pred[1][0], dc_left);
|
||||
INIT_ALL_SIZES(dc_pred[1][1], dc);
|
||||
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
INIT_ALL_SIZES(pred_high[V_PRED], highbd_v);
|
||||
INIT_ALL_SIZES(pred_high[H_PRED], highbd_h);
|
||||
INIT_ALL_SIZES(pred_high[D207_PRED], highbd_d207);
|
||||
INIT_ALL_SIZES(pred_high[D45_PRED], highbd_d45);
|
||||
INIT_ALL_SIZES(pred_high[D63_PRED], highbd_d63);
|
||||
INIT_ALL_SIZES(pred_high[D117_PRED], highbd_d117);
|
||||
INIT_ALL_SIZES(pred_high[D135_PRED], highbd_d135);
|
||||
INIT_ALL_SIZES(pred_high[D153_PRED], highbd_d153);
|
||||
INIT_ALL_SIZES(pred_high[TM_PRED], highbd_tm);
|
||||
|
||||
INIT_ALL_SIZES(dc_pred_high[0][0], highbd_dc_128);
|
||||
INIT_ALL_SIZES(dc_pred_high[0][1], highbd_dc_top);
|
||||
INIT_ALL_SIZES(dc_pred_high[1][0], highbd_dc_left);
|
||||
INIT_ALL_SIZES(dc_pred_high[1][1], highbd_dc);
|
||||
#endif // CONFIG_VP9_HIGHBITDEPTH
|
||||
|
||||
#undef intra_pred_allsizes
|
||||
}
|
||||
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
static void build_intra_predictors_high(
|
||||
const MACROBLOCKD *xd, const uint8_t *ref8, int ref_stride, uint8_t *dst8,
|
||||
int dst_stride, PREDICTION_MODE mode, TX_SIZE tx_size, int up_available,
|
||||
int left_available, int right_available, int x, int y, int plane, int bd) {
|
||||
int i;
|
||||
uint16_t *dst = CONVERT_TO_SHORTPTR(dst8);
|
||||
uint16_t *ref = CONVERT_TO_SHORTPTR(ref8);
|
||||
DECLARE_ALIGNED(16, uint16_t, left_col[32]);
|
||||
DECLARE_ALIGNED(16, uint16_t, above_data[64 + 16]);
|
||||
uint16_t *above_row = above_data + 16;
|
||||
const uint16_t *const_above_row = above_row;
|
||||
const int bs = 4 << tx_size;
|
||||
int frame_width, frame_height;
|
||||
int x0, y0;
|
||||
const struct macroblockd_plane *const pd = &xd->plane[plane];
|
||||
const int need_left = extend_modes[mode] & NEED_LEFT;
|
||||
const int need_above = extend_modes[mode] & NEED_ABOVE;
|
||||
const int need_aboveright = extend_modes[mode] & NEED_ABOVERIGHT;
|
||||
int base = 128 << (bd - 8);
|
||||
// 127 127 127 .. 127 127 127 127 127 127
|
||||
// 129 A B .. Y Z
|
||||
// 129 C D .. W X
|
||||
// 129 E F .. U V
|
||||
// 129 G H .. S T T T T T
|
||||
// For 10 bit and 12 bit, 127 and 129 are replaced by base -1 and base + 1.
|
||||
|
||||
// Get current frame pointer, width and height.
|
||||
if (plane == 0) {
|
||||
frame_width = xd->cur_buf->y_width;
|
||||
frame_height = xd->cur_buf->y_height;
|
||||
} else {
|
||||
frame_width = xd->cur_buf->uv_width;
|
||||
frame_height = xd->cur_buf->uv_height;
|
||||
}
|
||||
|
||||
// Get block position in current frame.
|
||||
x0 = (-xd->mb_to_left_edge >> (3 + pd->subsampling_x)) + x;
|
||||
y0 = (-xd->mb_to_top_edge >> (3 + pd->subsampling_y)) + y;
|
||||
|
||||
// NEED_LEFT
|
||||
if (need_left) {
|
||||
if (left_available) {
|
||||
if (xd->mb_to_bottom_edge < 0) {
|
||||
/* slower path if the block needs border extension */
|
||||
if (y0 + bs <= frame_height) {
|
||||
for (i = 0; i < bs; ++i) left_col[i] = ref[i * ref_stride - 1];
|
||||
} else {
|
||||
const int extend_bottom = frame_height - y0;
|
||||
for (i = 0; i < extend_bottom; ++i)
|
||||
left_col[i] = ref[i * ref_stride - 1];
|
||||
for (; i < bs; ++i)
|
||||
left_col[i] = ref[(extend_bottom - 1) * ref_stride - 1];
|
||||
}
|
||||
} else {
|
||||
/* faster path if the block does not need extension */
|
||||
for (i = 0; i < bs; ++i) left_col[i] = ref[i * ref_stride - 1];
|
||||
}
|
||||
} else {
|
||||
vpx_memset16(left_col, base + 1, bs);
|
||||
}
|
||||
}
|
||||
|
||||
// NEED_ABOVE
|
||||
if (need_above) {
|
||||
if (up_available) {
|
||||
const uint16_t *above_ref = ref - ref_stride;
|
||||
if (xd->mb_to_right_edge < 0) {
|
||||
/* slower path if the block needs border extension */
|
||||
if (x0 + bs <= frame_width) {
|
||||
memcpy(above_row, above_ref, bs * sizeof(above_row[0]));
|
||||
} else if (x0 <= frame_width) {
|
||||
const int r = frame_width - x0;
|
||||
memcpy(above_row, above_ref, r * sizeof(above_row[0]));
|
||||
vpx_memset16(above_row + r, above_row[r - 1], x0 + bs - frame_width);
|
||||
}
|
||||
} else {
|
||||
/* faster path if the block does not need extension */
|
||||
if (bs == 4 && right_available && left_available) {
|
||||
const_above_row = above_ref;
|
||||
} else {
|
||||
memcpy(above_row, above_ref, bs * sizeof(above_row[0]));
|
||||
}
|
||||
}
|
||||
above_row[-1] = left_available ? above_ref[-1] : (base + 1);
|
||||
} else {
|
||||
vpx_memset16(above_row, base - 1, bs);
|
||||
above_row[-1] = base - 1;
|
||||
}
|
||||
}
|
||||
|
||||
// NEED_ABOVERIGHT
|
||||
if (need_aboveright) {
|
||||
if (up_available) {
|
||||
const uint16_t *above_ref = ref - ref_stride;
|
||||
if (xd->mb_to_right_edge < 0) {
|
||||
/* slower path if the block needs border extension */
|
||||
if (x0 + 2 * bs <= frame_width) {
|
||||
if (right_available && bs == 4) {
|
||||
memcpy(above_row, above_ref, 2 * bs * sizeof(above_row[0]));
|
||||
} else {
|
||||
memcpy(above_row, above_ref, bs * sizeof(above_row[0]));
|
||||
vpx_memset16(above_row + bs, above_row[bs - 1], bs);
|
||||
}
|
||||
} else if (x0 + bs <= frame_width) {
|
||||
const int r = frame_width - x0;
|
||||
if (right_available && bs == 4) {
|
||||
memcpy(above_row, above_ref, r * sizeof(above_row[0]));
|
||||
vpx_memset16(above_row + r, above_row[r - 1],
|
||||
x0 + 2 * bs - frame_width);
|
||||
} else {
|
||||
memcpy(above_row, above_ref, bs * sizeof(above_row[0]));
|
||||
vpx_memset16(above_row + bs, above_row[bs - 1], bs);
|
||||
}
|
||||
} else if (x0 <= frame_width) {
|
||||
const int r = frame_width - x0;
|
||||
memcpy(above_row, above_ref, r * sizeof(above_row[0]));
|
||||
vpx_memset16(above_row + r, above_row[r - 1],
|
||||
x0 + 2 * bs - frame_width);
|
||||
}
|
||||
above_row[-1] = left_available ? above_ref[-1] : (base + 1);
|
||||
} else {
|
||||
/* faster path if the block does not need extension */
|
||||
if (bs == 4 && right_available && left_available) {
|
||||
const_above_row = above_ref;
|
||||
} else {
|
||||
memcpy(above_row, above_ref, bs * sizeof(above_row[0]));
|
||||
if (bs == 4 && right_available)
|
||||
memcpy(above_row + bs, above_ref + bs, bs * sizeof(above_row[0]));
|
||||
else
|
||||
vpx_memset16(above_row + bs, above_row[bs - 1], bs);
|
||||
above_row[-1] = left_available ? above_ref[-1] : (base + 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
vpx_memset16(above_row, base - 1, bs * 2);
|
||||
above_row[-1] = base - 1;
|
||||
}
|
||||
}
|
||||
|
||||
// predict
|
||||
if (mode == DC_PRED) {
|
||||
dc_pred_high[left_available][up_available][tx_size](
|
||||
dst, dst_stride, const_above_row, left_col, xd->bd);
|
||||
} else {
|
||||
pred_high[mode][tx_size](dst, dst_stride, const_above_row, left_col,
|
||||
xd->bd);
|
||||
}
|
||||
}
|
||||
#endif // CONFIG_VP9_HIGHBITDEPTH
|
||||
|
||||
static void build_intra_predictors(const MACROBLOCKD *xd, const uint8_t *ref,
|
||||
int ref_stride, uint8_t *dst, int dst_stride,
|
||||
PREDICTION_MODE mode, TX_SIZE tx_size,
|
||||
int up_available, int left_available,
|
||||
int right_available, int x, int y,
|
||||
int plane) {
|
||||
int i;
|
||||
DECLARE_ALIGNED(16, uint8_t, left_col[32]);
|
||||
DECLARE_ALIGNED(16, uint8_t, above_data[64 + 16]);
|
||||
uint8_t *above_row = above_data + 16;
|
||||
const uint8_t *const_above_row = above_row;
|
||||
const int bs = 4 << tx_size;
|
||||
int frame_width, frame_height;
|
||||
int x0, y0;
|
||||
const struct macroblockd_plane *const pd = &xd->plane[plane];
|
||||
|
||||
// 127 127 127 .. 127 127 127 127 127 127
|
||||
// 129 A B .. Y Z
|
||||
// 129 C D .. W X
|
||||
// 129 E F .. U V
|
||||
// 129 G H .. S T T T T T
|
||||
// ..
|
||||
|
||||
// Get current frame pointer, width and height.
|
||||
if (plane == 0) {
|
||||
frame_width = xd->cur_buf->y_width;
|
||||
frame_height = xd->cur_buf->y_height;
|
||||
} else {
|
||||
frame_width = xd->cur_buf->uv_width;
|
||||
frame_height = xd->cur_buf->uv_height;
|
||||
}
|
||||
|
||||
// Get block position in current frame.
|
||||
x0 = (-xd->mb_to_left_edge >> (3 + pd->subsampling_x)) + x;
|
||||
y0 = (-xd->mb_to_top_edge >> (3 + pd->subsampling_y)) + y;
|
||||
|
||||
// NEED_LEFT
|
||||
if (extend_modes[mode] & NEED_LEFT) {
|
||||
if (left_available) {
|
||||
if (xd->mb_to_bottom_edge < 0) {
|
||||
/* slower path if the block needs border extension */
|
||||
if (y0 + bs <= frame_height) {
|
||||
for (i = 0; i < bs; ++i) left_col[i] = ref[i * ref_stride - 1];
|
||||
} else {
|
||||
const int extend_bottom = frame_height - y0;
|
||||
for (i = 0; i < extend_bottom; ++i)
|
||||
left_col[i] = ref[i * ref_stride - 1];
|
||||
for (; i < bs; ++i)
|
||||
left_col[i] = ref[(extend_bottom - 1) * ref_stride - 1];
|
||||
}
|
||||
} else {
|
||||
/* faster path if the block does not need extension */
|
||||
for (i = 0; i < bs; ++i) left_col[i] = ref[i * ref_stride - 1];
|
||||
}
|
||||
} else {
|
||||
memset(left_col, 129, bs);
|
||||
}
|
||||
}
|
||||
|
||||
// NEED_ABOVE
|
||||
if (extend_modes[mode] & NEED_ABOVE) {
|
||||
if (up_available) {
|
||||
const uint8_t *above_ref = ref - ref_stride;
|
||||
if (xd->mb_to_right_edge < 0) {
|
||||
/* slower path if the block needs border extension */
|
||||
if (x0 + bs <= frame_width) {
|
||||
memcpy(above_row, above_ref, bs);
|
||||
} else if (x0 <= frame_width) {
|
||||
const int r = frame_width - x0;
|
||||
memcpy(above_row, above_ref, r);
|
||||
memset(above_row + r, above_row[r - 1], x0 + bs - frame_width);
|
||||
}
|
||||
} else {
|
||||
/* faster path if the block does not need extension */
|
||||
if (bs == 4 && right_available && left_available) {
|
||||
const_above_row = above_ref;
|
||||
} else {
|
||||
memcpy(above_row, above_ref, bs);
|
||||
}
|
||||
}
|
||||
above_row[-1] = left_available ? above_ref[-1] : 129;
|
||||
} else {
|
||||
memset(above_row, 127, bs);
|
||||
above_row[-1] = 127;
|
||||
}
|
||||
}
|
||||
|
||||
// NEED_ABOVERIGHT
|
||||
if (extend_modes[mode] & NEED_ABOVERIGHT) {
|
||||
if (up_available) {
|
||||
const uint8_t *above_ref = ref - ref_stride;
|
||||
if (xd->mb_to_right_edge < 0) {
|
||||
/* slower path if the block needs border extension */
|
||||
if (x0 + 2 * bs <= frame_width) {
|
||||
if (right_available && bs == 4) {
|
||||
memcpy(above_row, above_ref, 2 * bs);
|
||||
} else {
|
||||
memcpy(above_row, above_ref, bs);
|
||||
memset(above_row + bs, above_row[bs - 1], bs);
|
||||
}
|
||||
} else if (x0 + bs <= frame_width) {
|
||||
const int r = frame_width - x0;
|
||||
if (right_available && bs == 4) {
|
||||
memcpy(above_row, above_ref, r);
|
||||
memset(above_row + r, above_row[r - 1], x0 + 2 * bs - frame_width);
|
||||
} else {
|
||||
memcpy(above_row, above_ref, bs);
|
||||
memset(above_row + bs, above_row[bs - 1], bs);
|
||||
}
|
||||
} else if (x0 <= frame_width) {
|
||||
const int r = frame_width - x0;
|
||||
memcpy(above_row, above_ref, r);
|
||||
memset(above_row + r, above_row[r - 1], x0 + 2 * bs - frame_width);
|
||||
}
|
||||
} else {
|
||||
/* faster path if the block does not need extension */
|
||||
if (bs == 4 && right_available && left_available) {
|
||||
const_above_row = above_ref;
|
||||
} else {
|
||||
memcpy(above_row, above_ref, bs);
|
||||
if (bs == 4 && right_available)
|
||||
memcpy(above_row + bs, above_ref + bs, bs);
|
||||
else
|
||||
memset(above_row + bs, above_row[bs - 1], bs);
|
||||
}
|
||||
}
|
||||
above_row[-1] = left_available ? above_ref[-1] : 129;
|
||||
} else {
|
||||
memset(above_row, 127, bs * 2);
|
||||
above_row[-1] = 127;
|
||||
}
|
||||
}
|
||||
|
||||
// predict
|
||||
if (mode == DC_PRED) {
|
||||
dc_pred[left_available][up_available][tx_size](dst, dst_stride,
|
||||
const_above_row, left_col);
|
||||
} else {
|
||||
pred[mode][tx_size](dst, dst_stride, const_above_row, left_col);
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_predict_intra_block(const MACROBLOCKD *xd, int bwl_in, TX_SIZE tx_size,
|
||||
PREDICTION_MODE mode, const uint8_t *ref,
|
||||
int ref_stride, uint8_t *dst, int dst_stride,
|
||||
int aoff, int loff, int plane) {
|
||||
const int bw = (1 << bwl_in);
|
||||
const int txw = (1 << tx_size);
|
||||
const int have_top = loff || (xd->above_mi != NULL);
|
||||
const int have_left = aoff || (xd->left_mi != NULL);
|
||||
const int have_right = (aoff + txw) < bw;
|
||||
const int x = aoff * 4;
|
||||
const int y = loff * 4;
|
||||
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) {
|
||||
build_intra_predictors_high(xd, ref, ref_stride, dst, dst_stride, mode,
|
||||
tx_size, have_top, have_left, have_right, x, y,
|
||||
plane, xd->bd);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
build_intra_predictors(xd, ref, ref_stride, dst, dst_stride, mode, tx_size,
|
||||
have_top, have_left, have_right, x, y, plane);
|
||||
}
|
||||
|
||||
void vp9_init_intra_predictors(void) {
|
||||
once(vp9_init_intra_predictors_internal);
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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 VPX_VP9_COMMON_VP9_RECONINTRA_H_
|
||||
#define VPX_VP9_COMMON_VP9_RECONINTRA_H_
|
||||
|
||||
#include "vpx/vpx_integer.h"
|
||||
#include "vp9/common/vp9_blockd.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void vp9_init_intra_predictors(void);
|
||||
|
||||
void vp9_predict_intra_block(const MACROBLOCKD *xd, int bwl_in, TX_SIZE tx_size,
|
||||
PREDICTION_MODE mode, const uint8_t *ref,
|
||||
int ref_stride, uint8_t *dst, int dst_stride,
|
||||
int aoff, int loff, int plane);
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_COMMON_VP9_RECONINTRA_H_
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* 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 "./vpx_config.h"
|
||||
#define RTCD_C
|
||||
#include "./vp9_rtcd.h"
|
||||
#include "vpx_ports/vpx_once.h"
|
||||
|
||||
void vp9_rtcd() {
|
||||
// TODO(JBB): Remove this once, by insuring that both the encoder and
|
||||
// decoder setup functions are protected by once();
|
||||
once(setup_rtcd_internal);
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
##
|
||||
## Copyright (c) 2017 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.
|
||||
##
|
||||
|
||||
sub vp9_common_forward_decls() {
|
||||
print <<EOF
|
||||
/*
|
||||
* VP9
|
||||
*/
|
||||
|
||||
#include "vpx/vpx_integer.h"
|
||||
#include "vp9/common/vp9_common.h"
|
||||
#include "vp9/common/vp9_enums.h"
|
||||
#include "vp9/common/vp9_filter.h"
|
||||
|
||||
struct macroblockd;
|
||||
|
||||
/* Encoder forward decls */
|
||||
struct macroblock;
|
||||
struct vp9_variance_vtable;
|
||||
struct search_site_config;
|
||||
struct mv;
|
||||
union int_mv;
|
||||
struct yv12_buffer_config;
|
||||
EOF
|
||||
}
|
||||
forward_decls qw/vp9_common_forward_decls/;
|
||||
|
||||
# functions that are 64 bit only.
|
||||
$mmx_x86_64 = $sse2_x86_64 = $ssse3_x86_64 = $avx_x86_64 = $avx2_x86_64 = '';
|
||||
if ($opts{arch} eq "x86_64") {
|
||||
$mmx_x86_64 = 'mmx';
|
||||
$sse2_x86_64 = 'sse2';
|
||||
$ssse3_x86_64 = 'ssse3';
|
||||
$avx_x86_64 = 'avx';
|
||||
$avx2_x86_64 = 'avx2';
|
||||
$avx512_x86_64 = 'avx512';
|
||||
}
|
||||
|
||||
#
|
||||
# post proc
|
||||
#
|
||||
if (vpx_config("CONFIG_VP9_POSTPROC") eq "yes") {
|
||||
add_proto qw/void vp9_filter_by_weight16x16/, "const uint8_t *src, int src_stride, uint8_t *dst, int dst_stride, int src_weight";
|
||||
specialize qw/vp9_filter_by_weight16x16 sse2 msa/;
|
||||
|
||||
add_proto qw/void vp9_filter_by_weight8x8/, "const uint8_t *src, int src_stride, uint8_t *dst, int dst_stride, int src_weight";
|
||||
specialize qw/vp9_filter_by_weight8x8 sse2 msa/;
|
||||
}
|
||||
|
||||
#
|
||||
# dct
|
||||
#
|
||||
# Force C versions if CONFIG_EMULATE_HARDWARE is 1
|
||||
add_proto qw/void vp9_iht4x4_16_add/, "const tran_low_t *input, uint8_t *dest, int stride, int tx_type";
|
||||
|
||||
add_proto qw/void vp9_iht8x8_64_add/, "const tran_low_t *input, uint8_t *dest, int stride, int tx_type";
|
||||
|
||||
add_proto qw/void vp9_iht16x16_256_add/, "const tran_low_t *input, uint8_t *dest, int stride, int tx_type";
|
||||
|
||||
if (vpx_config("CONFIG_EMULATE_HARDWARE") ne "yes") {
|
||||
# Note that there are more specializations appended when
|
||||
# CONFIG_VP9_HIGHBITDEPTH is off.
|
||||
specialize qw/vp9_iht4x4_16_add neon sse2 vsx/;
|
||||
specialize qw/vp9_iht8x8_64_add neon sse2 vsx/;
|
||||
specialize qw/vp9_iht16x16_256_add neon sse2 vsx/;
|
||||
if (vpx_config("CONFIG_VP9_HIGHBITDEPTH") ne "yes") {
|
||||
# Note that these specializations are appended to the above ones.
|
||||
specialize qw/vp9_iht4x4_16_add dspr2 msa/;
|
||||
specialize qw/vp9_iht8x8_64_add dspr2 msa/;
|
||||
specialize qw/vp9_iht16x16_256_add dspr2 msa/;
|
||||
}
|
||||
}
|
||||
|
||||
# High bitdepth functions
|
||||
if (vpx_config("CONFIG_VP9_HIGHBITDEPTH") eq "yes") {
|
||||
#
|
||||
# post proc
|
||||
#
|
||||
if (vpx_config("CONFIG_VP9_POSTPROC") eq "yes") {
|
||||
add_proto qw/void vp9_highbd_mbpost_proc_down/, "uint16_t *dst, int pitch, int rows, int cols, int flimit";
|
||||
|
||||
add_proto qw/void vp9_highbd_mbpost_proc_across_ip/, "uint16_t *src, int pitch, int rows, int cols, int flimit";
|
||||
|
||||
add_proto qw/void vp9_highbd_post_proc_down_and_across/, "const uint16_t *src_ptr, uint16_t *dst_ptr, int src_pixels_per_line, int dst_pixels_per_line, int rows, int cols, int flimit";
|
||||
}
|
||||
|
||||
#
|
||||
# dct
|
||||
#
|
||||
# Note as optimized versions of these functions are added we need to add a check to ensure
|
||||
# that when CONFIG_EMULATE_HARDWARE is on, it defaults to the C versions only.
|
||||
add_proto qw/void vp9_highbd_iht4x4_16_add/, "const tran_low_t *input, uint16_t *dest, int stride, int tx_type, int bd";
|
||||
|
||||
add_proto qw/void vp9_highbd_iht8x8_64_add/, "const tran_low_t *input, uint16_t *dest, int stride, int tx_type, int bd";
|
||||
|
||||
add_proto qw/void vp9_highbd_iht16x16_256_add/, "const tran_low_t *input, uint16_t *dest, int stride, int tx_type, int bd";
|
||||
|
||||
if (vpx_config("CONFIG_EMULATE_HARDWARE") ne "yes") {
|
||||
specialize qw/vp9_highbd_iht4x4_16_add neon sse4_1/;
|
||||
specialize qw/vp9_highbd_iht8x8_64_add neon sse4_1/;
|
||||
specialize qw/vp9_highbd_iht16x16_256_add neon sse4_1/;
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# Encoder functions below this point.
|
||||
#
|
||||
if (vpx_config("CONFIG_VP9_ENCODER") eq "yes") {
|
||||
|
||||
# ENCODEMB INVOKE
|
||||
|
||||
#
|
||||
# Denoiser
|
||||
#
|
||||
if (vpx_config("CONFIG_VP9_TEMPORAL_DENOISING") eq "yes") {
|
||||
add_proto qw/int vp9_denoiser_filter/, "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";
|
||||
specialize qw/vp9_denoiser_filter neon sse2/;
|
||||
}
|
||||
|
||||
add_proto qw/int64_t vp9_block_error/, "const tran_low_t *coeff, const tran_low_t *dqcoeff, intptr_t block_size, int64_t *ssz";
|
||||
|
||||
add_proto qw/int64_t vp9_block_error_fp/, "const tran_low_t *coeff, const tran_low_t *dqcoeff, int block_size";
|
||||
|
||||
add_proto qw/void vp9_quantize_fp/, "const tran_low_t *coeff_ptr, intptr_t 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, const int16_t *scan, const int16_t *iscan";
|
||||
specialize qw/vp9_quantize_fp neon sse2 avx2 vsx/, "$ssse3_x86_64";
|
||||
|
||||
add_proto qw/void vp9_quantize_fp_32x32/, "const tran_low_t *coeff_ptr, intptr_t 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, const int16_t *scan, const int16_t *iscan";
|
||||
specialize qw/vp9_quantize_fp_32x32 neon vsx/, "$ssse3_x86_64";
|
||||
|
||||
if (vpx_config("CONFIG_VP9_HIGHBITDEPTH") eq "yes") {
|
||||
specialize qw/vp9_block_error avx2 sse2/;
|
||||
|
||||
specialize qw/vp9_block_error_fp avx2 sse2/;
|
||||
|
||||
add_proto qw/int64_t vp9_highbd_block_error/, "const tran_low_t *coeff, const tran_low_t *dqcoeff, intptr_t block_size, int64_t *ssz, int bd";
|
||||
specialize qw/vp9_highbd_block_error sse2/;
|
||||
} else {
|
||||
specialize qw/vp9_block_error avx2 msa sse2/;
|
||||
|
||||
specialize qw/vp9_block_error_fp neon avx2 sse2/;
|
||||
}
|
||||
|
||||
# fdct functions
|
||||
|
||||
add_proto qw/void vp9_fht4x4/, "const int16_t *input, tran_low_t *output, int stride, int tx_type";
|
||||
|
||||
add_proto qw/void vp9_fht8x8/, "const int16_t *input, tran_low_t *output, int stride, int tx_type";
|
||||
|
||||
add_proto qw/void vp9_fht16x16/, "const int16_t *input, tran_low_t *output, int stride, int tx_type";
|
||||
|
||||
add_proto qw/void vp9_fwht4x4/, "const int16_t *input, tran_low_t *output, int stride";
|
||||
|
||||
# Note that there are more specializations appended when CONFIG_VP9_HIGHBITDEPTH
|
||||
# is off.
|
||||
specialize qw/vp9_fht4x4 sse2/;
|
||||
specialize qw/vp9_fht8x8 sse2/;
|
||||
specialize qw/vp9_fht16x16 sse2/;
|
||||
specialize qw/vp9_fwht4x4 sse2/;
|
||||
if (vpx_config("CONFIG_VP9_HIGHBITDEPTH") ne "yes") {
|
||||
# Note that these specializations are appended to the above ones.
|
||||
specialize qw/vp9_fht4x4 msa/;
|
||||
specialize qw/vp9_fht8x8 msa/;
|
||||
specialize qw/vp9_fht16x16 msa/;
|
||||
specialize qw/vp9_fwht4x4 msa/;
|
||||
}
|
||||
|
||||
#
|
||||
# Motion search
|
||||
#
|
||||
add_proto qw/int vp9_diamond_search_sad/, "const struct macroblock *x, const struct search_site_config *cfg, struct mv *ref_mv, struct mv *best_mv, int search_param, int sad_per_bit, int *num00, const struct vp9_variance_vtable *fn_ptr, const struct mv *center_mv";
|
||||
specialize qw/vp9_diamond_search_sad avx/;
|
||||
|
||||
#
|
||||
# Apply temporal filter
|
||||
#
|
||||
if (vpx_config("CONFIG_REALTIME_ONLY") ne "yes") {
|
||||
add_proto qw/void vp9_apply_temporal_filter/, "const uint8_t *y_src, int y_src_stride, const uint8_t *y_pre, int y_pre_stride, const uint8_t *u_src, const uint8_t *v_src, int uv_src_stride, const uint8_t *u_pre, const uint8_t *v_pre, int uv_pre_stride, unsigned int block_width, unsigned int block_height, int ss_x, int ss_y, int strength, const int *const blk_fw, int use_32x32, uint32_t *y_accumulator, uint16_t *y_count, uint32_t *u_accumulator, uint16_t *u_count, uint32_t *v_accumulator, uint16_t *v_count";
|
||||
specialize qw/vp9_apply_temporal_filter sse4_1/;
|
||||
|
||||
if (vpx_config("CONFIG_VP9_HIGHBITDEPTH") eq "yes") {
|
||||
add_proto qw/void vp9_highbd_apply_temporal_filter/, "const uint16_t *y_src, int y_src_stride, const uint16_t *y_pre, int y_pre_stride, const uint16_t *u_src, const uint16_t *v_src, int uv_src_stride, const uint16_t *u_pre, const uint16_t *v_pre, int uv_pre_stride, unsigned int block_width, unsigned int block_height, int ss_x, int ss_y, int strength, const int *const blk_fw, int use_32x32, uint32_t *y_accum, uint16_t *y_count, uint32_t *u_accum, uint16_t *u_count, uint32_t *v_accum, uint16_t *v_count";
|
||||
specialize qw/vp9_highbd_apply_temporal_filter sse4_1/;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (vpx_config("CONFIG_VP9_HIGHBITDEPTH") eq "yes") {
|
||||
|
||||
# ENCODEMB INVOKE
|
||||
|
||||
add_proto qw/void vp9_highbd_quantize_fp/, "const tran_low_t *coeff_ptr, intptr_t 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, const int16_t *scan, const int16_t *iscan";
|
||||
|
||||
add_proto qw/void vp9_highbd_quantize_fp_32x32/, "const tran_low_t *coeff_ptr, intptr_t 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, const int16_t *scan, const int16_t *iscan" ;
|
||||
|
||||
# fdct functions
|
||||
add_proto qw/void vp9_highbd_fht4x4/, "const int16_t *input, tran_low_t *output, int stride, int tx_type";
|
||||
|
||||
add_proto qw/void vp9_highbd_fht8x8/, "const int16_t *input, tran_low_t *output, int stride, int tx_type";
|
||||
|
||||
add_proto qw/void vp9_highbd_fht16x16/, "const int16_t *input, tran_low_t *output, int stride, int tx_type";
|
||||
|
||||
add_proto qw/void vp9_highbd_fwht4x4/, "const int16_t *input, tran_low_t *output, int stride";
|
||||
|
||||
add_proto qw/void vp9_highbd_temporal_filter_apply/, "const uint8_t *frame1, unsigned int stride, const uint8_t *frame2, unsigned int block_width, unsigned int block_height, int strength, int *blk_fw, int use_32x32, uint32_t *accumulator, uint16_t *count";
|
||||
|
||||
}
|
||||
# End vp9_high encoder functions
|
||||
|
||||
#
|
||||
# frame based scale
|
||||
#
|
||||
add_proto qw/void vp9_scale_and_extend_frame/, "const struct yv12_buffer_config *src, struct yv12_buffer_config *dst, INTERP_FILTER filter_type, int phase_scaler";
|
||||
specialize qw/vp9_scale_and_extend_frame neon ssse3/;
|
||||
|
||||
}
|
||||
# end encoder functions
|
||||
1;
|
||||
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* 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 "./vpx_dsp_rtcd.h"
|
||||
#include "vp9/common/vp9_filter.h"
|
||||
#include "vp9/common/vp9_scale.h"
|
||||
#include "vpx_dsp/vpx_filter.h"
|
||||
|
||||
static INLINE int scaled_x(int val, const struct scale_factors *sf) {
|
||||
return (int)((int64_t)val * sf->x_scale_fp >> REF_SCALE_SHIFT);
|
||||
}
|
||||
|
||||
static INLINE int scaled_y(int val, const struct scale_factors *sf) {
|
||||
return (int)((int64_t)val * sf->y_scale_fp >> REF_SCALE_SHIFT);
|
||||
}
|
||||
|
||||
static int unscaled_value(int val, const struct scale_factors *sf) {
|
||||
(void)sf;
|
||||
return val;
|
||||
}
|
||||
|
||||
static int get_fixed_point_scale_factor(int other_size, int this_size) {
|
||||
// Calculate scaling factor once for each reference frame
|
||||
// and use fixed point scaling factors in decoding and encoding routines.
|
||||
// Hardware implementations can calculate scale factor in device driver
|
||||
// and use multiplication and shifting on hardware instead of division.
|
||||
return (other_size << REF_SCALE_SHIFT) / this_size;
|
||||
}
|
||||
|
||||
MV32 vp9_scale_mv(const MV *mv, int x, int y, const struct scale_factors *sf) {
|
||||
const int x_off_q4 = scaled_x(x << SUBPEL_BITS, sf) & SUBPEL_MASK;
|
||||
const int y_off_q4 = scaled_y(y << SUBPEL_BITS, sf) & SUBPEL_MASK;
|
||||
const MV32 res = { scaled_y(mv->row, sf) + y_off_q4,
|
||||
scaled_x(mv->col, sf) + x_off_q4 };
|
||||
return res;
|
||||
}
|
||||
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
void vp9_setup_scale_factors_for_frame(struct scale_factors *sf, int other_w,
|
||||
int other_h, int this_w, int this_h,
|
||||
int use_highbd) {
|
||||
#else
|
||||
void vp9_setup_scale_factors_for_frame(struct scale_factors *sf, int other_w,
|
||||
int other_h, int this_w, int this_h) {
|
||||
#endif
|
||||
if (!valid_ref_frame_size(other_w, other_h, this_w, this_h)) {
|
||||
sf->x_scale_fp = REF_INVALID_SCALE;
|
||||
sf->y_scale_fp = REF_INVALID_SCALE;
|
||||
return;
|
||||
}
|
||||
|
||||
sf->x_scale_fp = get_fixed_point_scale_factor(other_w, this_w);
|
||||
sf->y_scale_fp = get_fixed_point_scale_factor(other_h, this_h);
|
||||
sf->x_step_q4 = scaled_x(16, sf);
|
||||
sf->y_step_q4 = scaled_y(16, sf);
|
||||
|
||||
if (vp9_is_scaled(sf)) {
|
||||
sf->scale_value_x = scaled_x;
|
||||
sf->scale_value_y = scaled_y;
|
||||
} else {
|
||||
sf->scale_value_x = unscaled_value;
|
||||
sf->scale_value_y = unscaled_value;
|
||||
}
|
||||
|
||||
// TODO(agrange): Investigate the best choice of functions to use here
|
||||
// for EIGHTTAP_SMOOTH. Since it is not interpolating, need to choose what
|
||||
// to do at full-pel offsets. The current selection, where the filter is
|
||||
// applied in one direction only, and not at all for 0,0, seems to give the
|
||||
// best quality, but it may be worth trying an additional mode that does
|
||||
// do the filtering on full-pel.
|
||||
|
||||
if (sf->x_step_q4 == 16) {
|
||||
if (sf->y_step_q4 == 16) {
|
||||
// No scaling in either direction.
|
||||
sf->predict[0][0][0] = vpx_convolve_copy;
|
||||
sf->predict[0][0][1] = vpx_convolve_avg;
|
||||
sf->predict[0][1][0] = vpx_convolve8_vert;
|
||||
sf->predict[0][1][1] = vpx_convolve8_avg_vert;
|
||||
sf->predict[1][0][0] = vpx_convolve8_horiz;
|
||||
sf->predict[1][0][1] = vpx_convolve8_avg_horiz;
|
||||
} else {
|
||||
// No scaling in x direction. Must always scale in the y direction.
|
||||
sf->predict[0][0][0] = vpx_scaled_vert;
|
||||
sf->predict[0][0][1] = vpx_scaled_avg_vert;
|
||||
sf->predict[0][1][0] = vpx_scaled_vert;
|
||||
sf->predict[0][1][1] = vpx_scaled_avg_vert;
|
||||
sf->predict[1][0][0] = vpx_scaled_2d;
|
||||
sf->predict[1][0][1] = vpx_scaled_avg_2d;
|
||||
}
|
||||
} else {
|
||||
if (sf->y_step_q4 == 16) {
|
||||
// No scaling in the y direction. Must always scale in the x direction.
|
||||
sf->predict[0][0][0] = vpx_scaled_horiz;
|
||||
sf->predict[0][0][1] = vpx_scaled_avg_horiz;
|
||||
sf->predict[0][1][0] = vpx_scaled_2d;
|
||||
sf->predict[0][1][1] = vpx_scaled_avg_2d;
|
||||
sf->predict[1][0][0] = vpx_scaled_horiz;
|
||||
sf->predict[1][0][1] = vpx_scaled_avg_horiz;
|
||||
} else {
|
||||
// Must always scale in both directions.
|
||||
sf->predict[0][0][0] = vpx_scaled_2d;
|
||||
sf->predict[0][0][1] = vpx_scaled_avg_2d;
|
||||
sf->predict[0][1][0] = vpx_scaled_2d;
|
||||
sf->predict[0][1][1] = vpx_scaled_avg_2d;
|
||||
sf->predict[1][0][0] = vpx_scaled_2d;
|
||||
sf->predict[1][0][1] = vpx_scaled_avg_2d;
|
||||
}
|
||||
}
|
||||
|
||||
// 2D subpel motion always gets filtered in both directions
|
||||
|
||||
if ((sf->x_step_q4 != 16) || (sf->y_step_q4 != 16)) {
|
||||
sf->predict[1][1][0] = vpx_scaled_2d;
|
||||
sf->predict[1][1][1] = vpx_scaled_avg_2d;
|
||||
} else {
|
||||
sf->predict[1][1][0] = vpx_convolve8;
|
||||
sf->predict[1][1][1] = vpx_convolve8_avg;
|
||||
}
|
||||
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
if (use_highbd) {
|
||||
if (sf->x_step_q4 == 16) {
|
||||
if (sf->y_step_q4 == 16) {
|
||||
// No scaling in either direction.
|
||||
sf->highbd_predict[0][0][0] = vpx_highbd_convolve_copy;
|
||||
sf->highbd_predict[0][0][1] = vpx_highbd_convolve_avg;
|
||||
sf->highbd_predict[0][1][0] = vpx_highbd_convolve8_vert;
|
||||
sf->highbd_predict[0][1][1] = vpx_highbd_convolve8_avg_vert;
|
||||
sf->highbd_predict[1][0][0] = vpx_highbd_convolve8_horiz;
|
||||
sf->highbd_predict[1][0][1] = vpx_highbd_convolve8_avg_horiz;
|
||||
} else {
|
||||
// No scaling in x direction. Must always scale in the y direction.
|
||||
sf->highbd_predict[0][0][0] = vpx_highbd_convolve8_vert;
|
||||
sf->highbd_predict[0][0][1] = vpx_highbd_convolve8_avg_vert;
|
||||
sf->highbd_predict[0][1][0] = vpx_highbd_convolve8_vert;
|
||||
sf->highbd_predict[0][1][1] = vpx_highbd_convolve8_avg_vert;
|
||||
sf->highbd_predict[1][0][0] = vpx_highbd_convolve8;
|
||||
sf->highbd_predict[1][0][1] = vpx_highbd_convolve8_avg;
|
||||
}
|
||||
} else {
|
||||
if (sf->y_step_q4 == 16) {
|
||||
// No scaling in the y direction. Must always scale in the x direction.
|
||||
sf->highbd_predict[0][0][0] = vpx_highbd_convolve8_horiz;
|
||||
sf->highbd_predict[0][0][1] = vpx_highbd_convolve8_avg_horiz;
|
||||
sf->highbd_predict[0][1][0] = vpx_highbd_convolve8;
|
||||
sf->highbd_predict[0][1][1] = vpx_highbd_convolve8_avg;
|
||||
sf->highbd_predict[1][0][0] = vpx_highbd_convolve8_horiz;
|
||||
sf->highbd_predict[1][0][1] = vpx_highbd_convolve8_avg_horiz;
|
||||
} else {
|
||||
// Must always scale in both directions.
|
||||
sf->highbd_predict[0][0][0] = vpx_highbd_convolve8;
|
||||
sf->highbd_predict[0][0][1] = vpx_highbd_convolve8_avg;
|
||||
sf->highbd_predict[0][1][0] = vpx_highbd_convolve8;
|
||||
sf->highbd_predict[0][1][1] = vpx_highbd_convolve8_avg;
|
||||
sf->highbd_predict[1][0][0] = vpx_highbd_convolve8;
|
||||
sf->highbd_predict[1][0][1] = vpx_highbd_convolve8_avg;
|
||||
}
|
||||
}
|
||||
// 2D subpel motion always gets filtered in both directions.
|
||||
sf->highbd_predict[1][1][0] = vpx_highbd_convolve8;
|
||||
sf->highbd_predict[1][1][1] = vpx_highbd_convolve8_avg;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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 VPX_VP9_COMMON_VP9_SCALE_H_
|
||||
#define VPX_VP9_COMMON_VP9_SCALE_H_
|
||||
|
||||
#include "vp9/common/vp9_mv.h"
|
||||
#include "vpx_dsp/vpx_convolve.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define REF_SCALE_SHIFT 14
|
||||
#define REF_NO_SCALE (1 << REF_SCALE_SHIFT)
|
||||
#define REF_INVALID_SCALE (-1)
|
||||
|
||||
struct scale_factors {
|
||||
int x_scale_fp; // horizontal fixed point scale factor
|
||||
int y_scale_fp; // vertical fixed point scale factor
|
||||
int x_step_q4;
|
||||
int y_step_q4;
|
||||
|
||||
int (*scale_value_x)(int val, const struct scale_factors *sf);
|
||||
int (*scale_value_y)(int val, const struct scale_factors *sf);
|
||||
|
||||
convolve_fn_t predict[2][2][2]; // horiz, vert, avg
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
highbd_convolve_fn_t highbd_predict[2][2][2]; // horiz, vert, avg
|
||||
#endif
|
||||
};
|
||||
|
||||
MV32 vp9_scale_mv(const MV *mv, int x, int y, const struct scale_factors *sf);
|
||||
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
void vp9_setup_scale_factors_for_frame(struct scale_factors *sf, int other_w,
|
||||
int other_h, int this_w, int this_h,
|
||||
int use_highbd);
|
||||
#else
|
||||
void vp9_setup_scale_factors_for_frame(struct scale_factors *sf, int other_w,
|
||||
int other_h, int this_w, int this_h);
|
||||
#endif
|
||||
|
||||
static INLINE int vp9_is_valid_scale(const struct scale_factors *sf) {
|
||||
return sf->x_scale_fp != REF_INVALID_SCALE &&
|
||||
sf->y_scale_fp != REF_INVALID_SCALE;
|
||||
}
|
||||
|
||||
static INLINE int vp9_is_scaled(const struct scale_factors *sf) {
|
||||
return vp9_is_valid_scale(sf) &&
|
||||
(sf->x_scale_fp != REF_NO_SCALE || sf->y_scale_fp != REF_NO_SCALE);
|
||||
}
|
||||
|
||||
static INLINE int valid_ref_frame_size(int ref_width, int ref_height,
|
||||
int this_width, int this_height) {
|
||||
return 2 * this_width >= ref_width && 2 * this_height >= ref_height &&
|
||||
this_width <= 16 * ref_width && this_height <= 16 * ref_height;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_COMMON_VP9_SCALE_H_
|
||||
@@ -0,0 +1,724 @@
|
||||
/*
|
||||
* 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/common/vp9_scan.h"
|
||||
|
||||
DECLARE_ALIGNED(16, static const int16_t, default_scan_4x4[16]) = {
|
||||
0, 4, 1, 5, 8, 2, 12, 9, 3, 6, 13, 10, 7, 14, 11, 15,
|
||||
};
|
||||
|
||||
DECLARE_ALIGNED(16, static const int16_t, col_scan_4x4[16]) = {
|
||||
0, 4, 8, 1, 12, 5, 9, 2, 13, 6, 10, 3, 7, 14, 11, 15,
|
||||
};
|
||||
|
||||
DECLARE_ALIGNED(16, static const int16_t, row_scan_4x4[16]) = {
|
||||
0, 1, 4, 2, 5, 3, 6, 8, 9, 7, 12, 10, 13, 11, 14, 15,
|
||||
};
|
||||
|
||||
DECLARE_ALIGNED(16, static const int16_t, default_scan_8x8[64]) = {
|
||||
0, 8, 1, 16, 9, 2, 17, 24, 10, 3, 18, 25, 32, 11, 4, 26,
|
||||
33, 19, 40, 12, 34, 27, 5, 41, 20, 48, 13, 35, 42, 28, 21, 6,
|
||||
49, 56, 36, 43, 29, 7, 14, 50, 57, 44, 22, 37, 15, 51, 58, 30,
|
||||
45, 23, 52, 59, 38, 31, 60, 53, 46, 39, 61, 54, 47, 62, 55, 63,
|
||||
};
|
||||
|
||||
DECLARE_ALIGNED(16, static const int16_t, col_scan_8x8[64]) = {
|
||||
0, 8, 16, 1, 24, 9, 32, 17, 2, 40, 25, 10, 33, 18, 48, 3,
|
||||
26, 41, 11, 56, 19, 34, 4, 49, 27, 42, 12, 35, 20, 57, 50, 28,
|
||||
5, 43, 13, 36, 58, 51, 21, 44, 6, 29, 59, 37, 14, 52, 22, 7,
|
||||
45, 60, 30, 15, 38, 53, 23, 46, 31, 61, 39, 54, 47, 62, 55, 63,
|
||||
};
|
||||
|
||||
DECLARE_ALIGNED(16, static const int16_t, row_scan_8x8[64]) = {
|
||||
0, 1, 2, 8, 9, 3, 16, 10, 4, 17, 11, 24, 5, 18, 25, 12,
|
||||
19, 26, 32, 6, 13, 20, 33, 27, 7, 34, 40, 21, 28, 41, 14, 35,
|
||||
48, 42, 29, 36, 49, 22, 43, 15, 56, 37, 50, 44, 30, 57, 23, 51,
|
||||
58, 45, 38, 52, 31, 59, 53, 46, 60, 39, 61, 47, 54, 55, 62, 63,
|
||||
};
|
||||
|
||||
DECLARE_ALIGNED(16, static const int16_t, default_scan_16x16[256]) = {
|
||||
0, 16, 1, 32, 17, 2, 48, 33, 18, 3, 64, 34, 49, 19, 65,
|
||||
80, 50, 4, 35, 66, 20, 81, 96, 51, 5, 36, 82, 97, 67, 112,
|
||||
21, 52, 98, 37, 83, 113, 6, 68, 128, 53, 22, 99, 114, 84, 7,
|
||||
129, 38, 69, 100, 115, 144, 130, 85, 54, 23, 8, 145, 39, 70, 116,
|
||||
101, 131, 160, 146, 55, 86, 24, 71, 132, 117, 161, 40, 9, 102, 147,
|
||||
176, 162, 87, 56, 25, 133, 118, 177, 148, 72, 103, 41, 163, 10, 192,
|
||||
178, 88, 57, 134, 149, 119, 26, 164, 73, 104, 193, 42, 179, 208, 11,
|
||||
135, 89, 165, 120, 150, 58, 194, 180, 27, 74, 209, 105, 151, 136, 43,
|
||||
90, 224, 166, 195, 181, 121, 210, 59, 12, 152, 106, 167, 196, 75, 137,
|
||||
225, 211, 240, 182, 122, 91, 28, 197, 13, 226, 168, 183, 153, 44, 212,
|
||||
138, 107, 241, 60, 29, 123, 198, 184, 227, 169, 242, 76, 213, 154, 45,
|
||||
92, 14, 199, 139, 61, 228, 214, 170, 185, 243, 108, 77, 155, 30, 15,
|
||||
200, 229, 124, 215, 244, 93, 46, 186, 171, 201, 109, 140, 230, 62, 216,
|
||||
245, 31, 125, 78, 156, 231, 47, 187, 202, 217, 94, 246, 141, 63, 232,
|
||||
172, 110, 247, 157, 79, 218, 203, 126, 233, 188, 248, 95, 173, 142, 219,
|
||||
111, 249, 234, 158, 127, 189, 204, 250, 235, 143, 174, 220, 205, 159, 251,
|
||||
190, 221, 175, 236, 237, 191, 206, 252, 222, 253, 207, 238, 223, 254, 239,
|
||||
255,
|
||||
};
|
||||
|
||||
DECLARE_ALIGNED(16, static const int16_t, col_scan_16x16[256]) = {
|
||||
0, 16, 32, 48, 1, 64, 17, 80, 33, 96, 49, 2, 65, 112, 18,
|
||||
81, 34, 128, 50, 97, 3, 66, 144, 19, 113, 35, 82, 160, 98, 51,
|
||||
129, 4, 67, 176, 20, 114, 145, 83, 36, 99, 130, 52, 192, 5, 161,
|
||||
68, 115, 21, 146, 84, 208, 177, 37, 131, 100, 53, 162, 224, 69, 6,
|
||||
116, 193, 147, 85, 22, 240, 132, 38, 178, 101, 163, 54, 209, 117, 70,
|
||||
7, 148, 194, 86, 179, 225, 23, 133, 39, 164, 8, 102, 210, 241, 55,
|
||||
195, 118, 149, 71, 180, 24, 87, 226, 134, 165, 211, 40, 103, 56, 72,
|
||||
150, 196, 242, 119, 9, 181, 227, 88, 166, 25, 135, 41, 104, 212, 57,
|
||||
151, 197, 120, 73, 243, 182, 136, 167, 213, 89, 10, 228, 105, 152, 198,
|
||||
26, 42, 121, 183, 244, 168, 58, 137, 229, 74, 214, 90, 153, 199, 184,
|
||||
11, 106, 245, 27, 122, 230, 169, 43, 215, 59, 200, 138, 185, 246, 75,
|
||||
12, 91, 154, 216, 231, 107, 28, 44, 201, 123, 170, 60, 247, 232, 76,
|
||||
139, 13, 92, 217, 186, 248, 155, 108, 29, 124, 45, 202, 233, 171, 61,
|
||||
14, 77, 140, 15, 249, 93, 30, 187, 156, 218, 46, 109, 125, 62, 172,
|
||||
78, 203, 31, 141, 234, 94, 47, 188, 63, 157, 110, 250, 219, 79, 126,
|
||||
204, 173, 142, 95, 189, 111, 235, 158, 220, 251, 127, 174, 143, 205, 236,
|
||||
159, 190, 221, 252, 175, 206, 237, 191, 253, 222, 238, 207, 254, 223, 239,
|
||||
255,
|
||||
};
|
||||
|
||||
DECLARE_ALIGNED(16, static const int16_t, row_scan_16x16[256]) = {
|
||||
0, 1, 2, 16, 3, 17, 4, 18, 32, 5, 33, 19, 6, 34, 48,
|
||||
20, 49, 7, 35, 21, 50, 64, 8, 36, 65, 22, 51, 37, 80, 9,
|
||||
66, 52, 23, 38, 81, 67, 10, 53, 24, 82, 68, 96, 39, 11, 54,
|
||||
83, 97, 69, 25, 98, 84, 40, 112, 55, 12, 70, 99, 113, 85, 26,
|
||||
41, 56, 114, 100, 13, 71, 128, 86, 27, 115, 101, 129, 42, 57, 72,
|
||||
116, 14, 87, 130, 102, 144, 73, 131, 117, 28, 58, 15, 88, 43, 145,
|
||||
103, 132, 146, 118, 74, 160, 89, 133, 104, 29, 59, 147, 119, 44, 161,
|
||||
148, 90, 105, 134, 162, 120, 176, 75, 135, 149, 30, 60, 163, 177, 45,
|
||||
121, 91, 106, 164, 178, 150, 192, 136, 165, 179, 31, 151, 193, 76, 122,
|
||||
61, 137, 194, 107, 152, 180, 208, 46, 166, 167, 195, 92, 181, 138, 209,
|
||||
123, 153, 224, 196, 77, 168, 210, 182, 240, 108, 197, 62, 154, 225, 183,
|
||||
169, 211, 47, 139, 93, 184, 226, 212, 241, 198, 170, 124, 155, 199, 78,
|
||||
213, 185, 109, 227, 200, 63, 228, 242, 140, 214, 171, 186, 156, 229, 243,
|
||||
125, 94, 201, 244, 215, 216, 230, 141, 187, 202, 79, 172, 110, 157, 245,
|
||||
217, 231, 95, 246, 232, 126, 203, 247, 233, 173, 218, 142, 111, 158, 188,
|
||||
248, 127, 234, 219, 249, 189, 204, 143, 174, 159, 250, 235, 205, 220, 175,
|
||||
190, 251, 221, 191, 206, 236, 207, 237, 252, 222, 253, 223, 238, 239, 254,
|
||||
255,
|
||||
};
|
||||
|
||||
DECLARE_ALIGNED(16, static const int16_t, default_scan_32x32[1024]) = {
|
||||
0, 32, 1, 64, 33, 2, 96, 65, 34, 128, 3, 97, 66,
|
||||
160, 129, 35, 98, 4, 67, 130, 161, 192, 36, 99, 224, 5,
|
||||
162, 193, 68, 131, 37, 100, 225, 194, 256, 163, 69, 132, 6,
|
||||
226, 257, 288, 195, 101, 164, 38, 258, 7, 227, 289, 133, 320,
|
||||
70, 196, 165, 290, 259, 228, 39, 321, 102, 352, 8, 197, 71,
|
||||
134, 322, 291, 260, 353, 384, 229, 166, 103, 40, 354, 323, 292,
|
||||
135, 385, 198, 261, 72, 9, 416, 167, 386, 355, 230, 324, 104,
|
||||
293, 41, 417, 199, 136, 262, 387, 448, 325, 356, 10, 73, 418,
|
||||
231, 168, 449, 294, 388, 105, 419, 263, 42, 200, 357, 450, 137,
|
||||
480, 74, 326, 232, 11, 389, 169, 295, 420, 106, 451, 481, 358,
|
||||
264, 327, 201, 43, 138, 512, 482, 390, 296, 233, 170, 421, 75,
|
||||
452, 359, 12, 513, 265, 483, 328, 107, 202, 514, 544, 422, 391,
|
||||
453, 139, 44, 234, 484, 297, 360, 171, 76, 515, 545, 266, 329,
|
||||
454, 13, 423, 203, 108, 546, 485, 576, 298, 235, 140, 361, 330,
|
||||
172, 547, 45, 455, 267, 577, 486, 77, 204, 362, 608, 14, 299,
|
||||
578, 109, 236, 487, 609, 331, 141, 579, 46, 15, 173, 610, 363,
|
||||
78, 205, 16, 110, 237, 611, 142, 47, 174, 79, 206, 17, 111,
|
||||
238, 48, 143, 80, 175, 112, 207, 49, 18, 239, 81, 113, 19,
|
||||
50, 82, 114, 51, 83, 115, 640, 516, 392, 268, 144, 20, 672,
|
||||
641, 548, 517, 424, 393, 300, 269, 176, 145, 52, 21, 704, 673,
|
||||
642, 580, 549, 518, 456, 425, 394, 332, 301, 270, 208, 177, 146,
|
||||
84, 53, 22, 736, 705, 674, 643, 612, 581, 550, 519, 488, 457,
|
||||
426, 395, 364, 333, 302, 271, 240, 209, 178, 147, 116, 85, 54,
|
||||
23, 737, 706, 675, 613, 582, 551, 489, 458, 427, 365, 334, 303,
|
||||
241, 210, 179, 117, 86, 55, 738, 707, 614, 583, 490, 459, 366,
|
||||
335, 242, 211, 118, 87, 739, 615, 491, 367, 243, 119, 768, 644,
|
||||
520, 396, 272, 148, 24, 800, 769, 676, 645, 552, 521, 428, 397,
|
||||
304, 273, 180, 149, 56, 25, 832, 801, 770, 708, 677, 646, 584,
|
||||
553, 522, 460, 429, 398, 336, 305, 274, 212, 181, 150, 88, 57,
|
||||
26, 864, 833, 802, 771, 740, 709, 678, 647, 616, 585, 554, 523,
|
||||
492, 461, 430, 399, 368, 337, 306, 275, 244, 213, 182, 151, 120,
|
||||
89, 58, 27, 865, 834, 803, 741, 710, 679, 617, 586, 555, 493,
|
||||
462, 431, 369, 338, 307, 245, 214, 183, 121, 90, 59, 866, 835,
|
||||
742, 711, 618, 587, 494, 463, 370, 339, 246, 215, 122, 91, 867,
|
||||
743, 619, 495, 371, 247, 123, 896, 772, 648, 524, 400, 276, 152,
|
||||
28, 928, 897, 804, 773, 680, 649, 556, 525, 432, 401, 308, 277,
|
||||
184, 153, 60, 29, 960, 929, 898, 836, 805, 774, 712, 681, 650,
|
||||
588, 557, 526, 464, 433, 402, 340, 309, 278, 216, 185, 154, 92,
|
||||
61, 30, 992, 961, 930, 899, 868, 837, 806, 775, 744, 713, 682,
|
||||
651, 620, 589, 558, 527, 496, 465, 434, 403, 372, 341, 310, 279,
|
||||
248, 217, 186, 155, 124, 93, 62, 31, 993, 962, 931, 869, 838,
|
||||
807, 745, 714, 683, 621, 590, 559, 497, 466, 435, 373, 342, 311,
|
||||
249, 218, 187, 125, 94, 63, 994, 963, 870, 839, 746, 715, 622,
|
||||
591, 498, 467, 374, 343, 250, 219, 126, 95, 995, 871, 747, 623,
|
||||
499, 375, 251, 127, 900, 776, 652, 528, 404, 280, 156, 932, 901,
|
||||
808, 777, 684, 653, 560, 529, 436, 405, 312, 281, 188, 157, 964,
|
||||
933, 902, 840, 809, 778, 716, 685, 654, 592, 561, 530, 468, 437,
|
||||
406, 344, 313, 282, 220, 189, 158, 996, 965, 934, 903, 872, 841,
|
||||
810, 779, 748, 717, 686, 655, 624, 593, 562, 531, 500, 469, 438,
|
||||
407, 376, 345, 314, 283, 252, 221, 190, 159, 997, 966, 935, 873,
|
||||
842, 811, 749, 718, 687, 625, 594, 563, 501, 470, 439, 377, 346,
|
||||
315, 253, 222, 191, 998, 967, 874, 843, 750, 719, 626, 595, 502,
|
||||
471, 378, 347, 254, 223, 999, 875, 751, 627, 503, 379, 255, 904,
|
||||
780, 656, 532, 408, 284, 936, 905, 812, 781, 688, 657, 564, 533,
|
||||
440, 409, 316, 285, 968, 937, 906, 844, 813, 782, 720, 689, 658,
|
||||
596, 565, 534, 472, 441, 410, 348, 317, 286, 1000, 969, 938, 907,
|
||||
876, 845, 814, 783, 752, 721, 690, 659, 628, 597, 566, 535, 504,
|
||||
473, 442, 411, 380, 349, 318, 287, 1001, 970, 939, 877, 846, 815,
|
||||
753, 722, 691, 629, 598, 567, 505, 474, 443, 381, 350, 319, 1002,
|
||||
971, 878, 847, 754, 723, 630, 599, 506, 475, 382, 351, 1003, 879,
|
||||
755, 631, 507, 383, 908, 784, 660, 536, 412, 940, 909, 816, 785,
|
||||
692, 661, 568, 537, 444, 413, 972, 941, 910, 848, 817, 786, 724,
|
||||
693, 662, 600, 569, 538, 476, 445, 414, 1004, 973, 942, 911, 880,
|
||||
849, 818, 787, 756, 725, 694, 663, 632, 601, 570, 539, 508, 477,
|
||||
446, 415, 1005, 974, 943, 881, 850, 819, 757, 726, 695, 633, 602,
|
||||
571, 509, 478, 447, 1006, 975, 882, 851, 758, 727, 634, 603, 510,
|
||||
479, 1007, 883, 759, 635, 511, 912, 788, 664, 540, 944, 913, 820,
|
||||
789, 696, 665, 572, 541, 976, 945, 914, 852, 821, 790, 728, 697,
|
||||
666, 604, 573, 542, 1008, 977, 946, 915, 884, 853, 822, 791, 760,
|
||||
729, 698, 667, 636, 605, 574, 543, 1009, 978, 947, 885, 854, 823,
|
||||
761, 730, 699, 637, 606, 575, 1010, 979, 886, 855, 762, 731, 638,
|
||||
607, 1011, 887, 763, 639, 916, 792, 668, 948, 917, 824, 793, 700,
|
||||
669, 980, 949, 918, 856, 825, 794, 732, 701, 670, 1012, 981, 950,
|
||||
919, 888, 857, 826, 795, 764, 733, 702, 671, 1013, 982, 951, 889,
|
||||
858, 827, 765, 734, 703, 1014, 983, 890, 859, 766, 735, 1015, 891,
|
||||
767, 920, 796, 952, 921, 828, 797, 984, 953, 922, 860, 829, 798,
|
||||
1016, 985, 954, 923, 892, 861, 830, 799, 1017, 986, 955, 893, 862,
|
||||
831, 1018, 987, 894, 863, 1019, 895, 924, 956, 925, 988, 957, 926,
|
||||
1020, 989, 958, 927, 1021, 990, 959, 1022, 991, 1023,
|
||||
};
|
||||
|
||||
// Neighborhood 2-tuples for various scans and blocksizes,
|
||||
// in {top, left} order for each position in corresponding scan order.
|
||||
DECLARE_ALIGNED(16, static const int16_t,
|
||||
default_scan_4x4_neighbors[17 * MAX_NEIGHBORS]) = {
|
||||
0, 0, 0, 0, 0, 0, 1, 4, 4, 4, 1, 1, 8, 8, 5, 8, 2,
|
||||
2, 2, 5, 9, 12, 6, 9, 3, 6, 10, 13, 7, 10, 11, 14, 0, 0,
|
||||
};
|
||||
|
||||
DECLARE_ALIGNED(16, static const int16_t,
|
||||
col_scan_4x4_neighbors[17 * MAX_NEIGHBORS]) = {
|
||||
0, 0, 0, 0, 4, 4, 0, 0, 8, 8, 1, 1, 5, 5, 1, 1, 9,
|
||||
9, 2, 2, 6, 6, 2, 2, 3, 3, 10, 10, 7, 7, 11, 11, 0, 0,
|
||||
};
|
||||
|
||||
DECLARE_ALIGNED(16, static const int16_t,
|
||||
row_scan_4x4_neighbors[17 * MAX_NEIGHBORS]) = {
|
||||
0, 0, 0, 0, 0, 0, 1, 1, 4, 4, 2, 2, 5, 5, 4, 4, 8,
|
||||
8, 6, 6, 8, 8, 9, 9, 12, 12, 10, 10, 13, 13, 14, 14, 0, 0,
|
||||
};
|
||||
|
||||
DECLARE_ALIGNED(16, static const int16_t,
|
||||
col_scan_8x8_neighbors[65 * MAX_NEIGHBORS]) = {
|
||||
0, 0, 0, 0, 8, 8, 0, 0, 16, 16, 1, 1, 24, 24, 9, 9, 1, 1, 32,
|
||||
32, 17, 17, 2, 2, 25, 25, 10, 10, 40, 40, 2, 2, 18, 18, 33, 33, 3, 3,
|
||||
48, 48, 11, 11, 26, 26, 3, 3, 41, 41, 19, 19, 34, 34, 4, 4, 27, 27, 12,
|
||||
12, 49, 49, 42, 42, 20, 20, 4, 4, 35, 35, 5, 5, 28, 28, 50, 50, 43, 43,
|
||||
13, 13, 36, 36, 5, 5, 21, 21, 51, 51, 29, 29, 6, 6, 44, 44, 14, 14, 6,
|
||||
6, 37, 37, 52, 52, 22, 22, 7, 7, 30, 30, 45, 45, 15, 15, 38, 38, 23, 23,
|
||||
53, 53, 31, 31, 46, 46, 39, 39, 54, 54, 47, 47, 55, 55, 0, 0,
|
||||
};
|
||||
|
||||
DECLARE_ALIGNED(16, static const int16_t,
|
||||
row_scan_8x8_neighbors[65 * MAX_NEIGHBORS]) = {
|
||||
0, 0, 0, 0, 1, 1, 0, 0, 8, 8, 2, 2, 8, 8, 9, 9, 3, 3, 16,
|
||||
16, 10, 10, 16, 16, 4, 4, 17, 17, 24, 24, 11, 11, 18, 18, 25, 25, 24, 24,
|
||||
5, 5, 12, 12, 19, 19, 32, 32, 26, 26, 6, 6, 33, 33, 32, 32, 20, 20, 27,
|
||||
27, 40, 40, 13, 13, 34, 34, 40, 40, 41, 41, 28, 28, 35, 35, 48, 48, 21, 21,
|
||||
42, 42, 14, 14, 48, 48, 36, 36, 49, 49, 43, 43, 29, 29, 56, 56, 22, 22, 50,
|
||||
50, 57, 57, 44, 44, 37, 37, 51, 51, 30, 30, 58, 58, 52, 52, 45, 45, 59, 59,
|
||||
38, 38, 60, 60, 46, 46, 53, 53, 54, 54, 61, 61, 62, 62, 0, 0,
|
||||
};
|
||||
|
||||
DECLARE_ALIGNED(16, static const int16_t,
|
||||
default_scan_8x8_neighbors[65 * MAX_NEIGHBORS]) = {
|
||||
0, 0, 0, 0, 0, 0, 8, 8, 1, 8, 1, 1, 9, 16, 16, 16, 2, 9, 2,
|
||||
2, 10, 17, 17, 24, 24, 24, 3, 10, 3, 3, 18, 25, 25, 32, 11, 18, 32, 32,
|
||||
4, 11, 26, 33, 19, 26, 4, 4, 33, 40, 12, 19, 40, 40, 5, 12, 27, 34, 34,
|
||||
41, 20, 27, 13, 20, 5, 5, 41, 48, 48, 48, 28, 35, 35, 42, 21, 28, 6, 6,
|
||||
6, 13, 42, 49, 49, 56, 36, 43, 14, 21, 29, 36, 7, 14, 43, 50, 50, 57, 22,
|
||||
29, 37, 44, 15, 22, 44, 51, 51, 58, 30, 37, 23, 30, 52, 59, 45, 52, 38, 45,
|
||||
31, 38, 53, 60, 46, 53, 39, 46, 54, 61, 47, 54, 55, 62, 0, 0,
|
||||
};
|
||||
|
||||
DECLARE_ALIGNED(16, static const int16_t,
|
||||
col_scan_16x16_neighbors[257 * MAX_NEIGHBORS]) = {
|
||||
0, 0, 0, 0, 16, 16, 32, 32, 0, 0, 48, 48, 1, 1, 64,
|
||||
64, 17, 17, 80, 80, 33, 33, 1, 1, 49, 49, 96, 96, 2, 2,
|
||||
65, 65, 18, 18, 112, 112, 34, 34, 81, 81, 2, 2, 50, 50, 128,
|
||||
128, 3, 3, 97, 97, 19, 19, 66, 66, 144, 144, 82, 82, 35, 35,
|
||||
113, 113, 3, 3, 51, 51, 160, 160, 4, 4, 98, 98, 129, 129, 67,
|
||||
67, 20, 20, 83, 83, 114, 114, 36, 36, 176, 176, 4, 4, 145, 145,
|
||||
52, 52, 99, 99, 5, 5, 130, 130, 68, 68, 192, 192, 161, 161, 21,
|
||||
21, 115, 115, 84, 84, 37, 37, 146, 146, 208, 208, 53, 53, 5, 5,
|
||||
100, 100, 177, 177, 131, 131, 69, 69, 6, 6, 224, 224, 116, 116, 22,
|
||||
22, 162, 162, 85, 85, 147, 147, 38, 38, 193, 193, 101, 101, 54, 54,
|
||||
6, 6, 132, 132, 178, 178, 70, 70, 163, 163, 209, 209, 7, 7, 117,
|
||||
117, 23, 23, 148, 148, 7, 7, 86, 86, 194, 194, 225, 225, 39, 39,
|
||||
179, 179, 102, 102, 133, 133, 55, 55, 164, 164, 8, 8, 71, 71, 210,
|
||||
210, 118, 118, 149, 149, 195, 195, 24, 24, 87, 87, 40, 40, 56, 56,
|
||||
134, 134, 180, 180, 226, 226, 103, 103, 8, 8, 165, 165, 211, 211, 72,
|
||||
72, 150, 150, 9, 9, 119, 119, 25, 25, 88, 88, 196, 196, 41, 41,
|
||||
135, 135, 181, 181, 104, 104, 57, 57, 227, 227, 166, 166, 120, 120, 151,
|
||||
151, 197, 197, 73, 73, 9, 9, 212, 212, 89, 89, 136, 136, 182, 182,
|
||||
10, 10, 26, 26, 105, 105, 167, 167, 228, 228, 152, 152, 42, 42, 121,
|
||||
121, 213, 213, 58, 58, 198, 198, 74, 74, 137, 137, 183, 183, 168, 168,
|
||||
10, 10, 90, 90, 229, 229, 11, 11, 106, 106, 214, 214, 153, 153, 27,
|
||||
27, 199, 199, 43, 43, 184, 184, 122, 122, 169, 169, 230, 230, 59, 59,
|
||||
11, 11, 75, 75, 138, 138, 200, 200, 215, 215, 91, 91, 12, 12, 28,
|
||||
28, 185, 185, 107, 107, 154, 154, 44, 44, 231, 231, 216, 216, 60, 60,
|
||||
123, 123, 12, 12, 76, 76, 201, 201, 170, 170, 232, 232, 139, 139, 92,
|
||||
92, 13, 13, 108, 108, 29, 29, 186, 186, 217, 217, 155, 155, 45, 45,
|
||||
13, 13, 61, 61, 124, 124, 14, 14, 233, 233, 77, 77, 14, 14, 171,
|
||||
171, 140, 140, 202, 202, 30, 30, 93, 93, 109, 109, 46, 46, 156, 156,
|
||||
62, 62, 187, 187, 15, 15, 125, 125, 218, 218, 78, 78, 31, 31, 172,
|
||||
172, 47, 47, 141, 141, 94, 94, 234, 234, 203, 203, 63, 63, 110, 110,
|
||||
188, 188, 157, 157, 126, 126, 79, 79, 173, 173, 95, 95, 219, 219, 142,
|
||||
142, 204, 204, 235, 235, 111, 111, 158, 158, 127, 127, 189, 189, 220, 220,
|
||||
143, 143, 174, 174, 205, 205, 236, 236, 159, 159, 190, 190, 221, 221, 175,
|
||||
175, 237, 237, 206, 206, 222, 222, 191, 191, 238, 238, 207, 207, 223, 223,
|
||||
239, 239, 0, 0,
|
||||
};
|
||||
|
||||
DECLARE_ALIGNED(16, static const int16_t,
|
||||
row_scan_16x16_neighbors[257 * MAX_NEIGHBORS]) = {
|
||||
0, 0, 0, 0, 1, 1, 0, 0, 2, 2, 16, 16, 3, 3, 17,
|
||||
17, 16, 16, 4, 4, 32, 32, 18, 18, 5, 5, 33, 33, 32, 32,
|
||||
19, 19, 48, 48, 6, 6, 34, 34, 20, 20, 49, 49, 48, 48, 7,
|
||||
7, 35, 35, 64, 64, 21, 21, 50, 50, 36, 36, 64, 64, 8, 8,
|
||||
65, 65, 51, 51, 22, 22, 37, 37, 80, 80, 66, 66, 9, 9, 52,
|
||||
52, 23, 23, 81, 81, 67, 67, 80, 80, 38, 38, 10, 10, 53, 53,
|
||||
82, 82, 96, 96, 68, 68, 24, 24, 97, 97, 83, 83, 39, 39, 96,
|
||||
96, 54, 54, 11, 11, 69, 69, 98, 98, 112, 112, 84, 84, 25, 25,
|
||||
40, 40, 55, 55, 113, 113, 99, 99, 12, 12, 70, 70, 112, 112, 85,
|
||||
85, 26, 26, 114, 114, 100, 100, 128, 128, 41, 41, 56, 56, 71, 71,
|
||||
115, 115, 13, 13, 86, 86, 129, 129, 101, 101, 128, 128, 72, 72, 130,
|
||||
130, 116, 116, 27, 27, 57, 57, 14, 14, 87, 87, 42, 42, 144, 144,
|
||||
102, 102, 131, 131, 145, 145, 117, 117, 73, 73, 144, 144, 88, 88, 132,
|
||||
132, 103, 103, 28, 28, 58, 58, 146, 146, 118, 118, 43, 43, 160, 160,
|
||||
147, 147, 89, 89, 104, 104, 133, 133, 161, 161, 119, 119, 160, 160, 74,
|
||||
74, 134, 134, 148, 148, 29, 29, 59, 59, 162, 162, 176, 176, 44, 44,
|
||||
120, 120, 90, 90, 105, 105, 163, 163, 177, 177, 149, 149, 176, 176, 135,
|
||||
135, 164, 164, 178, 178, 30, 30, 150, 150, 192, 192, 75, 75, 121, 121,
|
||||
60, 60, 136, 136, 193, 193, 106, 106, 151, 151, 179, 179, 192, 192, 45,
|
||||
45, 165, 165, 166, 166, 194, 194, 91, 91, 180, 180, 137, 137, 208, 208,
|
||||
122, 122, 152, 152, 208, 208, 195, 195, 76, 76, 167, 167, 209, 209, 181,
|
||||
181, 224, 224, 107, 107, 196, 196, 61, 61, 153, 153, 224, 224, 182, 182,
|
||||
168, 168, 210, 210, 46, 46, 138, 138, 92, 92, 183, 183, 225, 225, 211,
|
||||
211, 240, 240, 197, 197, 169, 169, 123, 123, 154, 154, 198, 198, 77, 77,
|
||||
212, 212, 184, 184, 108, 108, 226, 226, 199, 199, 62, 62, 227, 227, 241,
|
||||
241, 139, 139, 213, 213, 170, 170, 185, 185, 155, 155, 228, 228, 242, 242,
|
||||
124, 124, 93, 93, 200, 200, 243, 243, 214, 214, 215, 215, 229, 229, 140,
|
||||
140, 186, 186, 201, 201, 78, 78, 171, 171, 109, 109, 156, 156, 244, 244,
|
||||
216, 216, 230, 230, 94, 94, 245, 245, 231, 231, 125, 125, 202, 202, 246,
|
||||
246, 232, 232, 172, 172, 217, 217, 141, 141, 110, 110, 157, 157, 187, 187,
|
||||
247, 247, 126, 126, 233, 233, 218, 218, 248, 248, 188, 188, 203, 203, 142,
|
||||
142, 173, 173, 158, 158, 249, 249, 234, 234, 204, 204, 219, 219, 174, 174,
|
||||
189, 189, 250, 250, 220, 220, 190, 190, 205, 205, 235, 235, 206, 206, 236,
|
||||
236, 251, 251, 221, 221, 252, 252, 222, 222, 237, 237, 238, 238, 253, 253,
|
||||
254, 254, 0, 0,
|
||||
};
|
||||
|
||||
DECLARE_ALIGNED(16, static const int16_t,
|
||||
default_scan_16x16_neighbors[257 * MAX_NEIGHBORS]) = {
|
||||
0, 0, 0, 0, 0, 0, 16, 16, 1, 16, 1, 1, 32, 32, 17,
|
||||
32, 2, 17, 2, 2, 48, 48, 18, 33, 33, 48, 3, 18, 49, 64,
|
||||
64, 64, 34, 49, 3, 3, 19, 34, 50, 65, 4, 19, 65, 80, 80,
|
||||
80, 35, 50, 4, 4, 20, 35, 66, 81, 81, 96, 51, 66, 96, 96,
|
||||
5, 20, 36, 51, 82, 97, 21, 36, 67, 82, 97, 112, 5, 5, 52,
|
||||
67, 112, 112, 37, 52, 6, 21, 83, 98, 98, 113, 68, 83, 6, 6,
|
||||
113, 128, 22, 37, 53, 68, 84, 99, 99, 114, 128, 128, 114, 129, 69,
|
||||
84, 38, 53, 7, 22, 7, 7, 129, 144, 23, 38, 54, 69, 100, 115,
|
||||
85, 100, 115, 130, 144, 144, 130, 145, 39, 54, 70, 85, 8, 23, 55,
|
||||
70, 116, 131, 101, 116, 145, 160, 24, 39, 8, 8, 86, 101, 131, 146,
|
||||
160, 160, 146, 161, 71, 86, 40, 55, 9, 24, 117, 132, 102, 117, 161,
|
||||
176, 132, 147, 56, 71, 87, 102, 25, 40, 147, 162, 9, 9, 176, 176,
|
||||
162, 177, 72, 87, 41, 56, 118, 133, 133, 148, 103, 118, 10, 25, 148,
|
||||
163, 57, 72, 88, 103, 177, 192, 26, 41, 163, 178, 192, 192, 10, 10,
|
||||
119, 134, 73, 88, 149, 164, 104, 119, 134, 149, 42, 57, 178, 193, 164,
|
||||
179, 11, 26, 58, 73, 193, 208, 89, 104, 135, 150, 120, 135, 27, 42,
|
||||
74, 89, 208, 208, 150, 165, 179, 194, 165, 180, 105, 120, 194, 209, 43,
|
||||
58, 11, 11, 136, 151, 90, 105, 151, 166, 180, 195, 59, 74, 121, 136,
|
||||
209, 224, 195, 210, 224, 224, 166, 181, 106, 121, 75, 90, 12, 27, 181,
|
||||
196, 12, 12, 210, 225, 152, 167, 167, 182, 137, 152, 28, 43, 196, 211,
|
||||
122, 137, 91, 106, 225, 240, 44, 59, 13, 28, 107, 122, 182, 197, 168,
|
||||
183, 211, 226, 153, 168, 226, 241, 60, 75, 197, 212, 138, 153, 29, 44,
|
||||
76, 91, 13, 13, 183, 198, 123, 138, 45, 60, 212, 227, 198, 213, 154,
|
||||
169, 169, 184, 227, 242, 92, 107, 61, 76, 139, 154, 14, 29, 14, 14,
|
||||
184, 199, 213, 228, 108, 123, 199, 214, 228, 243, 77, 92, 30, 45, 170,
|
||||
185, 155, 170, 185, 200, 93, 108, 124, 139, 214, 229, 46, 61, 200, 215,
|
||||
229, 244, 15, 30, 109, 124, 62, 77, 140, 155, 215, 230, 31, 46, 171,
|
||||
186, 186, 201, 201, 216, 78, 93, 230, 245, 125, 140, 47, 62, 216, 231,
|
||||
156, 171, 94, 109, 231, 246, 141, 156, 63, 78, 202, 217, 187, 202, 110,
|
||||
125, 217, 232, 172, 187, 232, 247, 79, 94, 157, 172, 126, 141, 203, 218,
|
||||
95, 110, 233, 248, 218, 233, 142, 157, 111, 126, 173, 188, 188, 203, 234,
|
||||
249, 219, 234, 127, 142, 158, 173, 204, 219, 189, 204, 143, 158, 235, 250,
|
||||
174, 189, 205, 220, 159, 174, 220, 235, 221, 236, 175, 190, 190, 205, 236,
|
||||
251, 206, 221, 237, 252, 191, 206, 222, 237, 207, 222, 238, 253, 223, 238,
|
||||
239, 254, 0, 0,
|
||||
};
|
||||
|
||||
DECLARE_ALIGNED(16, static const int16_t,
|
||||
default_scan_32x32_neighbors[1025 * MAX_NEIGHBORS]) = {
|
||||
0, 0, 0, 0, 0, 0, 32, 32, 1, 32, 1, 1, 64, 64,
|
||||
33, 64, 2, 33, 96, 96, 2, 2, 65, 96, 34, 65, 128, 128,
|
||||
97, 128, 3, 34, 66, 97, 3, 3, 35, 66, 98, 129, 129, 160,
|
||||
160, 160, 4, 35, 67, 98, 192, 192, 4, 4, 130, 161, 161, 192,
|
||||
36, 67, 99, 130, 5, 36, 68, 99, 193, 224, 162, 193, 224, 224,
|
||||
131, 162, 37, 68, 100, 131, 5, 5, 194, 225, 225, 256, 256, 256,
|
||||
163, 194, 69, 100, 132, 163, 6, 37, 226, 257, 6, 6, 195, 226,
|
||||
257, 288, 101, 132, 288, 288, 38, 69, 164, 195, 133, 164, 258, 289,
|
||||
227, 258, 196, 227, 7, 38, 289, 320, 70, 101, 320, 320, 7, 7,
|
||||
165, 196, 39, 70, 102, 133, 290, 321, 259, 290, 228, 259, 321, 352,
|
||||
352, 352, 197, 228, 134, 165, 71, 102, 8, 39, 322, 353, 291, 322,
|
||||
260, 291, 103, 134, 353, 384, 166, 197, 229, 260, 40, 71, 8, 8,
|
||||
384, 384, 135, 166, 354, 385, 323, 354, 198, 229, 292, 323, 72, 103,
|
||||
261, 292, 9, 40, 385, 416, 167, 198, 104, 135, 230, 261, 355, 386,
|
||||
416, 416, 293, 324, 324, 355, 9, 9, 41, 72, 386, 417, 199, 230,
|
||||
136, 167, 417, 448, 262, 293, 356, 387, 73, 104, 387, 418, 231, 262,
|
||||
10, 41, 168, 199, 325, 356, 418, 449, 105, 136, 448, 448, 42, 73,
|
||||
294, 325, 200, 231, 10, 10, 357, 388, 137, 168, 263, 294, 388, 419,
|
||||
74, 105, 419, 450, 449, 480, 326, 357, 232, 263, 295, 326, 169, 200,
|
||||
11, 42, 106, 137, 480, 480, 450, 481, 358, 389, 264, 295, 201, 232,
|
||||
138, 169, 389, 420, 43, 74, 420, 451, 327, 358, 11, 11, 481, 512,
|
||||
233, 264, 451, 482, 296, 327, 75, 106, 170, 201, 482, 513, 512, 512,
|
||||
390, 421, 359, 390, 421, 452, 107, 138, 12, 43, 202, 233, 452, 483,
|
||||
265, 296, 328, 359, 139, 170, 44, 75, 483, 514, 513, 544, 234, 265,
|
||||
297, 328, 422, 453, 12, 12, 391, 422, 171, 202, 76, 107, 514, 545,
|
||||
453, 484, 544, 544, 266, 297, 203, 234, 108, 139, 329, 360, 298, 329,
|
||||
140, 171, 515, 546, 13, 44, 423, 454, 235, 266, 545, 576, 454, 485,
|
||||
45, 76, 172, 203, 330, 361, 576, 576, 13, 13, 267, 298, 546, 577,
|
||||
77, 108, 204, 235, 455, 486, 577, 608, 299, 330, 109, 140, 547, 578,
|
||||
14, 45, 14, 14, 141, 172, 578, 609, 331, 362, 46, 77, 173, 204,
|
||||
15, 15, 78, 109, 205, 236, 579, 610, 110, 141, 15, 46, 142, 173,
|
||||
47, 78, 174, 205, 16, 16, 79, 110, 206, 237, 16, 47, 111, 142,
|
||||
48, 79, 143, 174, 80, 111, 175, 206, 17, 48, 17, 17, 207, 238,
|
||||
49, 80, 81, 112, 18, 18, 18, 49, 50, 81, 82, 113, 19, 50,
|
||||
51, 82, 83, 114, 608, 608, 484, 515, 360, 391, 236, 267, 112, 143,
|
||||
19, 19, 640, 640, 609, 640, 516, 547, 485, 516, 392, 423, 361, 392,
|
||||
268, 299, 237, 268, 144, 175, 113, 144, 20, 51, 20, 20, 672, 672,
|
||||
641, 672, 610, 641, 548, 579, 517, 548, 486, 517, 424, 455, 393, 424,
|
||||
362, 393, 300, 331, 269, 300, 238, 269, 176, 207, 145, 176, 114, 145,
|
||||
52, 83, 21, 52, 21, 21, 704, 704, 673, 704, 642, 673, 611, 642,
|
||||
580, 611, 549, 580, 518, 549, 487, 518, 456, 487, 425, 456, 394, 425,
|
||||
363, 394, 332, 363, 301, 332, 270, 301, 239, 270, 208, 239, 177, 208,
|
||||
146, 177, 115, 146, 84, 115, 53, 84, 22, 53, 22, 22, 705, 736,
|
||||
674, 705, 643, 674, 581, 612, 550, 581, 519, 550, 457, 488, 426, 457,
|
||||
395, 426, 333, 364, 302, 333, 271, 302, 209, 240, 178, 209, 147, 178,
|
||||
85, 116, 54, 85, 23, 54, 706, 737, 675, 706, 582, 613, 551, 582,
|
||||
458, 489, 427, 458, 334, 365, 303, 334, 210, 241, 179, 210, 86, 117,
|
||||
55, 86, 707, 738, 583, 614, 459, 490, 335, 366, 211, 242, 87, 118,
|
||||
736, 736, 612, 643, 488, 519, 364, 395, 240, 271, 116, 147, 23, 23,
|
||||
768, 768, 737, 768, 644, 675, 613, 644, 520, 551, 489, 520, 396, 427,
|
||||
365, 396, 272, 303, 241, 272, 148, 179, 117, 148, 24, 55, 24, 24,
|
||||
800, 800, 769, 800, 738, 769, 676, 707, 645, 676, 614, 645, 552, 583,
|
||||
521, 552, 490, 521, 428, 459, 397, 428, 366, 397, 304, 335, 273, 304,
|
||||
242, 273, 180, 211, 149, 180, 118, 149, 56, 87, 25, 56, 25, 25,
|
||||
832, 832, 801, 832, 770, 801, 739, 770, 708, 739, 677, 708, 646, 677,
|
||||
615, 646, 584, 615, 553, 584, 522, 553, 491, 522, 460, 491, 429, 460,
|
||||
398, 429, 367, 398, 336, 367, 305, 336, 274, 305, 243, 274, 212, 243,
|
||||
181, 212, 150, 181, 119, 150, 88, 119, 57, 88, 26, 57, 26, 26,
|
||||
833, 864, 802, 833, 771, 802, 709, 740, 678, 709, 647, 678, 585, 616,
|
||||
554, 585, 523, 554, 461, 492, 430, 461, 399, 430, 337, 368, 306, 337,
|
||||
275, 306, 213, 244, 182, 213, 151, 182, 89, 120, 58, 89, 27, 58,
|
||||
834, 865, 803, 834, 710, 741, 679, 710, 586, 617, 555, 586, 462, 493,
|
||||
431, 462, 338, 369, 307, 338, 214, 245, 183, 214, 90, 121, 59, 90,
|
||||
835, 866, 711, 742, 587, 618, 463, 494, 339, 370, 215, 246, 91, 122,
|
||||
864, 864, 740, 771, 616, 647, 492, 523, 368, 399, 244, 275, 120, 151,
|
||||
27, 27, 896, 896, 865, 896, 772, 803, 741, 772, 648, 679, 617, 648,
|
||||
524, 555, 493, 524, 400, 431, 369, 400, 276, 307, 245, 276, 152, 183,
|
||||
121, 152, 28, 59, 28, 28, 928, 928, 897, 928, 866, 897, 804, 835,
|
||||
773, 804, 742, 773, 680, 711, 649, 680, 618, 649, 556, 587, 525, 556,
|
||||
494, 525, 432, 463, 401, 432, 370, 401, 308, 339, 277, 308, 246, 277,
|
||||
184, 215, 153, 184, 122, 153, 60, 91, 29, 60, 29, 29, 960, 960,
|
||||
929, 960, 898, 929, 867, 898, 836, 867, 805, 836, 774, 805, 743, 774,
|
||||
712, 743, 681, 712, 650, 681, 619, 650, 588, 619, 557, 588, 526, 557,
|
||||
495, 526, 464, 495, 433, 464, 402, 433, 371, 402, 340, 371, 309, 340,
|
||||
278, 309, 247, 278, 216, 247, 185, 216, 154, 185, 123, 154, 92, 123,
|
||||
61, 92, 30, 61, 30, 30, 961, 992, 930, 961, 899, 930, 837, 868,
|
||||
806, 837, 775, 806, 713, 744, 682, 713, 651, 682, 589, 620, 558, 589,
|
||||
527, 558, 465, 496, 434, 465, 403, 434, 341, 372, 310, 341, 279, 310,
|
||||
217, 248, 186, 217, 155, 186, 93, 124, 62, 93, 31, 62, 962, 993,
|
||||
931, 962, 838, 869, 807, 838, 714, 745, 683, 714, 590, 621, 559, 590,
|
||||
466, 497, 435, 466, 342, 373, 311, 342, 218, 249, 187, 218, 94, 125,
|
||||
63, 94, 963, 994, 839, 870, 715, 746, 591, 622, 467, 498, 343, 374,
|
||||
219, 250, 95, 126, 868, 899, 744, 775, 620, 651, 496, 527, 372, 403,
|
||||
248, 279, 124, 155, 900, 931, 869, 900, 776, 807, 745, 776, 652, 683,
|
||||
621, 652, 528, 559, 497, 528, 404, 435, 373, 404, 280, 311, 249, 280,
|
||||
156, 187, 125, 156, 932, 963, 901, 932, 870, 901, 808, 839, 777, 808,
|
||||
746, 777, 684, 715, 653, 684, 622, 653, 560, 591, 529, 560, 498, 529,
|
||||
436, 467, 405, 436, 374, 405, 312, 343, 281, 312, 250, 281, 188, 219,
|
||||
157, 188, 126, 157, 964, 995, 933, 964, 902, 933, 871, 902, 840, 871,
|
||||
809, 840, 778, 809, 747, 778, 716, 747, 685, 716, 654, 685, 623, 654,
|
||||
592, 623, 561, 592, 530, 561, 499, 530, 468, 499, 437, 468, 406, 437,
|
||||
375, 406, 344, 375, 313, 344, 282, 313, 251, 282, 220, 251, 189, 220,
|
||||
158, 189, 127, 158, 965, 996, 934, 965, 903, 934, 841, 872, 810, 841,
|
||||
779, 810, 717, 748, 686, 717, 655, 686, 593, 624, 562, 593, 531, 562,
|
||||
469, 500, 438, 469, 407, 438, 345, 376, 314, 345, 283, 314, 221, 252,
|
||||
190, 221, 159, 190, 966, 997, 935, 966, 842, 873, 811, 842, 718, 749,
|
||||
687, 718, 594, 625, 563, 594, 470, 501, 439, 470, 346, 377, 315, 346,
|
||||
222, 253, 191, 222, 967, 998, 843, 874, 719, 750, 595, 626, 471, 502,
|
||||
347, 378, 223, 254, 872, 903, 748, 779, 624, 655, 500, 531, 376, 407,
|
||||
252, 283, 904, 935, 873, 904, 780, 811, 749, 780, 656, 687, 625, 656,
|
||||
532, 563, 501, 532, 408, 439, 377, 408, 284, 315, 253, 284, 936, 967,
|
||||
905, 936, 874, 905, 812, 843, 781, 812, 750, 781, 688, 719, 657, 688,
|
||||
626, 657, 564, 595, 533, 564, 502, 533, 440, 471, 409, 440, 378, 409,
|
||||
316, 347, 285, 316, 254, 285, 968, 999, 937, 968, 906, 937, 875, 906,
|
||||
844, 875, 813, 844, 782, 813, 751, 782, 720, 751, 689, 720, 658, 689,
|
||||
627, 658, 596, 627, 565, 596, 534, 565, 503, 534, 472, 503, 441, 472,
|
||||
410, 441, 379, 410, 348, 379, 317, 348, 286, 317, 255, 286, 969, 1000,
|
||||
938, 969, 907, 938, 845, 876, 814, 845, 783, 814, 721, 752, 690, 721,
|
||||
659, 690, 597, 628, 566, 597, 535, 566, 473, 504, 442, 473, 411, 442,
|
||||
349, 380, 318, 349, 287, 318, 970, 1001, 939, 970, 846, 877, 815, 846,
|
||||
722, 753, 691, 722, 598, 629, 567, 598, 474, 505, 443, 474, 350, 381,
|
||||
319, 350, 971, 1002, 847, 878, 723, 754, 599, 630, 475, 506, 351, 382,
|
||||
876, 907, 752, 783, 628, 659, 504, 535, 380, 411, 908, 939, 877, 908,
|
||||
784, 815, 753, 784, 660, 691, 629, 660, 536, 567, 505, 536, 412, 443,
|
||||
381, 412, 940, 971, 909, 940, 878, 909, 816, 847, 785, 816, 754, 785,
|
||||
692, 723, 661, 692, 630, 661, 568, 599, 537, 568, 506, 537, 444, 475,
|
||||
413, 444, 382, 413, 972, 1003, 941, 972, 910, 941, 879, 910, 848, 879,
|
||||
817, 848, 786, 817, 755, 786, 724, 755, 693, 724, 662, 693, 631, 662,
|
||||
600, 631, 569, 600, 538, 569, 507, 538, 476, 507, 445, 476, 414, 445,
|
||||
383, 414, 973, 1004, 942, 973, 911, 942, 849, 880, 818, 849, 787, 818,
|
||||
725, 756, 694, 725, 663, 694, 601, 632, 570, 601, 539, 570, 477, 508,
|
||||
446, 477, 415, 446, 974, 1005, 943, 974, 850, 881, 819, 850, 726, 757,
|
||||
695, 726, 602, 633, 571, 602, 478, 509, 447, 478, 975, 1006, 851, 882,
|
||||
727, 758, 603, 634, 479, 510, 880, 911, 756, 787, 632, 663, 508, 539,
|
||||
912, 943, 881, 912, 788, 819, 757, 788, 664, 695, 633, 664, 540, 571,
|
||||
509, 540, 944, 975, 913, 944, 882, 913, 820, 851, 789, 820, 758, 789,
|
||||
696, 727, 665, 696, 634, 665, 572, 603, 541, 572, 510, 541, 976, 1007,
|
||||
945, 976, 914, 945, 883, 914, 852, 883, 821, 852, 790, 821, 759, 790,
|
||||
728, 759, 697, 728, 666, 697, 635, 666, 604, 635, 573, 604, 542, 573,
|
||||
511, 542, 977, 1008, 946, 977, 915, 946, 853, 884, 822, 853, 791, 822,
|
||||
729, 760, 698, 729, 667, 698, 605, 636, 574, 605, 543, 574, 978, 1009,
|
||||
947, 978, 854, 885, 823, 854, 730, 761, 699, 730, 606, 637, 575, 606,
|
||||
979, 1010, 855, 886, 731, 762, 607, 638, 884, 915, 760, 791, 636, 667,
|
||||
916, 947, 885, 916, 792, 823, 761, 792, 668, 699, 637, 668, 948, 979,
|
||||
917, 948, 886, 917, 824, 855, 793, 824, 762, 793, 700, 731, 669, 700,
|
||||
638, 669, 980, 1011, 949, 980, 918, 949, 887, 918, 856, 887, 825, 856,
|
||||
794, 825, 763, 794, 732, 763, 701, 732, 670, 701, 639, 670, 981, 1012,
|
||||
950, 981, 919, 950, 857, 888, 826, 857, 795, 826, 733, 764, 702, 733,
|
||||
671, 702, 982, 1013, 951, 982, 858, 889, 827, 858, 734, 765, 703, 734,
|
||||
983, 1014, 859, 890, 735, 766, 888, 919, 764, 795, 920, 951, 889, 920,
|
||||
796, 827, 765, 796, 952, 983, 921, 952, 890, 921, 828, 859, 797, 828,
|
||||
766, 797, 984, 1015, 953, 984, 922, 953, 891, 922, 860, 891, 829, 860,
|
||||
798, 829, 767, 798, 985, 1016, 954, 985, 923, 954, 861, 892, 830, 861,
|
||||
799, 830, 986, 1017, 955, 986, 862, 893, 831, 862, 987, 1018, 863, 894,
|
||||
892, 923, 924, 955, 893, 924, 956, 987, 925, 956, 894, 925, 988, 1019,
|
||||
957, 988, 926, 957, 895, 926, 989, 1020, 958, 989, 927, 958, 990, 1021,
|
||||
959, 990, 991, 1022, 0, 0,
|
||||
};
|
||||
|
||||
DECLARE_ALIGNED(16, static const int16_t, vp9_default_iscan_4x4[16]) = {
|
||||
0, 2, 5, 8, 1, 3, 9, 12, 4, 7, 11, 14, 6, 10, 13, 15,
|
||||
};
|
||||
|
||||
DECLARE_ALIGNED(16, static const int16_t, vp9_col_iscan_4x4[16]) = {
|
||||
0, 3, 7, 11, 1, 5, 9, 12, 2, 6, 10, 14, 4, 8, 13, 15,
|
||||
};
|
||||
|
||||
DECLARE_ALIGNED(16, static const int16_t, vp9_row_iscan_4x4[16]) = {
|
||||
0, 1, 3, 5, 2, 4, 6, 9, 7, 8, 11, 13, 10, 12, 14, 15,
|
||||
};
|
||||
|
||||
DECLARE_ALIGNED(16, static const int16_t, vp9_col_iscan_8x8[64]) = {
|
||||
0, 3, 8, 15, 22, 32, 40, 47, 1, 5, 11, 18, 26, 34, 44, 51,
|
||||
2, 7, 13, 20, 28, 38, 46, 54, 4, 10, 16, 24, 31, 41, 50, 56,
|
||||
6, 12, 21, 27, 35, 43, 52, 58, 9, 17, 25, 33, 39, 48, 55, 60,
|
||||
14, 23, 30, 37, 45, 53, 59, 62, 19, 29, 36, 42, 49, 57, 61, 63,
|
||||
};
|
||||
|
||||
DECLARE_ALIGNED(16, static const int16_t, vp9_row_iscan_8x8[64]) = {
|
||||
0, 1, 2, 5, 8, 12, 19, 24, 3, 4, 7, 10, 15, 20, 30, 39,
|
||||
6, 9, 13, 16, 21, 27, 37, 46, 11, 14, 17, 23, 28, 34, 44, 52,
|
||||
18, 22, 25, 31, 35, 41, 50, 57, 26, 29, 33, 38, 43, 49, 55, 59,
|
||||
32, 36, 42, 47, 51, 54, 60, 61, 40, 45, 48, 53, 56, 58, 62, 63,
|
||||
};
|
||||
|
||||
DECLARE_ALIGNED(16, static const int16_t, vp9_default_iscan_8x8[64]) = {
|
||||
0, 2, 5, 9, 14, 22, 31, 37, 1, 4, 8, 13, 19, 26, 38, 44,
|
||||
3, 6, 10, 17, 24, 30, 42, 49, 7, 11, 15, 21, 29, 36, 47, 53,
|
||||
12, 16, 20, 27, 34, 43, 52, 57, 18, 23, 28, 35, 41, 48, 56, 60,
|
||||
25, 32, 39, 45, 50, 55, 59, 62, 33, 40, 46, 51, 54, 58, 61, 63,
|
||||
};
|
||||
|
||||
DECLARE_ALIGNED(16, static const int16_t, vp9_col_iscan_16x16[256]) = {
|
||||
0, 4, 11, 20, 31, 43, 59, 75, 85, 109, 130, 150, 165, 181, 195, 198,
|
||||
1, 6, 14, 23, 34, 47, 64, 81, 95, 114, 135, 153, 171, 188, 201, 212,
|
||||
2, 8, 16, 25, 38, 52, 67, 83, 101, 116, 136, 157, 172, 190, 205, 216,
|
||||
3, 10, 18, 29, 41, 55, 71, 89, 103, 119, 141, 159, 176, 194, 208, 218,
|
||||
5, 12, 21, 32, 45, 58, 74, 93, 104, 123, 144, 164, 179, 196, 210, 223,
|
||||
7, 15, 26, 37, 49, 63, 78, 96, 112, 129, 146, 166, 182, 200, 215, 228,
|
||||
9, 19, 28, 39, 54, 69, 86, 102, 117, 132, 151, 170, 187, 206, 220, 230,
|
||||
13, 24, 35, 46, 60, 73, 91, 108, 122, 137, 154, 174, 189, 207, 224, 235,
|
||||
17, 30, 40, 53, 66, 82, 98, 115, 126, 142, 161, 180, 197, 213, 227, 237,
|
||||
22, 36, 48, 62, 76, 92, 105, 120, 133, 147, 167, 186, 203, 219, 232, 240,
|
||||
27, 44, 56, 70, 84, 99, 113, 127, 140, 156, 175, 193, 209, 226, 236, 244,
|
||||
33, 51, 68, 79, 94, 110, 125, 138, 149, 162, 184, 202, 217, 229, 241, 247,
|
||||
42, 61, 77, 90, 106, 121, 134, 148, 160, 173, 191, 211, 225, 238, 245, 251,
|
||||
50, 72, 87, 100, 118, 128, 145, 158, 168, 183, 204, 222, 233, 242, 249, 253,
|
||||
57, 80, 97, 111, 131, 143, 155, 169, 178, 192, 214, 231, 239, 246, 250, 254,
|
||||
65, 88, 107, 124, 139, 152, 163, 177, 185, 199, 221, 234, 243, 248, 252, 255,
|
||||
};
|
||||
|
||||
DECLARE_ALIGNED(16, static const int16_t, vp9_row_iscan_16x16[256]) = {
|
||||
0, 1, 2, 4, 6, 9, 12, 17, 22, 29, 36, 43, 54, 64, 76,
|
||||
86, 3, 5, 7, 11, 15, 19, 25, 32, 38, 48, 59, 68, 84, 99,
|
||||
115, 130, 8, 10, 13, 18, 23, 27, 33, 42, 51, 60, 72, 88, 103,
|
||||
119, 142, 167, 14, 16, 20, 26, 31, 37, 44, 53, 61, 73, 85, 100,
|
||||
116, 135, 161, 185, 21, 24, 30, 35, 40, 47, 55, 65, 74, 81, 94,
|
||||
112, 133, 154, 179, 205, 28, 34, 39, 45, 50, 58, 67, 77, 87, 96,
|
||||
106, 121, 146, 169, 196, 212, 41, 46, 49, 56, 63, 70, 79, 90, 98,
|
||||
107, 122, 138, 159, 182, 207, 222, 52, 57, 62, 69, 75, 83, 93, 102,
|
||||
110, 120, 134, 150, 176, 195, 215, 226, 66, 71, 78, 82, 91, 97, 108,
|
||||
113, 127, 136, 148, 168, 188, 202, 221, 232, 80, 89, 92, 101, 105, 114,
|
||||
125, 131, 139, 151, 162, 177, 192, 208, 223, 234, 95, 104, 109, 117, 123,
|
||||
128, 143, 144, 155, 165, 175, 190, 206, 219, 233, 239, 111, 118, 124, 129,
|
||||
140, 147, 157, 164, 170, 181, 191, 203, 224, 230, 240, 243, 126, 132, 137,
|
||||
145, 153, 160, 174, 178, 184, 197, 204, 216, 231, 237, 244, 246, 141, 149,
|
||||
156, 166, 172, 180, 189, 199, 200, 210, 220, 228, 238, 242, 249, 251, 152,
|
||||
163, 171, 183, 186, 193, 201, 211, 214, 218, 227, 236, 245, 247, 252, 253,
|
||||
158, 173, 187, 194, 198, 209, 213, 217, 225, 229, 235, 241, 248, 250, 254,
|
||||
255,
|
||||
};
|
||||
|
||||
DECLARE_ALIGNED(16, static const int16_t, vp9_default_iscan_16x16[256]) = {
|
||||
0, 2, 5, 9, 17, 24, 36, 44, 55, 72, 88, 104, 128, 143, 166,
|
||||
179, 1, 4, 8, 13, 20, 30, 40, 54, 66, 79, 96, 113, 141, 154,
|
||||
178, 196, 3, 7, 11, 18, 25, 33, 46, 57, 71, 86, 101, 119, 148,
|
||||
164, 186, 201, 6, 12, 16, 23, 31, 39, 53, 64, 78, 92, 110, 127,
|
||||
153, 169, 193, 208, 10, 14, 19, 28, 37, 47, 58, 67, 84, 98, 114,
|
||||
133, 161, 176, 198, 214, 15, 21, 26, 34, 43, 52, 65, 77, 91, 106,
|
||||
120, 140, 165, 185, 205, 221, 22, 27, 32, 41, 48, 60, 73, 85, 99,
|
||||
116, 130, 151, 175, 190, 211, 225, 29, 35, 42, 49, 59, 69, 81, 95,
|
||||
108, 125, 139, 155, 182, 197, 217, 229, 38, 45, 51, 61, 68, 80, 93,
|
||||
105, 118, 134, 150, 168, 191, 207, 223, 234, 50, 56, 63, 74, 83, 94,
|
||||
109, 117, 129, 147, 163, 177, 199, 213, 228, 238, 62, 70, 76, 87, 97,
|
||||
107, 122, 131, 145, 159, 172, 188, 210, 222, 235, 242, 75, 82, 90, 102,
|
||||
112, 124, 138, 146, 157, 173, 187, 202, 219, 230, 240, 245, 89, 100, 111,
|
||||
123, 132, 142, 156, 167, 180, 189, 203, 216, 231, 237, 246, 250, 103, 115,
|
||||
126, 136, 149, 162, 171, 183, 194, 204, 215, 224, 236, 241, 248, 252, 121,
|
||||
135, 144, 158, 170, 181, 192, 200, 209, 218, 227, 233, 243, 244, 251, 254,
|
||||
137, 152, 160, 174, 184, 195, 206, 212, 220, 226, 232, 239, 247, 249, 253,
|
||||
255,
|
||||
};
|
||||
|
||||
DECLARE_ALIGNED(16, static const int16_t, vp9_default_iscan_32x32[1024]) = {
|
||||
0, 2, 5, 10, 17, 25, 38, 47, 62, 83, 101, 121, 145,
|
||||
170, 193, 204, 210, 219, 229, 233, 245, 257, 275, 299, 342, 356,
|
||||
377, 405, 455, 471, 495, 527, 1, 4, 8, 15, 22, 30, 45,
|
||||
58, 74, 92, 112, 133, 158, 184, 203, 215, 222, 228, 234, 237,
|
||||
256, 274, 298, 317, 355, 376, 404, 426, 470, 494, 526, 551, 3,
|
||||
7, 12, 18, 28, 36, 52, 64, 82, 102, 118, 142, 164, 189,
|
||||
208, 217, 224, 231, 235, 238, 273, 297, 316, 329, 375, 403, 425,
|
||||
440, 493, 525, 550, 567, 6, 11, 16, 23, 31, 43, 60, 73,
|
||||
90, 109, 126, 150, 173, 196, 211, 220, 226, 232, 236, 239, 296,
|
||||
315, 328, 335, 402, 424, 439, 447, 524, 549, 566, 575, 9, 14,
|
||||
19, 29, 37, 50, 65, 78, 95, 116, 134, 157, 179, 201, 214,
|
||||
223, 244, 255, 272, 295, 341, 354, 374, 401, 454, 469, 492, 523,
|
||||
582, 596, 617, 645, 13, 20, 26, 35, 44, 54, 72, 85, 105,
|
||||
123, 140, 163, 182, 205, 216, 225, 254, 271, 294, 314, 353, 373,
|
||||
400, 423, 468, 491, 522, 548, 595, 616, 644, 666, 21, 27, 33,
|
||||
42, 53, 63, 80, 94, 113, 132, 151, 172, 190, 209, 218, 227,
|
||||
270, 293, 313, 327, 372, 399, 422, 438, 490, 521, 547, 565, 615,
|
||||
643, 665, 680, 24, 32, 39, 48, 57, 71, 88, 104, 120, 139,
|
||||
159, 178, 197, 212, 221, 230, 292, 312, 326, 334, 398, 421, 437,
|
||||
446, 520, 546, 564, 574, 642, 664, 679, 687, 34, 40, 46, 56,
|
||||
68, 81, 96, 111, 130, 147, 167, 186, 243, 253, 269, 291, 340,
|
||||
352, 371, 397, 453, 467, 489, 519, 581, 594, 614, 641, 693, 705,
|
||||
723, 747, 41, 49, 55, 67, 77, 91, 107, 124, 138, 161, 177,
|
||||
194, 252, 268, 290, 311, 351, 370, 396, 420, 466, 488, 518, 545,
|
||||
593, 613, 640, 663, 704, 722, 746, 765, 51, 59, 66, 76, 89,
|
||||
99, 119, 131, 149, 168, 181, 200, 267, 289, 310, 325, 369, 395,
|
||||
419, 436, 487, 517, 544, 563, 612, 639, 662, 678, 721, 745, 764,
|
||||
777, 61, 69, 75, 87, 100, 114, 129, 144, 162, 180, 191, 207,
|
||||
288, 309, 324, 333, 394, 418, 435, 445, 516, 543, 562, 573, 638,
|
||||
661, 677, 686, 744, 763, 776, 783, 70, 79, 86, 97, 108, 122,
|
||||
137, 155, 242, 251, 266, 287, 339, 350, 368, 393, 452, 465, 486,
|
||||
515, 580, 592, 611, 637, 692, 703, 720, 743, 788, 798, 813, 833,
|
||||
84, 93, 103, 110, 125, 141, 154, 171, 250, 265, 286, 308, 349,
|
||||
367, 392, 417, 464, 485, 514, 542, 591, 610, 636, 660, 702, 719,
|
||||
742, 762, 797, 812, 832, 848, 98, 106, 115, 127, 143, 156, 169,
|
||||
185, 264, 285, 307, 323, 366, 391, 416, 434, 484, 513, 541, 561,
|
||||
609, 635, 659, 676, 718, 741, 761, 775, 811, 831, 847, 858, 117,
|
||||
128, 136, 148, 160, 175, 188, 198, 284, 306, 322, 332, 390, 415,
|
||||
433, 444, 512, 540, 560, 572, 634, 658, 675, 685, 740, 760, 774,
|
||||
782, 830, 846, 857, 863, 135, 146, 152, 165, 241, 249, 263, 283,
|
||||
338, 348, 365, 389, 451, 463, 483, 511, 579, 590, 608, 633, 691,
|
||||
701, 717, 739, 787, 796, 810, 829, 867, 875, 887, 903, 153, 166,
|
||||
174, 183, 248, 262, 282, 305, 347, 364, 388, 414, 462, 482, 510,
|
||||
539, 589, 607, 632, 657, 700, 716, 738, 759, 795, 809, 828, 845,
|
||||
874, 886, 902, 915, 176, 187, 195, 202, 261, 281, 304, 321, 363,
|
||||
387, 413, 432, 481, 509, 538, 559, 606, 631, 656, 674, 715, 737,
|
||||
758, 773, 808, 827, 844, 856, 885, 901, 914, 923, 192, 199, 206,
|
||||
213, 280, 303, 320, 331, 386, 412, 431, 443, 508, 537, 558, 571,
|
||||
630, 655, 673, 684, 736, 757, 772, 781, 826, 843, 855, 862, 900,
|
||||
913, 922, 927, 240, 247, 260, 279, 337, 346, 362, 385, 450, 461,
|
||||
480, 507, 578, 588, 605, 629, 690, 699, 714, 735, 786, 794, 807,
|
||||
825, 866, 873, 884, 899, 930, 936, 945, 957, 246, 259, 278, 302,
|
||||
345, 361, 384, 411, 460, 479, 506, 536, 587, 604, 628, 654, 698,
|
||||
713, 734, 756, 793, 806, 824, 842, 872, 883, 898, 912, 935, 944,
|
||||
956, 966, 258, 277, 301, 319, 360, 383, 410, 430, 478, 505, 535,
|
||||
557, 603, 627, 653, 672, 712, 733, 755, 771, 805, 823, 841, 854,
|
||||
882, 897, 911, 921, 943, 955, 965, 972, 276, 300, 318, 330, 382,
|
||||
409, 429, 442, 504, 534, 556, 570, 626, 652, 671, 683, 732, 754,
|
||||
770, 780, 822, 840, 853, 861, 896, 910, 920, 926, 954, 964, 971,
|
||||
975, 336, 344, 359, 381, 449, 459, 477, 503, 577, 586, 602, 625,
|
||||
689, 697, 711, 731, 785, 792, 804, 821, 865, 871, 881, 895, 929,
|
||||
934, 942, 953, 977, 981, 987, 995, 343, 358, 380, 408, 458, 476,
|
||||
502, 533, 585, 601, 624, 651, 696, 710, 730, 753, 791, 803, 820,
|
||||
839, 870, 880, 894, 909, 933, 941, 952, 963, 980, 986, 994, 1001,
|
||||
357, 379, 407, 428, 475, 501, 532, 555, 600, 623, 650, 670, 709,
|
||||
729, 752, 769, 802, 819, 838, 852, 879, 893, 908, 919, 940, 951,
|
||||
962, 970, 985, 993, 1000, 1005, 378, 406, 427, 441, 500, 531, 554,
|
||||
569, 622, 649, 669, 682, 728, 751, 768, 779, 818, 837, 851, 860,
|
||||
892, 907, 918, 925, 950, 961, 969, 974, 992, 999, 1004, 1007, 448,
|
||||
457, 474, 499, 576, 584, 599, 621, 688, 695, 708, 727, 784, 790,
|
||||
801, 817, 864, 869, 878, 891, 928, 932, 939, 949, 976, 979, 984,
|
||||
991, 1008, 1010, 1013, 1017, 456, 473, 498, 530, 583, 598, 620, 648,
|
||||
694, 707, 726, 750, 789, 800, 816, 836, 868, 877, 890, 906, 931,
|
||||
938, 948, 960, 978, 983, 990, 998, 1009, 1012, 1016, 1020, 472, 497,
|
||||
529, 553, 597, 619, 647, 668, 706, 725, 749, 767, 799, 815, 835,
|
||||
850, 876, 889, 905, 917, 937, 947, 959, 968, 982, 989, 997, 1003,
|
||||
1011, 1015, 1019, 1022, 496, 528, 552, 568, 618, 646, 667, 681, 724,
|
||||
748, 766, 778, 814, 834, 849, 859, 888, 904, 916, 924, 946, 958,
|
||||
967, 973, 988, 996, 1002, 1006, 1014, 1018, 1021, 1023,
|
||||
};
|
||||
|
||||
const scan_order vp9_default_scan_orders[TX_SIZES] = {
|
||||
{ default_scan_4x4, vp9_default_iscan_4x4, default_scan_4x4_neighbors },
|
||||
{ default_scan_8x8, vp9_default_iscan_8x8, default_scan_8x8_neighbors },
|
||||
{ default_scan_16x16, vp9_default_iscan_16x16, default_scan_16x16_neighbors },
|
||||
{ default_scan_32x32, vp9_default_iscan_32x32, default_scan_32x32_neighbors },
|
||||
};
|
||||
|
||||
const scan_order vp9_scan_orders[TX_SIZES][TX_TYPES] = {
|
||||
{ // TX_4X4
|
||||
{ default_scan_4x4, vp9_default_iscan_4x4, default_scan_4x4_neighbors },
|
||||
{ row_scan_4x4, vp9_row_iscan_4x4, row_scan_4x4_neighbors },
|
||||
{ col_scan_4x4, vp9_col_iscan_4x4, col_scan_4x4_neighbors },
|
||||
{ default_scan_4x4, vp9_default_iscan_4x4, default_scan_4x4_neighbors } },
|
||||
{ // TX_8X8
|
||||
{ default_scan_8x8, vp9_default_iscan_8x8, default_scan_8x8_neighbors },
|
||||
{ row_scan_8x8, vp9_row_iscan_8x8, row_scan_8x8_neighbors },
|
||||
{ col_scan_8x8, vp9_col_iscan_8x8, col_scan_8x8_neighbors },
|
||||
{ default_scan_8x8, vp9_default_iscan_8x8, default_scan_8x8_neighbors } },
|
||||
{ // TX_16X16
|
||||
{ default_scan_16x16, vp9_default_iscan_16x16,
|
||||
default_scan_16x16_neighbors },
|
||||
{ row_scan_16x16, vp9_row_iscan_16x16, row_scan_16x16_neighbors },
|
||||
{ col_scan_16x16, vp9_col_iscan_16x16, col_scan_16x16_neighbors },
|
||||
{ default_scan_16x16, vp9_default_iscan_16x16,
|
||||
default_scan_16x16_neighbors } },
|
||||
{ // TX_32X32
|
||||
{ default_scan_32x32, vp9_default_iscan_32x32,
|
||||
default_scan_32x32_neighbors },
|
||||
{ default_scan_32x32, vp9_default_iscan_32x32,
|
||||
default_scan_32x32_neighbors },
|
||||
{ default_scan_32x32, vp9_default_iscan_32x32,
|
||||
default_scan_32x32_neighbors },
|
||||
{ default_scan_32x32, vp9_default_iscan_32x32,
|
||||
default_scan_32x32_neighbors } }
|
||||
};
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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 VPX_VP9_COMMON_VP9_SCAN_H_
|
||||
#define VPX_VP9_COMMON_VP9_SCAN_H_
|
||||
|
||||
#include "vpx/vpx_integer.h"
|
||||
#include "vpx_ports/mem.h"
|
||||
|
||||
#include "vp9/common/vp9_enums.h"
|
||||
#include "vp9/common/vp9_blockd.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define MAX_NEIGHBORS 2
|
||||
|
||||
typedef struct {
|
||||
const int16_t *scan;
|
||||
const int16_t *iscan;
|
||||
const int16_t *neighbors;
|
||||
} scan_order;
|
||||
|
||||
extern const scan_order vp9_default_scan_orders[TX_SIZES];
|
||||
extern const scan_order vp9_scan_orders[TX_SIZES][TX_TYPES];
|
||||
|
||||
static INLINE int get_coef_context(const int16_t *neighbors,
|
||||
const uint8_t *token_cache, int c) {
|
||||
return (1 + token_cache[neighbors[MAX_NEIGHBORS * c + 0]] +
|
||||
token_cache[neighbors[MAX_NEIGHBORS * c + 1]]) >>
|
||||
1;
|
||||
}
|
||||
|
||||
static INLINE const scan_order *get_scan(const MACROBLOCKD *xd, TX_SIZE tx_size,
|
||||
PLANE_TYPE type, int block_idx) {
|
||||
const MODE_INFO *const mi = xd->mi[0];
|
||||
|
||||
if (is_inter_block(mi) || type != PLANE_TYPE_Y || xd->lossless) {
|
||||
return &vp9_default_scan_orders[tx_size];
|
||||
} else {
|
||||
const PREDICTION_MODE mode = get_y_mode(mi, block_idx);
|
||||
return &vp9_scan_orders[tx_size][intra_mode_to_tx_type_lookup[mode]];
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_COMMON_VP9_SCAN_H_
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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/common/vp9_blockd.h"
|
||||
#include "vp9/common/vp9_loopfilter.h"
|
||||
#include "vp9/common/vp9_seg_common.h"
|
||||
#include "vp9/common/vp9_quant_common.h"
|
||||
|
||||
static const int seg_feature_data_signed[SEG_LVL_MAX] = { 1, 1, 0, 0 };
|
||||
|
||||
static const int seg_feature_data_max[SEG_LVL_MAX] = { MAXQ, MAX_LOOP_FILTER, 3,
|
||||
0 };
|
||||
|
||||
// These functions provide access to new segment level features.
|
||||
// Eventually these function may be "optimized out" but for the moment,
|
||||
// the coding mechanism is still subject to change so these provide a
|
||||
// convenient single point of change.
|
||||
|
||||
void vp9_clearall_segfeatures(struct segmentation *seg) {
|
||||
vp9_zero(seg->feature_data);
|
||||
vp9_zero(seg->feature_mask);
|
||||
seg->aq_av_offset = 0;
|
||||
}
|
||||
|
||||
void vp9_enable_segfeature(struct segmentation *seg, int segment_id,
|
||||
SEG_LVL_FEATURES feature_id) {
|
||||
seg->feature_mask[segment_id] |= 1 << feature_id;
|
||||
}
|
||||
|
||||
int vp9_seg_feature_data_max(SEG_LVL_FEATURES feature_id) {
|
||||
return seg_feature_data_max[feature_id];
|
||||
}
|
||||
|
||||
int vp9_is_segfeature_signed(SEG_LVL_FEATURES feature_id) {
|
||||
return seg_feature_data_signed[feature_id];
|
||||
}
|
||||
|
||||
void vp9_set_segdata(struct segmentation *seg, int segment_id,
|
||||
SEG_LVL_FEATURES feature_id, int seg_data) {
|
||||
assert(seg_data <= seg_feature_data_max[feature_id]);
|
||||
if (seg_data < 0) {
|
||||
assert(seg_feature_data_signed[feature_id]);
|
||||
assert(-seg_data <= seg_feature_data_max[feature_id]);
|
||||
}
|
||||
|
||||
seg->feature_data[segment_id][feature_id] = seg_data;
|
||||
}
|
||||
|
||||
const vpx_tree_index vp9_segment_tree[TREE_SIZE(MAX_SEGMENTS)] = {
|
||||
2, 4, 6, 8, 10, 12, 0, -1, -2, -3, -4, -5, -6, -7
|
||||
};
|
||||
|
||||
// TBD? Functions to read and write segment data with range / validity checking
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* 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 VPX_VP9_COMMON_VP9_SEG_COMMON_H_
|
||||
#define VPX_VP9_COMMON_VP9_SEG_COMMON_H_
|
||||
|
||||
#include "vpx_dsp/prob.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define SEGMENT_DELTADATA 0
|
||||
#define SEGMENT_ABSDATA 1
|
||||
|
||||
#define MAX_SEGMENTS 8
|
||||
#define SEG_TREE_PROBS (MAX_SEGMENTS - 1)
|
||||
|
||||
#define PREDICTION_PROBS 3
|
||||
|
||||
// Segment level features.
|
||||
typedef enum {
|
||||
SEG_LVL_ALT_Q = 0, // Use alternate Quantizer ....
|
||||
SEG_LVL_ALT_LF = 1, // Use alternate loop filter value...
|
||||
SEG_LVL_REF_FRAME = 2, // Optional Segment reference frame
|
||||
SEG_LVL_SKIP = 3, // Optional Segment (0,0) + skip mode
|
||||
SEG_LVL_MAX = 4 // Number of features supported
|
||||
} SEG_LVL_FEATURES;
|
||||
|
||||
struct segmentation {
|
||||
uint8_t enabled;
|
||||
uint8_t update_map;
|
||||
uint8_t update_data;
|
||||
uint8_t abs_delta;
|
||||
uint8_t temporal_update;
|
||||
|
||||
vpx_prob tree_probs[SEG_TREE_PROBS];
|
||||
vpx_prob pred_probs[PREDICTION_PROBS];
|
||||
|
||||
int16_t feature_data[MAX_SEGMENTS][SEG_LVL_MAX];
|
||||
uint32_t feature_mask[MAX_SEGMENTS];
|
||||
int aq_av_offset;
|
||||
};
|
||||
|
||||
static INLINE int segfeature_active(const struct segmentation *seg,
|
||||
int segment_id,
|
||||
SEG_LVL_FEATURES feature_id) {
|
||||
return seg->enabled && (seg->feature_mask[segment_id] & (1 << feature_id));
|
||||
}
|
||||
|
||||
void vp9_clearall_segfeatures(struct segmentation *seg);
|
||||
|
||||
void vp9_enable_segfeature(struct segmentation *seg, int segment_id,
|
||||
SEG_LVL_FEATURES feature_id);
|
||||
|
||||
int vp9_seg_feature_data_max(SEG_LVL_FEATURES feature_id);
|
||||
|
||||
int vp9_is_segfeature_signed(SEG_LVL_FEATURES feature_id);
|
||||
|
||||
void vp9_set_segdata(struct segmentation *seg, int segment_id,
|
||||
SEG_LVL_FEATURES feature_id, int seg_data);
|
||||
|
||||
static INLINE int get_segdata(const struct segmentation *seg, int segment_id,
|
||||
SEG_LVL_FEATURES feature_id) {
|
||||
return seg->feature_data[segment_id][feature_id];
|
||||
}
|
||||
|
||||
extern const vpx_tree_index vp9_segment_tree[TREE_SIZE(MAX_SEGMENTS)];
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_COMMON_VP9_SEG_COMMON_H_
|
||||
@@ -0,0 +1,604 @@
|
||||
/*
|
||||
* 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 "./vpx_config.h"
|
||||
#include "vpx_dsp/vpx_dsp_common.h"
|
||||
#include "vpx_mem/vpx_mem.h"
|
||||
#include "vp9/common/vp9_entropymode.h"
|
||||
#include "vp9/common/vp9_thread_common.h"
|
||||
#include "vp9/common/vp9_reconinter.h"
|
||||
#include "vp9/common/vp9_loopfilter.h"
|
||||
|
||||
#if CONFIG_MULTITHREAD
|
||||
static INLINE void mutex_lock(pthread_mutex_t *const mutex) {
|
||||
const int kMaxTryLocks = 4000;
|
||||
int locked = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < kMaxTryLocks; ++i) {
|
||||
if (!pthread_mutex_trylock(mutex)) {
|
||||
locked = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!locked) pthread_mutex_lock(mutex);
|
||||
}
|
||||
#endif // CONFIG_MULTITHREAD
|
||||
|
||||
static INLINE void sync_read(VP9LfSync *const lf_sync, int r, int c) {
|
||||
#if CONFIG_MULTITHREAD
|
||||
const int nsync = lf_sync->sync_range;
|
||||
|
||||
if (r && !(c & (nsync - 1))) {
|
||||
pthread_mutex_t *const mutex = &lf_sync->mutex[r - 1];
|
||||
mutex_lock(mutex);
|
||||
|
||||
while (c > lf_sync->cur_sb_col[r - 1] - nsync) {
|
||||
pthread_cond_wait(&lf_sync->cond[r - 1], mutex);
|
||||
}
|
||||
pthread_mutex_unlock(mutex);
|
||||
}
|
||||
#else
|
||||
(void)lf_sync;
|
||||
(void)r;
|
||||
(void)c;
|
||||
#endif // CONFIG_MULTITHREAD
|
||||
}
|
||||
|
||||
static INLINE void sync_write(VP9LfSync *const lf_sync, int r, int c,
|
||||
const int sb_cols) {
|
||||
#if CONFIG_MULTITHREAD
|
||||
const int nsync = lf_sync->sync_range;
|
||||
int cur;
|
||||
// Only signal when there are enough filtered SB for next row to run.
|
||||
int sig = 1;
|
||||
|
||||
if (c < sb_cols - 1) {
|
||||
cur = c;
|
||||
if (c % nsync) sig = 0;
|
||||
} else {
|
||||
cur = sb_cols + nsync;
|
||||
}
|
||||
|
||||
if (sig) {
|
||||
mutex_lock(&lf_sync->mutex[r]);
|
||||
|
||||
lf_sync->cur_sb_col[r] = cur;
|
||||
|
||||
pthread_cond_signal(&lf_sync->cond[r]);
|
||||
pthread_mutex_unlock(&lf_sync->mutex[r]);
|
||||
}
|
||||
#else
|
||||
(void)lf_sync;
|
||||
(void)r;
|
||||
(void)c;
|
||||
(void)sb_cols;
|
||||
#endif // CONFIG_MULTITHREAD
|
||||
}
|
||||
|
||||
// Implement row loopfiltering for each thread.
|
||||
static INLINE void thread_loop_filter_rows(
|
||||
const YV12_BUFFER_CONFIG *const frame_buffer, VP9_COMMON *const cm,
|
||||
struct macroblockd_plane planes[MAX_MB_PLANE], int start, int stop,
|
||||
int y_only, VP9LfSync *const lf_sync) {
|
||||
const int num_planes = y_only ? 1 : MAX_MB_PLANE;
|
||||
const int sb_cols = mi_cols_aligned_to_sb(cm->mi_cols) >> MI_BLOCK_SIZE_LOG2;
|
||||
const int num_active_workers = lf_sync->num_active_workers;
|
||||
int mi_row, mi_col;
|
||||
enum lf_path path;
|
||||
if (y_only)
|
||||
path = LF_PATH_444;
|
||||
else if (planes[1].subsampling_y == 1 && planes[1].subsampling_x == 1)
|
||||
path = LF_PATH_420;
|
||||
else if (planes[1].subsampling_y == 0 && planes[1].subsampling_x == 0)
|
||||
path = LF_PATH_444;
|
||||
else
|
||||
path = LF_PATH_SLOW;
|
||||
|
||||
assert(num_active_workers > 0);
|
||||
|
||||
for (mi_row = start; mi_row < stop;
|
||||
mi_row += num_active_workers * MI_BLOCK_SIZE) {
|
||||
MODE_INFO **const mi = cm->mi_grid_visible + mi_row * cm->mi_stride;
|
||||
LOOP_FILTER_MASK *lfm = get_lfm(&cm->lf, mi_row, 0);
|
||||
|
||||
for (mi_col = 0; mi_col < cm->mi_cols; mi_col += MI_BLOCK_SIZE, ++lfm) {
|
||||
const int r = mi_row >> MI_BLOCK_SIZE_LOG2;
|
||||
const int c = mi_col >> MI_BLOCK_SIZE_LOG2;
|
||||
int plane;
|
||||
|
||||
sync_read(lf_sync, r, c);
|
||||
|
||||
vp9_setup_dst_planes(planes, frame_buffer, mi_row, mi_col);
|
||||
|
||||
vp9_adjust_mask(cm, mi_row, mi_col, lfm);
|
||||
|
||||
vp9_filter_block_plane_ss00(cm, &planes[0], mi_row, lfm);
|
||||
for (plane = 1; plane < num_planes; ++plane) {
|
||||
switch (path) {
|
||||
case LF_PATH_420:
|
||||
vp9_filter_block_plane_ss11(cm, &planes[plane], mi_row, lfm);
|
||||
break;
|
||||
case LF_PATH_444:
|
||||
vp9_filter_block_plane_ss00(cm, &planes[plane], mi_row, lfm);
|
||||
break;
|
||||
case LF_PATH_SLOW:
|
||||
vp9_filter_block_plane_non420(cm, &planes[plane], mi + mi_col,
|
||||
mi_row, mi_col);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sync_write(lf_sync, r, c, sb_cols);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Row-based multi-threaded loopfilter hook
|
||||
static int loop_filter_row_worker(void *arg1, void *arg2) {
|
||||
VP9LfSync *const lf_sync = (VP9LfSync *)arg1;
|
||||
LFWorkerData *const lf_data = (LFWorkerData *)arg2;
|
||||
thread_loop_filter_rows(lf_data->frame_buffer, lf_data->cm, lf_data->planes,
|
||||
lf_data->start, lf_data->stop, lf_data->y_only,
|
||||
lf_sync);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void loop_filter_rows_mt(YV12_BUFFER_CONFIG *frame, VP9_COMMON *cm,
|
||||
struct macroblockd_plane planes[MAX_MB_PLANE],
|
||||
int start, int stop, int y_only,
|
||||
VPxWorker *workers, int nworkers,
|
||||
VP9LfSync *lf_sync) {
|
||||
const VPxWorkerInterface *const winterface = vpx_get_worker_interface();
|
||||
// Number of superblock rows and cols
|
||||
const int sb_rows = mi_cols_aligned_to_sb(cm->mi_rows) >> MI_BLOCK_SIZE_LOG2;
|
||||
const int num_tile_cols = 1 << cm->log2_tile_cols;
|
||||
// Limit the number of workers to prevent changes in frame dimensions from
|
||||
// causing incorrect sync calculations when sb_rows < threads/tile_cols.
|
||||
// Further restrict them by the number of tile columns should the user
|
||||
// request more as this implementation doesn't scale well beyond that.
|
||||
const int num_workers = VPXMIN(nworkers, VPXMIN(num_tile_cols, sb_rows));
|
||||
int i;
|
||||
|
||||
if (!lf_sync->sync_range || sb_rows != lf_sync->rows ||
|
||||
num_workers > lf_sync->num_workers) {
|
||||
vp9_loop_filter_dealloc(lf_sync);
|
||||
vp9_loop_filter_alloc(lf_sync, cm, sb_rows, cm->width, num_workers);
|
||||
}
|
||||
lf_sync->num_active_workers = num_workers;
|
||||
|
||||
// Initialize cur_sb_col to -1 for all SB rows.
|
||||
memset(lf_sync->cur_sb_col, -1, sizeof(*lf_sync->cur_sb_col) * sb_rows);
|
||||
|
||||
// Set up loopfilter thread data.
|
||||
// The decoder is capping num_workers because it has been observed that using
|
||||
// more threads on the loopfilter than there are cores will hurt performance
|
||||
// on Android. This is because the system will only schedule the tile decode
|
||||
// workers on cores equal to the number of tile columns. Then if the decoder
|
||||
// tries to use more threads for the loopfilter, it will hurt performance
|
||||
// because of contention. If the multithreading code changes in the future
|
||||
// then the number of workers used by the loopfilter should be revisited.
|
||||
for (i = 0; i < num_workers; ++i) {
|
||||
VPxWorker *const worker = &workers[i];
|
||||
LFWorkerData *const lf_data = &lf_sync->lfdata[i];
|
||||
|
||||
worker->hook = loop_filter_row_worker;
|
||||
worker->data1 = lf_sync;
|
||||
worker->data2 = lf_data;
|
||||
|
||||
// Loopfilter data
|
||||
vp9_loop_filter_data_reset(lf_data, frame, cm, planes);
|
||||
lf_data->start = start + i * MI_BLOCK_SIZE;
|
||||
lf_data->stop = stop;
|
||||
lf_data->y_only = y_only;
|
||||
|
||||
// Start loopfiltering
|
||||
if (i == num_workers - 1) {
|
||||
winterface->execute(worker);
|
||||
} else {
|
||||
winterface->launch(worker);
|
||||
}
|
||||
}
|
||||
|
||||
// Wait till all rows are finished
|
||||
for (i = 0; i < num_workers; ++i) {
|
||||
winterface->sync(&workers[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_loop_filter_frame_mt(YV12_BUFFER_CONFIG *frame, VP9_COMMON *cm,
|
||||
struct macroblockd_plane planes[MAX_MB_PLANE],
|
||||
int frame_filter_level, int y_only,
|
||||
int partial_frame, VPxWorker *workers,
|
||||
int num_workers, VP9LfSync *lf_sync) {
|
||||
int start_mi_row, end_mi_row, mi_rows_to_filter;
|
||||
|
||||
if (!frame_filter_level) return;
|
||||
|
||||
start_mi_row = 0;
|
||||
mi_rows_to_filter = cm->mi_rows;
|
||||
if (partial_frame && cm->mi_rows > 8) {
|
||||
start_mi_row = cm->mi_rows >> 1;
|
||||
start_mi_row &= 0xfffffff8;
|
||||
mi_rows_to_filter = VPXMAX(cm->mi_rows / 8, 8);
|
||||
}
|
||||
end_mi_row = start_mi_row + mi_rows_to_filter;
|
||||
vp9_loop_filter_frame_init(cm, frame_filter_level);
|
||||
|
||||
loop_filter_rows_mt(frame, cm, planes, start_mi_row, end_mi_row, y_only,
|
||||
workers, num_workers, lf_sync);
|
||||
}
|
||||
|
||||
void vp9_lpf_mt_init(VP9LfSync *lf_sync, VP9_COMMON *cm, int frame_filter_level,
|
||||
int num_workers) {
|
||||
const int sb_rows = mi_cols_aligned_to_sb(cm->mi_rows) >> MI_BLOCK_SIZE_LOG2;
|
||||
|
||||
if (!frame_filter_level) return;
|
||||
|
||||
if (!lf_sync->sync_range || sb_rows != lf_sync->rows ||
|
||||
num_workers > lf_sync->num_workers) {
|
||||
vp9_loop_filter_dealloc(lf_sync);
|
||||
vp9_loop_filter_alloc(lf_sync, cm, sb_rows, cm->width, num_workers);
|
||||
}
|
||||
|
||||
// Initialize cur_sb_col to -1 for all SB rows.
|
||||
memset(lf_sync->cur_sb_col, -1, sizeof(*lf_sync->cur_sb_col) * sb_rows);
|
||||
|
||||
lf_sync->corrupted = 0;
|
||||
|
||||
memset(lf_sync->num_tiles_done, 0,
|
||||
sizeof(*lf_sync->num_tiles_done) * sb_rows);
|
||||
cm->lf_row = 0;
|
||||
}
|
||||
|
||||
// Set up nsync by width.
|
||||
static INLINE int get_sync_range(int width) {
|
||||
// nsync numbers are picked by testing. For example, for 4k
|
||||
// video, using 4 gives best performance.
|
||||
if (width < 640)
|
||||
return 1;
|
||||
else if (width <= 1280)
|
||||
return 2;
|
||||
else if (width <= 4096)
|
||||
return 4;
|
||||
else
|
||||
return 8;
|
||||
}
|
||||
|
||||
// Allocate memory for lf row synchronization
|
||||
void vp9_loop_filter_alloc(VP9LfSync *lf_sync, VP9_COMMON *cm, int rows,
|
||||
int width, int num_workers) {
|
||||
lf_sync->rows = rows;
|
||||
#if CONFIG_MULTITHREAD
|
||||
{
|
||||
int i;
|
||||
|
||||
CHECK_MEM_ERROR(cm, lf_sync->mutex,
|
||||
vpx_malloc(sizeof(*lf_sync->mutex) * rows));
|
||||
if (lf_sync->mutex) {
|
||||
for (i = 0; i < rows; ++i) {
|
||||
pthread_mutex_init(&lf_sync->mutex[i], NULL);
|
||||
}
|
||||
}
|
||||
|
||||
CHECK_MEM_ERROR(cm, lf_sync->cond,
|
||||
vpx_malloc(sizeof(*lf_sync->cond) * rows));
|
||||
if (lf_sync->cond) {
|
||||
for (i = 0; i < rows; ++i) {
|
||||
pthread_cond_init(&lf_sync->cond[i], NULL);
|
||||
}
|
||||
}
|
||||
|
||||
CHECK_MEM_ERROR(cm, lf_sync->lf_mutex,
|
||||
vpx_malloc(sizeof(*lf_sync->lf_mutex)));
|
||||
pthread_mutex_init(lf_sync->lf_mutex, NULL);
|
||||
|
||||
CHECK_MEM_ERROR(cm, lf_sync->recon_done_mutex,
|
||||
vpx_malloc(sizeof(*lf_sync->recon_done_mutex) * rows));
|
||||
if (lf_sync->recon_done_mutex) {
|
||||
int i;
|
||||
for (i = 0; i < rows; ++i) {
|
||||
pthread_mutex_init(&lf_sync->recon_done_mutex[i], NULL);
|
||||
}
|
||||
}
|
||||
|
||||
CHECK_MEM_ERROR(cm, lf_sync->recon_done_cond,
|
||||
vpx_malloc(sizeof(*lf_sync->recon_done_cond) * rows));
|
||||
if (lf_sync->recon_done_cond) {
|
||||
int i;
|
||||
for (i = 0; i < rows; ++i) {
|
||||
pthread_cond_init(&lf_sync->recon_done_cond[i], NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // CONFIG_MULTITHREAD
|
||||
|
||||
CHECK_MEM_ERROR(cm, lf_sync->lfdata,
|
||||
vpx_malloc(num_workers * sizeof(*lf_sync->lfdata)));
|
||||
lf_sync->num_workers = num_workers;
|
||||
lf_sync->num_active_workers = lf_sync->num_workers;
|
||||
|
||||
CHECK_MEM_ERROR(cm, lf_sync->cur_sb_col,
|
||||
vpx_malloc(sizeof(*lf_sync->cur_sb_col) * rows));
|
||||
|
||||
CHECK_MEM_ERROR(cm, lf_sync->num_tiles_done,
|
||||
vpx_malloc(sizeof(*lf_sync->num_tiles_done) *
|
||||
mi_cols_aligned_to_sb(cm->mi_rows) >>
|
||||
MI_BLOCK_SIZE_LOG2));
|
||||
|
||||
// Set up nsync.
|
||||
lf_sync->sync_range = get_sync_range(width);
|
||||
}
|
||||
|
||||
// Deallocate lf synchronization related mutex and data
|
||||
void vp9_loop_filter_dealloc(VP9LfSync *lf_sync) {
|
||||
assert(lf_sync != NULL);
|
||||
|
||||
#if CONFIG_MULTITHREAD
|
||||
if (lf_sync->mutex != NULL) {
|
||||
int i;
|
||||
for (i = 0; i < lf_sync->rows; ++i) {
|
||||
pthread_mutex_destroy(&lf_sync->mutex[i]);
|
||||
}
|
||||
vpx_free(lf_sync->mutex);
|
||||
}
|
||||
if (lf_sync->cond != NULL) {
|
||||
int i;
|
||||
for (i = 0; i < lf_sync->rows; ++i) {
|
||||
pthread_cond_destroy(&lf_sync->cond[i]);
|
||||
}
|
||||
vpx_free(lf_sync->cond);
|
||||
}
|
||||
if (lf_sync->recon_done_mutex != NULL) {
|
||||
int i;
|
||||
for (i = 0; i < lf_sync->rows; ++i) {
|
||||
pthread_mutex_destroy(&lf_sync->recon_done_mutex[i]);
|
||||
}
|
||||
vpx_free(lf_sync->recon_done_mutex);
|
||||
}
|
||||
|
||||
if (lf_sync->lf_mutex != NULL) {
|
||||
pthread_mutex_destroy(lf_sync->lf_mutex);
|
||||
vpx_free(lf_sync->lf_mutex);
|
||||
}
|
||||
if (lf_sync->recon_done_cond != NULL) {
|
||||
int i;
|
||||
for (i = 0; i < lf_sync->rows; ++i) {
|
||||
pthread_cond_destroy(&lf_sync->recon_done_cond[i]);
|
||||
}
|
||||
vpx_free(lf_sync->recon_done_cond);
|
||||
}
|
||||
#endif // CONFIG_MULTITHREAD
|
||||
|
||||
vpx_free(lf_sync->lfdata);
|
||||
vpx_free(lf_sync->cur_sb_col);
|
||||
vpx_free(lf_sync->num_tiles_done);
|
||||
// clear the structure as the source of this call may be a resize in which
|
||||
// case this call will be followed by an _alloc() which may fail.
|
||||
vp9_zero(*lf_sync);
|
||||
}
|
||||
|
||||
static int get_next_row(VP9_COMMON *cm, VP9LfSync *lf_sync) {
|
||||
int return_val = -1;
|
||||
int cur_row;
|
||||
const int max_rows = cm->mi_rows;
|
||||
|
||||
#if CONFIG_MULTITHREAD
|
||||
const int tile_cols = 1 << cm->log2_tile_cols;
|
||||
|
||||
pthread_mutex_lock(lf_sync->lf_mutex);
|
||||
if (cm->lf_row < max_rows) {
|
||||
cur_row = cm->lf_row >> MI_BLOCK_SIZE_LOG2;
|
||||
return_val = cm->lf_row;
|
||||
cm->lf_row += MI_BLOCK_SIZE;
|
||||
if (cm->lf_row < max_rows) {
|
||||
/* If this is not the last row, make sure the next row is also decoded.
|
||||
* This is because the intra predict has to happen before loop filter */
|
||||
cur_row += 1;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(lf_sync->lf_mutex);
|
||||
|
||||
if (return_val == -1) return return_val;
|
||||
|
||||
pthread_mutex_lock(&lf_sync->recon_done_mutex[cur_row]);
|
||||
if (lf_sync->num_tiles_done[cur_row] < tile_cols) {
|
||||
pthread_cond_wait(&lf_sync->recon_done_cond[cur_row],
|
||||
&lf_sync->recon_done_mutex[cur_row]);
|
||||
}
|
||||
pthread_mutex_unlock(&lf_sync->recon_done_mutex[cur_row]);
|
||||
pthread_mutex_lock(lf_sync->lf_mutex);
|
||||
if (lf_sync->corrupted) {
|
||||
int row = return_val >> MI_BLOCK_SIZE_LOG2;
|
||||
pthread_mutex_lock(&lf_sync->mutex[row]);
|
||||
lf_sync->cur_sb_col[row] = INT_MAX;
|
||||
pthread_cond_signal(&lf_sync->cond[row]);
|
||||
pthread_mutex_unlock(&lf_sync->mutex[row]);
|
||||
return_val = -1;
|
||||
}
|
||||
pthread_mutex_unlock(lf_sync->lf_mutex);
|
||||
#else
|
||||
(void)lf_sync;
|
||||
if (cm->lf_row < max_rows) {
|
||||
cur_row = cm->lf_row >> MI_BLOCK_SIZE_LOG2;
|
||||
return_val = cm->lf_row;
|
||||
cm->lf_row += MI_BLOCK_SIZE;
|
||||
if (cm->lf_row < max_rows) {
|
||||
/* If this is not the last row, make sure the next row is also decoded.
|
||||
* This is because the intra predict has to happen before loop filter */
|
||||
cur_row += 1;
|
||||
}
|
||||
}
|
||||
#endif // CONFIG_MULTITHREAD
|
||||
|
||||
return return_val;
|
||||
}
|
||||
|
||||
void vp9_loopfilter_rows(LFWorkerData *lf_data, VP9LfSync *lf_sync) {
|
||||
int mi_row;
|
||||
VP9_COMMON *cm = lf_data->cm;
|
||||
|
||||
while ((mi_row = get_next_row(cm, lf_sync)) != -1 && mi_row < cm->mi_rows) {
|
||||
lf_data->start = mi_row;
|
||||
lf_data->stop = mi_row + MI_BLOCK_SIZE;
|
||||
|
||||
thread_loop_filter_rows(lf_data->frame_buffer, lf_data->cm, lf_data->planes,
|
||||
lf_data->start, lf_data->stop, lf_data->y_only,
|
||||
lf_sync);
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_set_row(VP9LfSync *lf_sync, int num_tiles, int row, int is_last_row,
|
||||
int corrupted) {
|
||||
#if CONFIG_MULTITHREAD
|
||||
pthread_mutex_lock(lf_sync->lf_mutex);
|
||||
lf_sync->corrupted |= corrupted;
|
||||
pthread_mutex_unlock(lf_sync->lf_mutex);
|
||||
pthread_mutex_lock(&lf_sync->recon_done_mutex[row]);
|
||||
lf_sync->num_tiles_done[row] += 1;
|
||||
if (num_tiles == lf_sync->num_tiles_done[row]) {
|
||||
if (is_last_row) {
|
||||
/* The last 2 rows wait on the last row to be done.
|
||||
* So, we have to broadcast the signal in this case.
|
||||
*/
|
||||
pthread_cond_broadcast(&lf_sync->recon_done_cond[row]);
|
||||
} else {
|
||||
pthread_cond_signal(&lf_sync->recon_done_cond[row]);
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&lf_sync->recon_done_mutex[row]);
|
||||
#else
|
||||
(void)lf_sync;
|
||||
(void)num_tiles;
|
||||
(void)row;
|
||||
(void)is_last_row;
|
||||
(void)corrupted;
|
||||
#endif // CONFIG_MULTITHREAD
|
||||
}
|
||||
|
||||
void vp9_loopfilter_job(LFWorkerData *lf_data, VP9LfSync *lf_sync) {
|
||||
thread_loop_filter_rows(lf_data->frame_buffer, lf_data->cm, lf_data->planes,
|
||||
lf_data->start, lf_data->stop, lf_data->y_only,
|
||||
lf_sync);
|
||||
}
|
||||
|
||||
// Accumulate frame counts.
|
||||
void vp9_accumulate_frame_counts(FRAME_COUNTS *accum,
|
||||
const FRAME_COUNTS *counts, int is_dec) {
|
||||
int i, j, k, l, m;
|
||||
|
||||
for (i = 0; i < BLOCK_SIZE_GROUPS; i++)
|
||||
for (j = 0; j < INTRA_MODES; j++)
|
||||
accum->y_mode[i][j] += counts->y_mode[i][j];
|
||||
|
||||
for (i = 0; i < INTRA_MODES; i++)
|
||||
for (j = 0; j < INTRA_MODES; j++)
|
||||
accum->uv_mode[i][j] += counts->uv_mode[i][j];
|
||||
|
||||
for (i = 0; i < PARTITION_CONTEXTS; i++)
|
||||
for (j = 0; j < PARTITION_TYPES; j++)
|
||||
accum->partition[i][j] += counts->partition[i][j];
|
||||
|
||||
if (is_dec) {
|
||||
int n;
|
||||
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++) {
|
||||
accum->eob_branch[i][j][k][l][m] +=
|
||||
counts->eob_branch[i][j][k][l][m];
|
||||
for (n = 0; n < UNCONSTRAINED_NODES + 1; n++)
|
||||
accum->coef[i][j][k][l][m][n] += counts->coef[i][j][k][l][m][n];
|
||||
}
|
||||
} else {
|
||||
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++)
|
||||
accum->eob_branch[i][j][k][l][m] +=
|
||||
counts->eob_branch[i][j][k][l][m];
|
||||
// In the encoder, coef is only updated at frame
|
||||
// level, so not need to accumulate it here.
|
||||
// for (n = 0; n < UNCONSTRAINED_NODES + 1; n++)
|
||||
// accum->coef[i][j][k][l][m][n] +=
|
||||
// counts->coef[i][j][k][l][m][n];
|
||||
}
|
||||
|
||||
for (i = 0; i < SWITCHABLE_FILTER_CONTEXTS; i++)
|
||||
for (j = 0; j < SWITCHABLE_FILTERS; j++)
|
||||
accum->switchable_interp[i][j] += counts->switchable_interp[i][j];
|
||||
|
||||
for (i = 0; i < INTER_MODE_CONTEXTS; i++)
|
||||
for (j = 0; j < INTER_MODES; j++)
|
||||
accum->inter_mode[i][j] += counts->inter_mode[i][j];
|
||||
|
||||
for (i = 0; i < INTRA_INTER_CONTEXTS; i++)
|
||||
for (j = 0; j < 2; j++)
|
||||
accum->intra_inter[i][j] += counts->intra_inter[i][j];
|
||||
|
||||
for (i = 0; i < COMP_INTER_CONTEXTS; i++)
|
||||
for (j = 0; j < 2; j++) accum->comp_inter[i][j] += counts->comp_inter[i][j];
|
||||
|
||||
for (i = 0; i < REF_CONTEXTS; i++)
|
||||
for (j = 0; j < 2; j++)
|
||||
for (k = 0; k < 2; k++)
|
||||
accum->single_ref[i][j][k] += counts->single_ref[i][j][k];
|
||||
|
||||
for (i = 0; i < REF_CONTEXTS; i++)
|
||||
for (j = 0; j < 2; j++) accum->comp_ref[i][j] += counts->comp_ref[i][j];
|
||||
|
||||
for (i = 0; i < TX_SIZE_CONTEXTS; i++) {
|
||||
for (j = 0; j < TX_SIZES; j++)
|
||||
accum->tx.p32x32[i][j] += counts->tx.p32x32[i][j];
|
||||
|
||||
for (j = 0; j < TX_SIZES - 1; j++)
|
||||
accum->tx.p16x16[i][j] += counts->tx.p16x16[i][j];
|
||||
|
||||
for (j = 0; j < TX_SIZES - 2; j++)
|
||||
accum->tx.p8x8[i][j] += counts->tx.p8x8[i][j];
|
||||
}
|
||||
|
||||
for (i = 0; i < TX_SIZES; i++)
|
||||
accum->tx.tx_totals[i] += counts->tx.tx_totals[i];
|
||||
|
||||
for (i = 0; i < SKIP_CONTEXTS; i++)
|
||||
for (j = 0; j < 2; j++) accum->skip[i][j] += counts->skip[i][j];
|
||||
|
||||
for (i = 0; i < MV_JOINTS; i++) accum->mv.joints[i] += counts->mv.joints[i];
|
||||
|
||||
for (k = 0; k < 2; k++) {
|
||||
nmv_component_counts *const comps = &accum->mv.comps[k];
|
||||
const nmv_component_counts *const comps_t = &counts->mv.comps[k];
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
comps->sign[i] += comps_t->sign[i];
|
||||
comps->class0_hp[i] += comps_t->class0_hp[i];
|
||||
comps->hp[i] += comps_t->hp[i];
|
||||
}
|
||||
|
||||
for (i = 0; i < MV_CLASSES; i++) comps->classes[i] += comps_t->classes[i];
|
||||
|
||||
for (i = 0; i < CLASS0_SIZE; i++) {
|
||||
comps->class0[i] += comps_t->class0[i];
|
||||
for (j = 0; j < MV_FP_SIZE; j++)
|
||||
comps->class0_fp[i][j] += comps_t->class0_fp[i][j];
|
||||
}
|
||||
|
||||
for (i = 0; i < MV_OFFSET_BITS; i++)
|
||||
for (j = 0; j < 2; j++) comps->bits[i][j] += comps_t->bits[i][j];
|
||||
|
||||
for (i = 0; i < MV_FP_SIZE; i++) comps->fp[i] += comps_t->fp[i];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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 VPX_VP9_COMMON_VP9_THREAD_COMMON_H_
|
||||
#define VPX_VP9_COMMON_VP9_THREAD_COMMON_H_
|
||||
#include "./vpx_config.h"
|
||||
#include "vp9/common/vp9_loopfilter.h"
|
||||
#include "vpx_util/vpx_thread.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct VP9Common;
|
||||
struct FRAME_COUNTS;
|
||||
|
||||
// Loopfilter row synchronization
|
||||
typedef struct VP9LfSyncData {
|
||||
#if CONFIG_MULTITHREAD
|
||||
pthread_mutex_t *mutex;
|
||||
pthread_cond_t *cond;
|
||||
#endif
|
||||
// Allocate memory to store the loop-filtered superblock index in each row.
|
||||
int *cur_sb_col;
|
||||
// The optimal sync_range for different resolution and platform should be
|
||||
// determined by testing. Currently, it is chosen to be a power-of-2 number.
|
||||
int sync_range;
|
||||
int rows;
|
||||
|
||||
// Row-based parallel loopfilter data
|
||||
LFWorkerData *lfdata;
|
||||
int num_workers; // number of allocated workers.
|
||||
int num_active_workers; // number of scheduled workers.
|
||||
|
||||
#if CONFIG_MULTITHREAD
|
||||
pthread_mutex_t *lf_mutex;
|
||||
pthread_mutex_t *recon_done_mutex;
|
||||
pthread_cond_t *recon_done_cond;
|
||||
#endif
|
||||
int *num_tiles_done;
|
||||
int corrupted;
|
||||
} VP9LfSync;
|
||||
|
||||
// Allocate memory for loopfilter row synchronization.
|
||||
void vp9_loop_filter_alloc(VP9LfSync *lf_sync, struct VP9Common *cm, int rows,
|
||||
int width, int num_workers);
|
||||
|
||||
// Deallocate loopfilter synchronization related mutex and data.
|
||||
void vp9_loop_filter_dealloc(VP9LfSync *lf_sync);
|
||||
|
||||
// Multi-threaded loopfilter that uses the tile threads.
|
||||
void vp9_loop_filter_frame_mt(YV12_BUFFER_CONFIG *frame, struct VP9Common *cm,
|
||||
struct macroblockd_plane planes[MAX_MB_PLANE],
|
||||
int frame_filter_level, int y_only,
|
||||
int partial_frame, VPxWorker *workers,
|
||||
int num_workers, VP9LfSync *lf_sync);
|
||||
|
||||
// Multi-threaded loopfilter initialisations
|
||||
void vp9_lpf_mt_init(VP9LfSync *lf_sync, struct VP9Common *cm,
|
||||
int frame_filter_level, int num_workers);
|
||||
|
||||
void vp9_loopfilter_rows(LFWorkerData *lf_data, VP9LfSync *lf_sync);
|
||||
|
||||
void vp9_set_row(VP9LfSync *lf_sync, int num_tiles, int row, int is_last_row,
|
||||
int corrupted);
|
||||
|
||||
void vp9_loopfilter_job(LFWorkerData *lf_data, VP9LfSync *lf_sync);
|
||||
|
||||
void vp9_accumulate_frame_counts(struct FRAME_COUNTS *accum,
|
||||
const struct FRAME_COUNTS *counts, int is_dec);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_COMMON_VP9_THREAD_COMMON_H_
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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/common/vp9_tile_common.h"
|
||||
#include "vp9/common/vp9_onyxc_int.h"
|
||||
#include "vpx_dsp/vpx_dsp_common.h"
|
||||
|
||||
#define MIN_TILE_WIDTH_B64 4
|
||||
#define MAX_TILE_WIDTH_B64 64
|
||||
|
||||
static int get_tile_offset(int idx, int mis, int log2) {
|
||||
const int sb_cols = mi_cols_aligned_to_sb(mis) >> MI_BLOCK_SIZE_LOG2;
|
||||
const int offset = ((idx * sb_cols) >> log2) << MI_BLOCK_SIZE_LOG2;
|
||||
return VPXMIN(offset, mis);
|
||||
}
|
||||
|
||||
void vp9_tile_set_row(TileInfo *tile, const VP9_COMMON *cm, int row) {
|
||||
tile->mi_row_start = get_tile_offset(row, cm->mi_rows, cm->log2_tile_rows);
|
||||
tile->mi_row_end = get_tile_offset(row + 1, cm->mi_rows, cm->log2_tile_rows);
|
||||
}
|
||||
|
||||
void vp9_tile_set_col(TileInfo *tile, const VP9_COMMON *cm, int col) {
|
||||
tile->mi_col_start = get_tile_offset(col, cm->mi_cols, cm->log2_tile_cols);
|
||||
tile->mi_col_end = get_tile_offset(col + 1, cm->mi_cols, cm->log2_tile_cols);
|
||||
}
|
||||
|
||||
void vp9_tile_init(TileInfo *tile, const VP9_COMMON *cm, int row, int col) {
|
||||
vp9_tile_set_row(tile, cm, row);
|
||||
vp9_tile_set_col(tile, cm, col);
|
||||
}
|
||||
|
||||
static int get_min_log2_tile_cols(const int sb64_cols) {
|
||||
int min_log2 = 0;
|
||||
while ((MAX_TILE_WIDTH_B64 << min_log2) < sb64_cols) ++min_log2;
|
||||
return min_log2;
|
||||
}
|
||||
|
||||
static int get_max_log2_tile_cols(const int sb64_cols) {
|
||||
int max_log2 = 1;
|
||||
while ((sb64_cols >> max_log2) >= MIN_TILE_WIDTH_B64) ++max_log2;
|
||||
return max_log2 - 1;
|
||||
}
|
||||
|
||||
void vp9_get_tile_n_bits(int mi_cols, int *min_log2_tile_cols,
|
||||
int *max_log2_tile_cols) {
|
||||
const int sb64_cols = mi_cols_aligned_to_sb(mi_cols) >> MI_BLOCK_SIZE_LOG2;
|
||||
*min_log2_tile_cols = get_min_log2_tile_cols(sb64_cols);
|
||||
*max_log2_tile_cols = get_max_log2_tile_cols(sb64_cols);
|
||||
assert(*min_log2_tile_cols <= *max_log2_tile_cols);
|
||||
}
|
||||
@@ -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 VPX_VP9_COMMON_VP9_TILE_COMMON_H_
|
||||
#define VPX_VP9_COMMON_VP9_TILE_COMMON_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct VP9Common;
|
||||
|
||||
typedef struct TileInfo {
|
||||
int mi_row_start, mi_row_end;
|
||||
int mi_col_start, mi_col_end;
|
||||
} TileInfo;
|
||||
|
||||
// initializes 'tile->mi_(row|col)_(start|end)' for (row, col) based on
|
||||
// 'cm->log2_tile_(rows|cols)' & 'cm->mi_(rows|cols)'
|
||||
void vp9_tile_init(TileInfo *tile, const struct VP9Common *cm, int row,
|
||||
int col);
|
||||
|
||||
void vp9_tile_set_row(TileInfo *tile, const struct VP9Common *cm, int row);
|
||||
void vp9_tile_set_col(TileInfo *tile, const struct VP9Common *cm, int col);
|
||||
|
||||
void vp9_get_tile_n_bits(int mi_cols, int *min_log2_tile_cols,
|
||||
int *max_log2_tile_cols);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_COMMON_VP9_TILE_COMMON_H_
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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 VPX_VP9_DECODER_VP9_DECODEFRAME_H_
|
||||
#define VPX_VP9_DECODER_VP9_DECODEFRAME_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "vp9/common/vp9_enums.h"
|
||||
|
||||
struct VP9Decoder;
|
||||
struct vpx_read_bit_buffer;
|
||||
|
||||
int vp9_read_sync_code(struct vpx_read_bit_buffer *const rb);
|
||||
void vp9_read_frame_size(struct vpx_read_bit_buffer *rb, int *width,
|
||||
int *height);
|
||||
BITSTREAM_PROFILE vp9_read_profile(struct vpx_read_bit_buffer *rb);
|
||||
|
||||
void vp9_decode_frame(struct VP9Decoder *pbi, const uint8_t *data,
|
||||
const uint8_t *data_end, const uint8_t **p_data_end);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_DECODER_VP9_DECODEFRAME_H_
|
||||
@@ -0,0 +1,840 @@
|
||||
/*
|
||||
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/common/vp9_common.h"
|
||||
#include "vp9/common/vp9_entropy.h"
|
||||
#include "vp9/common/vp9_entropymode.h"
|
||||
#include "vp9/common/vp9_entropymv.h"
|
||||
#include "vp9/common/vp9_mvref_common.h"
|
||||
#include "vp9/common/vp9_pred_common.h"
|
||||
#include "vp9/common/vp9_reconinter.h"
|
||||
#include "vp9/common/vp9_seg_common.h"
|
||||
|
||||
#include "vp9/decoder/vp9_decodemv.h"
|
||||
#include "vp9/decoder/vp9_decodeframe.h"
|
||||
|
||||
#include "vpx_dsp/vpx_dsp_common.h"
|
||||
|
||||
static PREDICTION_MODE read_intra_mode(vpx_reader *r, const vpx_prob *p) {
|
||||
return (PREDICTION_MODE)vpx_read_tree(r, vp9_intra_mode_tree, p);
|
||||
}
|
||||
|
||||
static PREDICTION_MODE read_intra_mode_y(VP9_COMMON *cm, MACROBLOCKD *xd,
|
||||
vpx_reader *r, int size_group) {
|
||||
const PREDICTION_MODE y_mode =
|
||||
read_intra_mode(r, cm->fc->y_mode_prob[size_group]);
|
||||
FRAME_COUNTS *counts = xd->counts;
|
||||
if (counts) ++counts->y_mode[size_group][y_mode];
|
||||
return y_mode;
|
||||
}
|
||||
|
||||
static PREDICTION_MODE read_intra_mode_uv(VP9_COMMON *cm, MACROBLOCKD *xd,
|
||||
vpx_reader *r,
|
||||
PREDICTION_MODE y_mode) {
|
||||
const PREDICTION_MODE uv_mode =
|
||||
read_intra_mode(r, cm->fc->uv_mode_prob[y_mode]);
|
||||
FRAME_COUNTS *counts = xd->counts;
|
||||
if (counts) ++counts->uv_mode[y_mode][uv_mode];
|
||||
return uv_mode;
|
||||
}
|
||||
|
||||
static PREDICTION_MODE read_inter_mode(VP9_COMMON *cm, MACROBLOCKD *xd,
|
||||
vpx_reader *r, int ctx) {
|
||||
const int mode =
|
||||
vpx_read_tree(r, vp9_inter_mode_tree, cm->fc->inter_mode_probs[ctx]);
|
||||
FRAME_COUNTS *counts = xd->counts;
|
||||
if (counts) ++counts->inter_mode[ctx][mode];
|
||||
|
||||
return NEARESTMV + mode;
|
||||
}
|
||||
|
||||
static int read_segment_id(vpx_reader *r, const struct segmentation *seg) {
|
||||
return vpx_read_tree(r, vp9_segment_tree, seg->tree_probs);
|
||||
}
|
||||
|
||||
static TX_SIZE read_selected_tx_size(VP9_COMMON *cm, MACROBLOCKD *xd,
|
||||
TX_SIZE max_tx_size, vpx_reader *r) {
|
||||
FRAME_COUNTS *counts = xd->counts;
|
||||
const int ctx = get_tx_size_context(xd);
|
||||
const vpx_prob *tx_probs = get_tx_probs(max_tx_size, ctx, &cm->fc->tx_probs);
|
||||
int tx_size = vpx_read(r, tx_probs[0]);
|
||||
if (tx_size != TX_4X4 && max_tx_size >= TX_16X16) {
|
||||
tx_size += vpx_read(r, tx_probs[1]);
|
||||
if (tx_size != TX_8X8 && max_tx_size >= TX_32X32)
|
||||
tx_size += vpx_read(r, tx_probs[2]);
|
||||
}
|
||||
|
||||
if (counts) ++get_tx_counts(max_tx_size, ctx, &counts->tx)[tx_size];
|
||||
return (TX_SIZE)tx_size;
|
||||
}
|
||||
|
||||
static INLINE TX_SIZE read_tx_size(VP9_COMMON *cm, MACROBLOCKD *xd,
|
||||
int allow_select, vpx_reader *r) {
|
||||
TX_MODE tx_mode = cm->tx_mode;
|
||||
BLOCK_SIZE bsize = xd->mi[0]->sb_type;
|
||||
const TX_SIZE max_tx_size = max_txsize_lookup[bsize];
|
||||
if (allow_select && tx_mode == TX_MODE_SELECT && bsize >= BLOCK_8X8)
|
||||
return read_selected_tx_size(cm, xd, max_tx_size, r);
|
||||
else
|
||||
return VPXMIN(max_tx_size, tx_mode_to_biggest_tx_size[tx_mode]);
|
||||
}
|
||||
|
||||
static int dec_get_segment_id(const VP9_COMMON *cm, const uint8_t *segment_ids,
|
||||
int mi_offset, int x_mis, int y_mis) {
|
||||
int x, y, segment_id = INT_MAX;
|
||||
|
||||
for (y = 0; y < y_mis; y++)
|
||||
for (x = 0; x < x_mis; x++)
|
||||
segment_id =
|
||||
VPXMIN(segment_id, segment_ids[mi_offset + y * cm->mi_cols + x]);
|
||||
|
||||
assert(segment_id >= 0 && segment_id < MAX_SEGMENTS);
|
||||
return segment_id;
|
||||
}
|
||||
|
||||
static void set_segment_id(VP9_COMMON *cm, int mi_offset, int x_mis, int y_mis,
|
||||
int segment_id) {
|
||||
int x, y;
|
||||
|
||||
assert(segment_id >= 0 && segment_id < MAX_SEGMENTS);
|
||||
|
||||
for (y = 0; y < y_mis; y++)
|
||||
for (x = 0; x < x_mis; x++)
|
||||
cm->current_frame_seg_map[mi_offset + y * cm->mi_cols + x] = segment_id;
|
||||
}
|
||||
|
||||
static void copy_segment_id(const VP9_COMMON *cm,
|
||||
const uint8_t *last_segment_ids,
|
||||
uint8_t *current_segment_ids, int mi_offset,
|
||||
int x_mis, int y_mis) {
|
||||
int x, y;
|
||||
|
||||
for (y = 0; y < y_mis; y++)
|
||||
for (x = 0; x < x_mis; x++)
|
||||
current_segment_ids[mi_offset + y * cm->mi_cols + x] =
|
||||
last_segment_ids ? last_segment_ids[mi_offset + y * cm->mi_cols + x]
|
||||
: 0;
|
||||
}
|
||||
|
||||
static int read_intra_segment_id(VP9_COMMON *const cm, int mi_offset, int x_mis,
|
||||
int y_mis, vpx_reader *r) {
|
||||
struct segmentation *const seg = &cm->seg;
|
||||
int segment_id;
|
||||
|
||||
if (!seg->enabled) return 0; // Default for disabled segmentation
|
||||
|
||||
if (!seg->update_map) {
|
||||
copy_segment_id(cm, cm->last_frame_seg_map, cm->current_frame_seg_map,
|
||||
mi_offset, x_mis, y_mis);
|
||||
return 0;
|
||||
}
|
||||
|
||||
segment_id = read_segment_id(r, seg);
|
||||
set_segment_id(cm, mi_offset, x_mis, y_mis, segment_id);
|
||||
return segment_id;
|
||||
}
|
||||
|
||||
static int read_inter_segment_id(VP9_COMMON *const cm, MACROBLOCKD *const xd,
|
||||
int mi_row, int mi_col, vpx_reader *r,
|
||||
int x_mis, int y_mis) {
|
||||
struct segmentation *const seg = &cm->seg;
|
||||
MODE_INFO *const mi = xd->mi[0];
|
||||
int predicted_segment_id, segment_id;
|
||||
const int mi_offset = mi_row * cm->mi_cols + mi_col;
|
||||
|
||||
if (!seg->enabled) return 0; // Default for disabled segmentation
|
||||
|
||||
predicted_segment_id = cm->last_frame_seg_map
|
||||
? dec_get_segment_id(cm, cm->last_frame_seg_map,
|
||||
mi_offset, x_mis, y_mis)
|
||||
: 0;
|
||||
|
||||
if (!seg->update_map) {
|
||||
copy_segment_id(cm, cm->last_frame_seg_map, cm->current_frame_seg_map,
|
||||
mi_offset, x_mis, y_mis);
|
||||
return predicted_segment_id;
|
||||
}
|
||||
|
||||
if (seg->temporal_update) {
|
||||
const vpx_prob pred_prob = vp9_get_pred_prob_seg_id(seg, xd);
|
||||
mi->seg_id_predicted = vpx_read(r, pred_prob);
|
||||
segment_id =
|
||||
mi->seg_id_predicted ? predicted_segment_id : read_segment_id(r, seg);
|
||||
} else {
|
||||
segment_id = read_segment_id(r, seg);
|
||||
}
|
||||
set_segment_id(cm, mi_offset, x_mis, y_mis, segment_id);
|
||||
return segment_id;
|
||||
}
|
||||
|
||||
static int read_skip(VP9_COMMON *cm, const MACROBLOCKD *xd, int segment_id,
|
||||
vpx_reader *r) {
|
||||
if (segfeature_active(&cm->seg, segment_id, SEG_LVL_SKIP)) {
|
||||
return 1;
|
||||
} else {
|
||||
const int ctx = vp9_get_skip_context(xd);
|
||||
const int skip = vpx_read(r, cm->fc->skip_probs[ctx]);
|
||||
FRAME_COUNTS *counts = xd->counts;
|
||||
if (counts) ++counts->skip[ctx][skip];
|
||||
return skip;
|
||||
}
|
||||
}
|
||||
|
||||
static void read_intra_frame_mode_info(VP9_COMMON *const cm,
|
||||
MACROBLOCKD *const xd, int mi_row,
|
||||
int mi_col, vpx_reader *r, int x_mis,
|
||||
int y_mis) {
|
||||
MODE_INFO *const mi = xd->mi[0];
|
||||
const MODE_INFO *above_mi = xd->above_mi;
|
||||
const MODE_INFO *left_mi = xd->left_mi;
|
||||
const BLOCK_SIZE bsize = mi->sb_type;
|
||||
int i;
|
||||
const int mi_offset = mi_row * cm->mi_cols + mi_col;
|
||||
|
||||
mi->segment_id = read_intra_segment_id(cm, mi_offset, x_mis, y_mis, r);
|
||||
mi->skip = read_skip(cm, xd, mi->segment_id, r);
|
||||
mi->tx_size = read_tx_size(cm, xd, 1, r);
|
||||
mi->ref_frame[0] = INTRA_FRAME;
|
||||
mi->ref_frame[1] = NONE;
|
||||
|
||||
switch (bsize) {
|
||||
case BLOCK_4X4:
|
||||
for (i = 0; i < 4; ++i)
|
||||
mi->bmi[i].as_mode =
|
||||
read_intra_mode(r, get_y_mode_probs(mi, above_mi, left_mi, i));
|
||||
mi->mode = mi->bmi[3].as_mode;
|
||||
break;
|
||||
case BLOCK_4X8:
|
||||
mi->bmi[0].as_mode = mi->bmi[2].as_mode =
|
||||
read_intra_mode(r, get_y_mode_probs(mi, above_mi, left_mi, 0));
|
||||
mi->bmi[1].as_mode = mi->bmi[3].as_mode = mi->mode =
|
||||
read_intra_mode(r, get_y_mode_probs(mi, above_mi, left_mi, 1));
|
||||
break;
|
||||
case BLOCK_8X4:
|
||||
mi->bmi[0].as_mode = mi->bmi[1].as_mode =
|
||||
read_intra_mode(r, get_y_mode_probs(mi, above_mi, left_mi, 0));
|
||||
mi->bmi[2].as_mode = mi->bmi[3].as_mode = mi->mode =
|
||||
read_intra_mode(r, get_y_mode_probs(mi, above_mi, left_mi, 2));
|
||||
break;
|
||||
default:
|
||||
mi->mode = read_intra_mode(r, get_y_mode_probs(mi, above_mi, left_mi, 0));
|
||||
}
|
||||
|
||||
mi->uv_mode = read_intra_mode(r, vp9_kf_uv_mode_prob[mi->mode]);
|
||||
}
|
||||
|
||||
static int read_mv_component(vpx_reader *r, const nmv_component *mvcomp,
|
||||
int usehp) {
|
||||
int mag, d, fr, hp;
|
||||
const int sign = vpx_read(r, mvcomp->sign);
|
||||
const int mv_class = vpx_read_tree(r, vp9_mv_class_tree, mvcomp->classes);
|
||||
const int class0 = mv_class == MV_CLASS_0;
|
||||
|
||||
// Integer part
|
||||
if (class0) {
|
||||
d = vpx_read(r, mvcomp->class0[0]);
|
||||
mag = 0;
|
||||
} else {
|
||||
int i;
|
||||
const int n = mv_class + CLASS0_BITS - 1; // number of bits
|
||||
|
||||
d = 0;
|
||||
for (i = 0; i < n; ++i) d |= vpx_read(r, mvcomp->bits[i]) << i;
|
||||
mag = CLASS0_SIZE << (mv_class + 2);
|
||||
}
|
||||
|
||||
// Fractional part
|
||||
fr = vpx_read_tree(r, vp9_mv_fp_tree,
|
||||
class0 ? mvcomp->class0_fp[d] : mvcomp->fp);
|
||||
|
||||
// High precision part (if hp is not used, the default value of the hp is 1)
|
||||
hp = usehp ? vpx_read(r, class0 ? mvcomp->class0_hp : mvcomp->hp) : 1;
|
||||
|
||||
// Result
|
||||
mag += ((d << 3) | (fr << 1) | hp) + 1;
|
||||
return sign ? -mag : mag;
|
||||
}
|
||||
|
||||
static INLINE void read_mv(vpx_reader *r, MV *mv, const MV *ref,
|
||||
const nmv_context *ctx, nmv_context_counts *counts,
|
||||
int allow_hp) {
|
||||
const MV_JOINT_TYPE joint_type =
|
||||
(MV_JOINT_TYPE)vpx_read_tree(r, vp9_mv_joint_tree, ctx->joints);
|
||||
const int use_hp = allow_hp && use_mv_hp(ref);
|
||||
MV diff = { 0, 0 };
|
||||
|
||||
if (mv_joint_vertical(joint_type))
|
||||
diff.row = read_mv_component(r, &ctx->comps[0], use_hp);
|
||||
|
||||
if (mv_joint_horizontal(joint_type))
|
||||
diff.col = read_mv_component(r, &ctx->comps[1], use_hp);
|
||||
|
||||
vp9_inc_mv(&diff, counts);
|
||||
|
||||
mv->row = ref->row + diff.row;
|
||||
mv->col = ref->col + diff.col;
|
||||
}
|
||||
|
||||
static REFERENCE_MODE read_block_reference_mode(VP9_COMMON *cm,
|
||||
const MACROBLOCKD *xd,
|
||||
vpx_reader *r) {
|
||||
if (cm->reference_mode == REFERENCE_MODE_SELECT) {
|
||||
const int ctx = vp9_get_reference_mode_context(cm, xd);
|
||||
const REFERENCE_MODE mode =
|
||||
(REFERENCE_MODE)vpx_read(r, cm->fc->comp_inter_prob[ctx]);
|
||||
FRAME_COUNTS *counts = xd->counts;
|
||||
if (counts) ++counts->comp_inter[ctx][mode];
|
||||
return mode; // SINGLE_REFERENCE or COMPOUND_REFERENCE
|
||||
} else {
|
||||
return cm->reference_mode;
|
||||
}
|
||||
}
|
||||
|
||||
// Read the referncence frame
|
||||
static void read_ref_frames(VP9_COMMON *const cm, MACROBLOCKD *const xd,
|
||||
vpx_reader *r, int segment_id,
|
||||
MV_REFERENCE_FRAME ref_frame[2]) {
|
||||
FRAME_CONTEXT *const fc = cm->fc;
|
||||
FRAME_COUNTS *counts = xd->counts;
|
||||
|
||||
if (segfeature_active(&cm->seg, segment_id, SEG_LVL_REF_FRAME)) {
|
||||
ref_frame[0] = (MV_REFERENCE_FRAME)get_segdata(&cm->seg, segment_id,
|
||||
SEG_LVL_REF_FRAME);
|
||||
ref_frame[1] = NONE;
|
||||
} else {
|
||||
const REFERENCE_MODE mode = read_block_reference_mode(cm, xd, r);
|
||||
// FIXME(rbultje) I'm pretty sure this breaks segmentation ref frame coding
|
||||
if (mode == COMPOUND_REFERENCE) {
|
||||
const int idx = cm->ref_frame_sign_bias[cm->comp_fixed_ref];
|
||||
const int ctx = vp9_get_pred_context_comp_ref_p(cm, xd);
|
||||
const int bit = vpx_read(r, fc->comp_ref_prob[ctx]);
|
||||
if (counts) ++counts->comp_ref[ctx][bit];
|
||||
ref_frame[idx] = cm->comp_fixed_ref;
|
||||
ref_frame[!idx] = cm->comp_var_ref[bit];
|
||||
} else if (mode == SINGLE_REFERENCE) {
|
||||
const int ctx0 = vp9_get_pred_context_single_ref_p1(xd);
|
||||
const int bit0 = vpx_read(r, fc->single_ref_prob[ctx0][0]);
|
||||
if (counts) ++counts->single_ref[ctx0][0][bit0];
|
||||
if (bit0) {
|
||||
const int ctx1 = vp9_get_pred_context_single_ref_p2(xd);
|
||||
const int bit1 = vpx_read(r, fc->single_ref_prob[ctx1][1]);
|
||||
if (counts) ++counts->single_ref[ctx1][1][bit1];
|
||||
ref_frame[0] = bit1 ? ALTREF_FRAME : GOLDEN_FRAME;
|
||||
} else {
|
||||
ref_frame[0] = LAST_FRAME;
|
||||
}
|
||||
|
||||
ref_frame[1] = NONE;
|
||||
} else {
|
||||
assert(0 && "Invalid prediction mode.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static INLINE INTERP_FILTER read_switchable_interp_filter(VP9_COMMON *const cm,
|
||||
MACROBLOCKD *const xd,
|
||||
vpx_reader *r) {
|
||||
const int ctx = get_pred_context_switchable_interp(xd);
|
||||
const INTERP_FILTER type = (INTERP_FILTER)vpx_read_tree(
|
||||
r, vp9_switchable_interp_tree, cm->fc->switchable_interp_prob[ctx]);
|
||||
FRAME_COUNTS *counts = xd->counts;
|
||||
if (counts) ++counts->switchable_interp[ctx][type];
|
||||
return type;
|
||||
}
|
||||
|
||||
static void read_intra_block_mode_info(VP9_COMMON *const cm,
|
||||
MACROBLOCKD *const xd, MODE_INFO *mi,
|
||||
vpx_reader *r) {
|
||||
const BLOCK_SIZE bsize = mi->sb_type;
|
||||
int i;
|
||||
|
||||
switch (bsize) {
|
||||
case BLOCK_4X4:
|
||||
for (i = 0; i < 4; ++i)
|
||||
mi->bmi[i].as_mode = read_intra_mode_y(cm, xd, r, 0);
|
||||
mi->mode = mi->bmi[3].as_mode;
|
||||
break;
|
||||
case BLOCK_4X8:
|
||||
mi->bmi[0].as_mode = mi->bmi[2].as_mode = read_intra_mode_y(cm, xd, r, 0);
|
||||
mi->bmi[1].as_mode = mi->bmi[3].as_mode = mi->mode =
|
||||
read_intra_mode_y(cm, xd, r, 0);
|
||||
break;
|
||||
case BLOCK_8X4:
|
||||
mi->bmi[0].as_mode = mi->bmi[1].as_mode = read_intra_mode_y(cm, xd, r, 0);
|
||||
mi->bmi[2].as_mode = mi->bmi[3].as_mode = mi->mode =
|
||||
read_intra_mode_y(cm, xd, r, 0);
|
||||
break;
|
||||
default: mi->mode = read_intra_mode_y(cm, xd, r, size_group_lookup[bsize]);
|
||||
}
|
||||
|
||||
mi->uv_mode = read_intra_mode_uv(cm, xd, r, mi->mode);
|
||||
|
||||
// Initialize interp_filter here so we do not have to check for inter block
|
||||
// modes in get_pred_context_switchable_interp()
|
||||
mi->interp_filter = SWITCHABLE_FILTERS;
|
||||
|
||||
mi->ref_frame[0] = INTRA_FRAME;
|
||||
mi->ref_frame[1] = NONE;
|
||||
}
|
||||
|
||||
static INLINE int is_mv_valid(const MV *mv) {
|
||||
return mv->row > MV_LOW && mv->row < MV_UPP && mv->col > MV_LOW &&
|
||||
mv->col < MV_UPP;
|
||||
}
|
||||
|
||||
static INLINE void copy_mv_pair(int_mv *dst, const int_mv *src) {
|
||||
memcpy(dst, src, sizeof(*dst) * 2);
|
||||
}
|
||||
|
||||
static INLINE void zero_mv_pair(int_mv *dst) {
|
||||
memset(dst, 0, sizeof(*dst) * 2);
|
||||
}
|
||||
|
||||
static INLINE int assign_mv(VP9_COMMON *cm, MACROBLOCKD *xd,
|
||||
PREDICTION_MODE mode, int_mv mv[2],
|
||||
int_mv ref_mv[2], int_mv near_nearest_mv[2],
|
||||
int is_compound, int allow_hp, vpx_reader *r) {
|
||||
int i;
|
||||
int ret = 1;
|
||||
|
||||
switch (mode) {
|
||||
case NEWMV: {
|
||||
FRAME_COUNTS *counts = xd->counts;
|
||||
nmv_context_counts *const mv_counts = counts ? &counts->mv : NULL;
|
||||
for (i = 0; i < 1 + is_compound; ++i) {
|
||||
read_mv(r, &mv[i].as_mv, &ref_mv[i].as_mv, &cm->fc->nmvc, mv_counts,
|
||||
allow_hp);
|
||||
ret = ret && is_mv_valid(&mv[i].as_mv);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NEARMV:
|
||||
case NEARESTMV: {
|
||||
copy_mv_pair(mv, near_nearest_mv);
|
||||
break;
|
||||
}
|
||||
case ZEROMV: {
|
||||
zero_mv_pair(mv);
|
||||
break;
|
||||
}
|
||||
default: { return 0; }
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int read_is_inter_block(VP9_COMMON *const cm, MACROBLOCKD *const xd,
|
||||
int segment_id, vpx_reader *r) {
|
||||
if (segfeature_active(&cm->seg, segment_id, SEG_LVL_REF_FRAME)) {
|
||||
return get_segdata(&cm->seg, segment_id, SEG_LVL_REF_FRAME) != INTRA_FRAME;
|
||||
} else {
|
||||
const int ctx = get_intra_inter_context(xd);
|
||||
const int is_inter = vpx_read(r, cm->fc->intra_inter_prob[ctx]);
|
||||
FRAME_COUNTS *counts = xd->counts;
|
||||
if (counts) ++counts->intra_inter[ctx][is_inter];
|
||||
return is_inter;
|
||||
}
|
||||
}
|
||||
|
||||
// This macro is used to add a motion vector mv_ref list if it isn't
|
||||
// already in the list. If it's the second motion vector or early_break
|
||||
// it will also skip all additional processing and jump to Done!
|
||||
#define ADD_MV_REF_LIST_EB(mv, refmv_count, mv_ref_list, Done) \
|
||||
do { \
|
||||
if (refmv_count) { \
|
||||
if ((mv).as_int != (mv_ref_list)[0].as_int) { \
|
||||
(mv_ref_list)[(refmv_count)] = (mv); \
|
||||
refmv_count++; \
|
||||
goto Done; \
|
||||
} \
|
||||
} else { \
|
||||
(mv_ref_list)[(refmv_count)++] = (mv); \
|
||||
if (early_break) goto Done; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// If either reference frame is different, not INTRA, and they
|
||||
// are different from each other scale and add the mv to our list.
|
||||
#define IF_DIFF_REF_FRAME_ADD_MV_EB(mbmi, ref_frame, ref_sign_bias, \
|
||||
refmv_count, mv_ref_list, Done) \
|
||||
do { \
|
||||
if (is_inter_block(mbmi)) { \
|
||||
if ((mbmi)->ref_frame[0] != ref_frame) \
|
||||
ADD_MV_REF_LIST_EB(scale_mv((mbmi), 0, ref_frame, ref_sign_bias), \
|
||||
refmv_count, mv_ref_list, Done); \
|
||||
if (has_second_ref(mbmi) && (mbmi)->ref_frame[1] != ref_frame && \
|
||||
(mbmi)->mv[1].as_int != (mbmi)->mv[0].as_int) \
|
||||
ADD_MV_REF_LIST_EB(scale_mv((mbmi), 1, ref_frame, ref_sign_bias), \
|
||||
refmv_count, mv_ref_list, Done); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// This function searches the neighborhood of a given MB/SB
|
||||
// to try and find candidate reference vectors.
|
||||
static int dec_find_mv_refs(const VP9_COMMON *cm, const MACROBLOCKD *xd,
|
||||
PREDICTION_MODE mode, MV_REFERENCE_FRAME ref_frame,
|
||||
const POSITION *const mv_ref_search,
|
||||
int_mv *mv_ref_list, int mi_row, int mi_col,
|
||||
int block) {
|
||||
const int *ref_sign_bias = cm->ref_frame_sign_bias;
|
||||
int i, refmv_count = 0;
|
||||
int different_ref_found = 0;
|
||||
const MV_REF *const prev_frame_mvs =
|
||||
cm->use_prev_frame_mvs
|
||||
? cm->prev_frame->mvs + mi_row * cm->mi_cols + mi_col
|
||||
: NULL;
|
||||
const TileInfo *const tile = &xd->tile;
|
||||
// If mode is nearestmv or newmv (uses nearestmv as a reference) then stop
|
||||
// searching after the first mv is found.
|
||||
const int early_break = (mode != NEARMV);
|
||||
|
||||
// Blank the reference vector list
|
||||
memset(mv_ref_list, 0, sizeof(*mv_ref_list) * MAX_MV_REF_CANDIDATES);
|
||||
|
||||
i = 0;
|
||||
if (block >= 0) {
|
||||
// If the size < 8x8 we get the mv from the bmi substructure for the
|
||||
// nearest two blocks.
|
||||
for (i = 0; i < 2; ++i) {
|
||||
const POSITION *const mv_ref = &mv_ref_search[i];
|
||||
if (is_inside(tile, mi_col, mi_row, cm->mi_rows, mv_ref)) {
|
||||
const MODE_INFO *const candidate_mi =
|
||||
xd->mi[mv_ref->col + mv_ref->row * xd->mi_stride];
|
||||
different_ref_found = 1;
|
||||
|
||||
if (candidate_mi->ref_frame[0] == ref_frame)
|
||||
ADD_MV_REF_LIST_EB(
|
||||
get_sub_block_mv(candidate_mi, 0, mv_ref->col, block),
|
||||
refmv_count, mv_ref_list, Done);
|
||||
else if (candidate_mi->ref_frame[1] == ref_frame)
|
||||
ADD_MV_REF_LIST_EB(
|
||||
get_sub_block_mv(candidate_mi, 1, mv_ref->col, block),
|
||||
refmv_count, mv_ref_list, Done);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check the rest of the neighbors in much the same way
|
||||
// as before except we don't need to keep track of sub blocks or
|
||||
// mode counts.
|
||||
for (; i < MVREF_NEIGHBOURS; ++i) {
|
||||
const POSITION *const mv_ref = &mv_ref_search[i];
|
||||
if (is_inside(tile, mi_col, mi_row, cm->mi_rows, mv_ref)) {
|
||||
const MODE_INFO *const candidate =
|
||||
xd->mi[mv_ref->col + mv_ref->row * xd->mi_stride];
|
||||
different_ref_found = 1;
|
||||
|
||||
if (candidate->ref_frame[0] == ref_frame)
|
||||
ADD_MV_REF_LIST_EB(candidate->mv[0], refmv_count, mv_ref_list, Done);
|
||||
else if (candidate->ref_frame[1] == ref_frame)
|
||||
ADD_MV_REF_LIST_EB(candidate->mv[1], refmv_count, mv_ref_list, Done);
|
||||
}
|
||||
}
|
||||
|
||||
// Check the last frame's mode and mv info.
|
||||
if (prev_frame_mvs) {
|
||||
if (prev_frame_mvs->ref_frame[0] == ref_frame) {
|
||||
ADD_MV_REF_LIST_EB(prev_frame_mvs->mv[0], refmv_count, mv_ref_list, Done);
|
||||
} else if (prev_frame_mvs->ref_frame[1] == ref_frame) {
|
||||
ADD_MV_REF_LIST_EB(prev_frame_mvs->mv[1], refmv_count, mv_ref_list, Done);
|
||||
}
|
||||
}
|
||||
|
||||
// Since we couldn't find 2 mvs from the same reference frame
|
||||
// go back through the neighbors and find motion vectors from
|
||||
// different reference frames.
|
||||
if (different_ref_found) {
|
||||
for (i = 0; i < MVREF_NEIGHBOURS; ++i) {
|
||||
const POSITION *mv_ref = &mv_ref_search[i];
|
||||
if (is_inside(tile, mi_col, mi_row, cm->mi_rows, mv_ref)) {
|
||||
const MODE_INFO *const candidate =
|
||||
xd->mi[mv_ref->col + mv_ref->row * xd->mi_stride];
|
||||
|
||||
// If the candidate is INTRA we don't want to consider its mv.
|
||||
IF_DIFF_REF_FRAME_ADD_MV_EB(candidate, ref_frame, ref_sign_bias,
|
||||
refmv_count, mv_ref_list, Done);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Since we still don't have a candidate we'll try the last frame.
|
||||
if (prev_frame_mvs) {
|
||||
if (prev_frame_mvs->ref_frame[0] != ref_frame &&
|
||||
prev_frame_mvs->ref_frame[0] > INTRA_FRAME) {
|
||||
int_mv mv = prev_frame_mvs->mv[0];
|
||||
if (ref_sign_bias[prev_frame_mvs->ref_frame[0]] !=
|
||||
ref_sign_bias[ref_frame]) {
|
||||
mv.as_mv.row *= -1;
|
||||
mv.as_mv.col *= -1;
|
||||
}
|
||||
ADD_MV_REF_LIST_EB(mv, refmv_count, mv_ref_list, Done);
|
||||
}
|
||||
|
||||
if (prev_frame_mvs->ref_frame[1] > INTRA_FRAME &&
|
||||
prev_frame_mvs->ref_frame[1] != ref_frame &&
|
||||
prev_frame_mvs->mv[1].as_int != prev_frame_mvs->mv[0].as_int) {
|
||||
int_mv mv = prev_frame_mvs->mv[1];
|
||||
if (ref_sign_bias[prev_frame_mvs->ref_frame[1]] !=
|
||||
ref_sign_bias[ref_frame]) {
|
||||
mv.as_mv.row *= -1;
|
||||
mv.as_mv.col *= -1;
|
||||
}
|
||||
ADD_MV_REF_LIST_EB(mv, refmv_count, mv_ref_list, Done);
|
||||
}
|
||||
}
|
||||
|
||||
if (mode == NEARMV)
|
||||
refmv_count = MAX_MV_REF_CANDIDATES;
|
||||
else
|
||||
// we only care about the nearestmv for the remaining modes
|
||||
refmv_count = 1;
|
||||
|
||||
Done:
|
||||
// Clamp vectors
|
||||
for (i = 0; i < refmv_count; ++i) clamp_mv_ref(&mv_ref_list[i].as_mv, xd);
|
||||
|
||||
return refmv_count;
|
||||
}
|
||||
|
||||
static void append_sub8x8_mvs_for_idx(VP9_COMMON *cm, MACROBLOCKD *xd,
|
||||
const POSITION *const mv_ref_search,
|
||||
PREDICTION_MODE b_mode, int block,
|
||||
int ref, int mi_row, int mi_col,
|
||||
int_mv *best_sub8x8) {
|
||||
int_mv mv_list[MAX_MV_REF_CANDIDATES];
|
||||
MODE_INFO *const mi = xd->mi[0];
|
||||
b_mode_info *bmi = mi->bmi;
|
||||
int n;
|
||||
int refmv_count;
|
||||
|
||||
assert(MAX_MV_REF_CANDIDATES == 2);
|
||||
|
||||
switch (block) {
|
||||
case 0:
|
||||
refmv_count =
|
||||
dec_find_mv_refs(cm, xd, b_mode, mi->ref_frame[ref], mv_ref_search,
|
||||
mv_list, mi_row, mi_col, block);
|
||||
best_sub8x8->as_int = mv_list[refmv_count - 1].as_int;
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
if (b_mode == NEARESTMV) {
|
||||
best_sub8x8->as_int = bmi[0].as_mv[ref].as_int;
|
||||
} else {
|
||||
dec_find_mv_refs(cm, xd, b_mode, mi->ref_frame[ref], mv_ref_search,
|
||||
mv_list, mi_row, mi_col, block);
|
||||
best_sub8x8->as_int = 0;
|
||||
for (n = 0; n < 2; ++n)
|
||||
if (bmi[0].as_mv[ref].as_int != mv_list[n].as_int) {
|
||||
best_sub8x8->as_int = mv_list[n].as_int;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (b_mode == NEARESTMV) {
|
||||
best_sub8x8->as_int = bmi[2].as_mv[ref].as_int;
|
||||
} else {
|
||||
best_sub8x8->as_int = 0;
|
||||
if (bmi[2].as_mv[ref].as_int != bmi[1].as_mv[ref].as_int) {
|
||||
best_sub8x8->as_int = bmi[1].as_mv[ref].as_int;
|
||||
break;
|
||||
}
|
||||
if (bmi[2].as_mv[ref].as_int != bmi[0].as_mv[ref].as_int) {
|
||||
best_sub8x8->as_int = bmi[0].as_mv[ref].as_int;
|
||||
break;
|
||||
}
|
||||
dec_find_mv_refs(cm, xd, b_mode, mi->ref_frame[ref], mv_ref_search,
|
||||
mv_list, mi_row, mi_col, block);
|
||||
for (n = 0; n < 2; ++n)
|
||||
if (bmi[2].as_mv[ref].as_int != mv_list[n].as_int) {
|
||||
best_sub8x8->as_int = mv_list[n].as_int;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default: assert(0 && "Invalid block index.");
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t get_mode_context(const VP9_COMMON *cm, const MACROBLOCKD *xd,
|
||||
const POSITION *const mv_ref_search, int mi_row,
|
||||
int mi_col) {
|
||||
int i;
|
||||
int context_counter = 0;
|
||||
const TileInfo *const tile = &xd->tile;
|
||||
|
||||
// Get mode count from nearest 2 blocks
|
||||
for (i = 0; i < 2; ++i) {
|
||||
const POSITION *const mv_ref = &mv_ref_search[i];
|
||||
if (is_inside(tile, mi_col, mi_row, cm->mi_rows, mv_ref)) {
|
||||
const MODE_INFO *const candidate =
|
||||
xd->mi[mv_ref->col + mv_ref->row * xd->mi_stride];
|
||||
// Keep counts for entropy encoding.
|
||||
context_counter += mode_2_counter[candidate->mode];
|
||||
}
|
||||
}
|
||||
|
||||
return counter_to_context[context_counter];
|
||||
}
|
||||
|
||||
static void read_inter_block_mode_info(VP9Decoder *const pbi,
|
||||
MACROBLOCKD *const xd,
|
||||
MODE_INFO *const mi, int mi_row,
|
||||
int mi_col, vpx_reader *r) {
|
||||
VP9_COMMON *const cm = &pbi->common;
|
||||
const BLOCK_SIZE bsize = mi->sb_type;
|
||||
const int allow_hp = cm->allow_high_precision_mv;
|
||||
int_mv best_ref_mvs[2] = { { 0 }, { 0 } };
|
||||
int ref, is_compound;
|
||||
uint8_t inter_mode_ctx;
|
||||
const POSITION *const mv_ref_search = mv_ref_blocks[bsize];
|
||||
|
||||
read_ref_frames(cm, xd, r, mi->segment_id, mi->ref_frame);
|
||||
is_compound = has_second_ref(mi);
|
||||
inter_mode_ctx = get_mode_context(cm, xd, mv_ref_search, mi_row, mi_col);
|
||||
|
||||
if (segfeature_active(&cm->seg, mi->segment_id, SEG_LVL_SKIP)) {
|
||||
mi->mode = ZEROMV;
|
||||
if (bsize < BLOCK_8X8) {
|
||||
vpx_internal_error(xd->error_info, VPX_CODEC_UNSUP_BITSTREAM,
|
||||
"Invalid usage of segement feature on small blocks");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (bsize >= BLOCK_8X8)
|
||||
mi->mode = read_inter_mode(cm, xd, r, inter_mode_ctx);
|
||||
}
|
||||
|
||||
mi->interp_filter = (cm->interp_filter == SWITCHABLE)
|
||||
? read_switchable_interp_filter(cm, xd, r)
|
||||
: cm->interp_filter;
|
||||
|
||||
if (bsize < BLOCK_8X8) {
|
||||
const int num_4x4_w = 1 << xd->bmode_blocks_wl;
|
||||
const int num_4x4_h = 1 << xd->bmode_blocks_hl;
|
||||
int idx, idy;
|
||||
PREDICTION_MODE b_mode;
|
||||
int got_mv_refs_for_new = 0;
|
||||
int_mv best_sub8x8[2];
|
||||
const uint32_t invalid_mv = 0x80008000;
|
||||
// Initialize the 2nd element as even though it won't be used meaningfully
|
||||
// if is_compound is false, copying/clamping it may trigger a MSan warning.
|
||||
best_sub8x8[1].as_int = invalid_mv;
|
||||
for (idy = 0; idy < 2; idy += num_4x4_h) {
|
||||
for (idx = 0; idx < 2; idx += num_4x4_w) {
|
||||
const int j = idy * 2 + idx;
|
||||
b_mode = read_inter_mode(cm, xd, r, inter_mode_ctx);
|
||||
|
||||
if (b_mode == NEARESTMV || b_mode == NEARMV) {
|
||||
for (ref = 0; ref < 1 + is_compound; ++ref)
|
||||
append_sub8x8_mvs_for_idx(cm, xd, mv_ref_search, b_mode, j, ref,
|
||||
mi_row, mi_col, &best_sub8x8[ref]);
|
||||
} else if (b_mode == NEWMV && !got_mv_refs_for_new) {
|
||||
for (ref = 0; ref < 1 + is_compound; ++ref) {
|
||||
int_mv tmp_mvs[MAX_MV_REF_CANDIDATES];
|
||||
const MV_REFERENCE_FRAME frame = mi->ref_frame[ref];
|
||||
|
||||
dec_find_mv_refs(cm, xd, NEWMV, frame, mv_ref_search, tmp_mvs,
|
||||
mi_row, mi_col, -1);
|
||||
|
||||
lower_mv_precision(&tmp_mvs[0].as_mv, allow_hp);
|
||||
best_ref_mvs[ref] = tmp_mvs[0];
|
||||
got_mv_refs_for_new = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!assign_mv(cm, xd, b_mode, mi->bmi[j].as_mv, best_ref_mvs,
|
||||
best_sub8x8, is_compound, allow_hp, r)) {
|
||||
xd->corrupted |= 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (num_4x4_h == 2) mi->bmi[j + 2] = mi->bmi[j];
|
||||
if (num_4x4_w == 2) mi->bmi[j + 1] = mi->bmi[j];
|
||||
}
|
||||
}
|
||||
|
||||
mi->mode = b_mode;
|
||||
|
||||
copy_mv_pair(mi->mv, mi->bmi[3].as_mv);
|
||||
} else {
|
||||
if (mi->mode != ZEROMV) {
|
||||
for (ref = 0; ref < 1 + is_compound; ++ref) {
|
||||
int_mv tmp_mvs[MAX_MV_REF_CANDIDATES];
|
||||
const MV_REFERENCE_FRAME frame = mi->ref_frame[ref];
|
||||
int refmv_count =
|
||||
dec_find_mv_refs(cm, xd, mi->mode, frame, mv_ref_search, tmp_mvs,
|
||||
mi_row, mi_col, -1);
|
||||
lower_mv_precision(&tmp_mvs[refmv_count - 1].as_mv, allow_hp);
|
||||
best_ref_mvs[ref] = tmp_mvs[refmv_count - 1];
|
||||
}
|
||||
}
|
||||
xd->corrupted |= !assign_mv(cm, xd, mi->mode, mi->mv, best_ref_mvs,
|
||||
best_ref_mvs, is_compound, allow_hp, r);
|
||||
}
|
||||
}
|
||||
|
||||
static void read_inter_frame_mode_info(VP9Decoder *const pbi,
|
||||
MACROBLOCKD *const xd, int mi_row,
|
||||
int mi_col, vpx_reader *r, int x_mis,
|
||||
int y_mis) {
|
||||
VP9_COMMON *const cm = &pbi->common;
|
||||
MODE_INFO *const mi = xd->mi[0];
|
||||
int inter_block;
|
||||
|
||||
mi->segment_id =
|
||||
read_inter_segment_id(cm, xd, mi_row, mi_col, r, x_mis, y_mis);
|
||||
mi->skip = read_skip(cm, xd, mi->segment_id, r);
|
||||
inter_block = read_is_inter_block(cm, xd, mi->segment_id, r);
|
||||
mi->tx_size = read_tx_size(cm, xd, !mi->skip || !inter_block, r);
|
||||
|
||||
if (inter_block)
|
||||
read_inter_block_mode_info(pbi, xd, mi, mi_row, mi_col, r);
|
||||
else
|
||||
read_intra_block_mode_info(cm, xd, mi, r);
|
||||
}
|
||||
|
||||
static INLINE void copy_ref_frame_pair(MV_REFERENCE_FRAME *dst,
|
||||
const MV_REFERENCE_FRAME *src) {
|
||||
memcpy(dst, src, sizeof(*dst) * 2);
|
||||
}
|
||||
|
||||
void vp9_read_mode_info(TileWorkerData *twd, VP9Decoder *const pbi, int mi_row,
|
||||
int mi_col, int x_mis, int y_mis) {
|
||||
vpx_reader *r = &twd->bit_reader;
|
||||
MACROBLOCKD *const xd = &twd->xd;
|
||||
VP9_COMMON *const cm = &pbi->common;
|
||||
MODE_INFO *const mi = xd->mi[0];
|
||||
MV_REF *frame_mvs = cm->cur_frame->mvs + mi_row * cm->mi_cols + mi_col;
|
||||
int w, h;
|
||||
|
||||
if (frame_is_intra_only(cm)) {
|
||||
read_intra_frame_mode_info(cm, xd, mi_row, mi_col, r, x_mis, y_mis);
|
||||
} else {
|
||||
read_inter_frame_mode_info(pbi, xd, mi_row, mi_col, r, x_mis, y_mis);
|
||||
|
||||
for (h = 0; h < y_mis; ++h) {
|
||||
for (w = 0; w < x_mis; ++w) {
|
||||
MV_REF *const mv = frame_mvs + w;
|
||||
copy_ref_frame_pair(mv->ref_frame, mi->ref_frame);
|
||||
copy_mv_pair(mv->mv, mi->mv);
|
||||
}
|
||||
frame_mvs += cm->mi_cols;
|
||||
}
|
||||
}
|
||||
#if 0 // CONFIG_BETTER_HW_COMPATIBILITY && CONFIG_VP9_HIGHBITDEPTH
|
||||
if ((xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) &&
|
||||
(xd->above_mi == NULL || xd->left_mi == NULL) &&
|
||||
!is_inter_block(mi) && need_top_left[mi->uv_mode])
|
||||
assert(0);
|
||||
#endif // CONFIG_BETTER_HW_COMPATIBILITY && CONFIG_VP9_HIGHBITDEPTH
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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 VPX_VP9_DECODER_VP9_DECODEMV_H_
|
||||
#define VPX_VP9_DECODER_VP9_DECODEMV_H_
|
||||
|
||||
#include "vpx_dsp/bitreader.h"
|
||||
|
||||
#include "vp9/decoder/vp9_decoder.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void vp9_read_mode_info(TileWorkerData *twd, VP9Decoder *const pbi, int mi_row,
|
||||
int mi_col, int x_mis, int y_mis);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_DECODER_VP9_DECODEMV_H_
|
||||
@@ -0,0 +1,579 @@
|
||||
/*
|
||||
* 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 <stdio.h>
|
||||
|
||||
#include "./vp9_rtcd.h"
|
||||
#include "./vpx_dsp_rtcd.h"
|
||||
#include "./vpx_scale_rtcd.h"
|
||||
|
||||
#include "vpx_mem/vpx_mem.h"
|
||||
#include "vpx_ports/system_state.h"
|
||||
#include "vpx_ports/vpx_once.h"
|
||||
#include "vpx_ports/vpx_timer.h"
|
||||
#include "vpx_scale/vpx_scale.h"
|
||||
#include "vpx_util/vpx_thread.h"
|
||||
|
||||
#include "vp9/common/vp9_alloccommon.h"
|
||||
#include "vp9/common/vp9_loopfilter.h"
|
||||
#include "vp9/common/vp9_onyxc_int.h"
|
||||
#if CONFIG_VP9_POSTPROC
|
||||
#include "vp9/common/vp9_postproc.h"
|
||||
#endif
|
||||
#include "vp9/common/vp9_quant_common.h"
|
||||
#include "vp9/common/vp9_reconintra.h"
|
||||
|
||||
#include "vp9/decoder/vp9_decodeframe.h"
|
||||
#include "vp9/decoder/vp9_decoder.h"
|
||||
#include "vp9/decoder/vp9_detokenize.h"
|
||||
|
||||
static void initialize_dec(void) {
|
||||
static volatile int init_done = 0;
|
||||
|
||||
if (!init_done) {
|
||||
vp9_rtcd();
|
||||
vpx_dsp_rtcd();
|
||||
vpx_scale_rtcd();
|
||||
vp9_init_intra_predictors();
|
||||
init_done = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void vp9_dec_setup_mi(VP9_COMMON *cm) {
|
||||
cm->mi = cm->mip + cm->mi_stride + 1;
|
||||
cm->mi_grid_visible = cm->mi_grid_base + cm->mi_stride + 1;
|
||||
memset(cm->mi_grid_base, 0,
|
||||
cm->mi_stride * (cm->mi_rows + 1) * sizeof(*cm->mi_grid_base));
|
||||
}
|
||||
|
||||
void vp9_dec_alloc_row_mt_mem(RowMTWorkerData *row_mt_worker_data,
|
||||
VP9_COMMON *cm, int num_sbs, int max_threads,
|
||||
int num_jobs) {
|
||||
int plane;
|
||||
const size_t dqcoeff_size = (num_sbs << DQCOEFFS_PER_SB_LOG2) *
|
||||
sizeof(*row_mt_worker_data->dqcoeff[0]);
|
||||
row_mt_worker_data->num_jobs = num_jobs;
|
||||
#if CONFIG_MULTITHREAD
|
||||
{
|
||||
int i;
|
||||
CHECK_MEM_ERROR(
|
||||
cm, row_mt_worker_data->recon_sync_mutex,
|
||||
vpx_malloc(sizeof(*row_mt_worker_data->recon_sync_mutex) * num_jobs));
|
||||
if (row_mt_worker_data->recon_sync_mutex) {
|
||||
for (i = 0; i < num_jobs; ++i) {
|
||||
pthread_mutex_init(&row_mt_worker_data->recon_sync_mutex[i], NULL);
|
||||
}
|
||||
}
|
||||
|
||||
CHECK_MEM_ERROR(
|
||||
cm, row_mt_worker_data->recon_sync_cond,
|
||||
vpx_malloc(sizeof(*row_mt_worker_data->recon_sync_cond) * num_jobs));
|
||||
if (row_mt_worker_data->recon_sync_cond) {
|
||||
for (i = 0; i < num_jobs; ++i) {
|
||||
pthread_cond_init(&row_mt_worker_data->recon_sync_cond[i], NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
row_mt_worker_data->num_sbs = num_sbs;
|
||||
for (plane = 0; plane < 3; ++plane) {
|
||||
CHECK_MEM_ERROR(cm, row_mt_worker_data->dqcoeff[plane],
|
||||
vpx_memalign(16, dqcoeff_size));
|
||||
memset(row_mt_worker_data->dqcoeff[plane], 0, dqcoeff_size);
|
||||
CHECK_MEM_ERROR(cm, row_mt_worker_data->eob[plane],
|
||||
vpx_calloc(num_sbs << EOBS_PER_SB_LOG2,
|
||||
sizeof(*row_mt_worker_data->eob[plane])));
|
||||
}
|
||||
CHECK_MEM_ERROR(cm, row_mt_worker_data->partition,
|
||||
vpx_calloc(num_sbs * PARTITIONS_PER_SB,
|
||||
sizeof(*row_mt_worker_data->partition)));
|
||||
CHECK_MEM_ERROR(cm, row_mt_worker_data->recon_map,
|
||||
vpx_calloc(num_sbs, sizeof(*row_mt_worker_data->recon_map)));
|
||||
|
||||
// allocate memory for thread_data
|
||||
if (row_mt_worker_data->thread_data == NULL) {
|
||||
const size_t thread_size =
|
||||
max_threads * sizeof(*row_mt_worker_data->thread_data);
|
||||
CHECK_MEM_ERROR(cm, row_mt_worker_data->thread_data,
|
||||
vpx_memalign(32, thread_size));
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_dec_free_row_mt_mem(RowMTWorkerData *row_mt_worker_data) {
|
||||
if (row_mt_worker_data != NULL) {
|
||||
int plane;
|
||||
#if CONFIG_MULTITHREAD
|
||||
int i;
|
||||
if (row_mt_worker_data->recon_sync_mutex != NULL) {
|
||||
for (i = 0; i < row_mt_worker_data->num_jobs; ++i) {
|
||||
pthread_mutex_destroy(&row_mt_worker_data->recon_sync_mutex[i]);
|
||||
}
|
||||
vpx_free(row_mt_worker_data->recon_sync_mutex);
|
||||
row_mt_worker_data->recon_sync_mutex = NULL;
|
||||
}
|
||||
if (row_mt_worker_data->recon_sync_cond != NULL) {
|
||||
for (i = 0; i < row_mt_worker_data->num_jobs; ++i) {
|
||||
pthread_cond_destroy(&row_mt_worker_data->recon_sync_cond[i]);
|
||||
}
|
||||
vpx_free(row_mt_worker_data->recon_sync_cond);
|
||||
row_mt_worker_data->recon_sync_cond = NULL;
|
||||
}
|
||||
#endif
|
||||
for (plane = 0; plane < 3; ++plane) {
|
||||
vpx_free(row_mt_worker_data->eob[plane]);
|
||||
row_mt_worker_data->eob[plane] = NULL;
|
||||
vpx_free(row_mt_worker_data->dqcoeff[plane]);
|
||||
row_mt_worker_data->dqcoeff[plane] = NULL;
|
||||
}
|
||||
vpx_free(row_mt_worker_data->partition);
|
||||
row_mt_worker_data->partition = NULL;
|
||||
vpx_free(row_mt_worker_data->recon_map);
|
||||
row_mt_worker_data->recon_map = NULL;
|
||||
vpx_free(row_mt_worker_data->thread_data);
|
||||
row_mt_worker_data->thread_data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int vp9_dec_alloc_mi(VP9_COMMON *cm, int mi_size) {
|
||||
cm->mip = vpx_calloc(mi_size, sizeof(*cm->mip));
|
||||
if (!cm->mip) return 1;
|
||||
cm->mi_alloc_size = mi_size;
|
||||
cm->mi_grid_base = (MODE_INFO **)vpx_calloc(mi_size, sizeof(MODE_INFO *));
|
||||
if (!cm->mi_grid_base) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vp9_dec_free_mi(VP9_COMMON *cm) {
|
||||
vpx_free(cm->mip);
|
||||
cm->mip = NULL;
|
||||
vpx_free(cm->mi_grid_base);
|
||||
cm->mi_grid_base = NULL;
|
||||
cm->mi_alloc_size = 0;
|
||||
}
|
||||
|
||||
VP9Decoder *vp9_decoder_create(BufferPool *const pool) {
|
||||
VP9Decoder *volatile const pbi = vpx_memalign(32, sizeof(*pbi));
|
||||
VP9_COMMON *volatile const cm = pbi ? &pbi->common : NULL;
|
||||
|
||||
if (!cm) return NULL;
|
||||
|
||||
vp9_zero(*pbi);
|
||||
|
||||
if (setjmp(cm->error.jmp)) {
|
||||
cm->error.setjmp = 0;
|
||||
vp9_decoder_remove(pbi);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cm->error.setjmp = 1;
|
||||
|
||||
CHECK_MEM_ERROR(cm, cm->fc, (FRAME_CONTEXT *)vpx_calloc(1, sizeof(*cm->fc)));
|
||||
CHECK_MEM_ERROR(
|
||||
cm, cm->frame_contexts,
|
||||
(FRAME_CONTEXT *)vpx_calloc(FRAME_CONTEXTS, sizeof(*cm->frame_contexts)));
|
||||
|
||||
pbi->need_resync = 1;
|
||||
once(initialize_dec);
|
||||
|
||||
// Initialize the references to not point to any frame buffers.
|
||||
memset(&cm->ref_frame_map, -1, sizeof(cm->ref_frame_map));
|
||||
memset(&cm->next_ref_frame_map, -1, sizeof(cm->next_ref_frame_map));
|
||||
|
||||
cm->current_video_frame = 0;
|
||||
pbi->ready_for_new_data = 1;
|
||||
pbi->common.buffer_pool = pool;
|
||||
|
||||
cm->bit_depth = VPX_BITS_8;
|
||||
cm->dequant_bit_depth = VPX_BITS_8;
|
||||
|
||||
cm->alloc_mi = vp9_dec_alloc_mi;
|
||||
cm->free_mi = vp9_dec_free_mi;
|
||||
cm->setup_mi = vp9_dec_setup_mi;
|
||||
|
||||
vp9_loop_filter_init(cm);
|
||||
|
||||
cm->error.setjmp = 0;
|
||||
|
||||
vpx_get_worker_interface()->init(&pbi->lf_worker);
|
||||
|
||||
return pbi;
|
||||
}
|
||||
|
||||
void vp9_decoder_remove(VP9Decoder *pbi) {
|
||||
int i;
|
||||
|
||||
if (!pbi) return;
|
||||
|
||||
vpx_get_worker_interface()->end(&pbi->lf_worker);
|
||||
vpx_free(pbi->lf_worker.data1);
|
||||
|
||||
for (i = 0; i < pbi->num_tile_workers; ++i) {
|
||||
VPxWorker *const worker = &pbi->tile_workers[i];
|
||||
vpx_get_worker_interface()->end(worker);
|
||||
}
|
||||
|
||||
vpx_free(pbi->tile_worker_data);
|
||||
vpx_free(pbi->tile_workers);
|
||||
|
||||
if (pbi->num_tile_workers > 0) {
|
||||
vp9_loop_filter_dealloc(&pbi->lf_row_sync);
|
||||
}
|
||||
|
||||
if (pbi->row_mt == 1) {
|
||||
vp9_dec_free_row_mt_mem(pbi->row_mt_worker_data);
|
||||
if (pbi->row_mt_worker_data != NULL) {
|
||||
vp9_jobq_deinit(&pbi->row_mt_worker_data->jobq);
|
||||
vpx_free(pbi->row_mt_worker_data->jobq_buf);
|
||||
#if CONFIG_MULTITHREAD
|
||||
pthread_mutex_destroy(&pbi->row_mt_worker_data->recon_done_mutex);
|
||||
#endif
|
||||
}
|
||||
vpx_free(pbi->row_mt_worker_data);
|
||||
}
|
||||
|
||||
vp9_remove_common(&pbi->common);
|
||||
vpx_free(pbi);
|
||||
}
|
||||
|
||||
static int equal_dimensions(const YV12_BUFFER_CONFIG *a,
|
||||
const YV12_BUFFER_CONFIG *b) {
|
||||
return a->y_height == b->y_height && a->y_width == b->y_width &&
|
||||
a->uv_height == b->uv_height && a->uv_width == b->uv_width;
|
||||
}
|
||||
|
||||
vpx_codec_err_t vp9_copy_reference_dec(VP9Decoder *pbi,
|
||||
VP9_REFFRAME ref_frame_flag,
|
||||
YV12_BUFFER_CONFIG *sd) {
|
||||
VP9_COMMON *cm = &pbi->common;
|
||||
|
||||
/* TODO(jkoleszar): The decoder doesn't have any real knowledge of what the
|
||||
* encoder is using the frame buffers for. This is just a stub to keep the
|
||||
* vpxenc --test-decode functionality working, and will be replaced in a
|
||||
* later commit that adds VP9-specific controls for this functionality.
|
||||
*/
|
||||
if (ref_frame_flag == VP9_LAST_FLAG) {
|
||||
const YV12_BUFFER_CONFIG *const cfg = get_ref_frame(cm, 0);
|
||||
if (cfg == NULL) {
|
||||
vpx_internal_error(&cm->error, VPX_CODEC_ERROR,
|
||||
"No 'last' reference frame");
|
||||
return VPX_CODEC_ERROR;
|
||||
}
|
||||
if (!equal_dimensions(cfg, sd))
|
||||
vpx_internal_error(&cm->error, VPX_CODEC_ERROR,
|
||||
"Incorrect buffer dimensions");
|
||||
else
|
||||
vpx_yv12_copy_frame(cfg, sd);
|
||||
} else {
|
||||
vpx_internal_error(&cm->error, VPX_CODEC_ERROR, "Invalid reference frame");
|
||||
}
|
||||
|
||||
return cm->error.error_code;
|
||||
}
|
||||
|
||||
vpx_codec_err_t vp9_set_reference_dec(VP9_COMMON *cm,
|
||||
VP9_REFFRAME ref_frame_flag,
|
||||
YV12_BUFFER_CONFIG *sd) {
|
||||
int idx;
|
||||
YV12_BUFFER_CONFIG *ref_buf = NULL;
|
||||
|
||||
// TODO(jkoleszar): The decoder doesn't have any real knowledge of what the
|
||||
// encoder is using the frame buffers for. This is just a stub to keep the
|
||||
// vpxenc --test-decode functionality working, and will be replaced in a
|
||||
// later commit that adds VP9-specific controls for this functionality.
|
||||
// (Yunqing) The set_reference control depends on the following setting in
|
||||
// encoder.
|
||||
// cpi->lst_fb_idx = 0;
|
||||
// cpi->gld_fb_idx = 1;
|
||||
// cpi->alt_fb_idx = 2;
|
||||
if (ref_frame_flag == VP9_LAST_FLAG) {
|
||||
idx = cm->ref_frame_map[0];
|
||||
} else if (ref_frame_flag == VP9_GOLD_FLAG) {
|
||||
idx = cm->ref_frame_map[1];
|
||||
} else if (ref_frame_flag == VP9_ALT_FLAG) {
|
||||
idx = cm->ref_frame_map[2];
|
||||
} else {
|
||||
vpx_internal_error(&cm->error, VPX_CODEC_ERROR, "Invalid reference frame");
|
||||
return cm->error.error_code;
|
||||
}
|
||||
|
||||
if (idx < 0 || idx >= FRAME_BUFFERS) {
|
||||
vpx_internal_error(&cm->error, VPX_CODEC_ERROR,
|
||||
"Invalid reference frame map");
|
||||
return cm->error.error_code;
|
||||
}
|
||||
|
||||
// Get the destination reference buffer.
|
||||
ref_buf = &cm->buffer_pool->frame_bufs[idx].buf;
|
||||
|
||||
if (!equal_dimensions(ref_buf, sd)) {
|
||||
vpx_internal_error(&cm->error, VPX_CODEC_ERROR,
|
||||
"Incorrect buffer dimensions");
|
||||
} else {
|
||||
// Overwrite the reference frame buffer.
|
||||
vpx_yv12_copy_frame(sd, ref_buf);
|
||||
}
|
||||
|
||||
return cm->error.error_code;
|
||||
}
|
||||
|
||||
/* If any buffer updating is signaled it should be done here. */
|
||||
static void swap_frame_buffers(VP9Decoder *pbi) {
|
||||
int ref_index = 0, mask;
|
||||
VP9_COMMON *const cm = &pbi->common;
|
||||
BufferPool *const pool = cm->buffer_pool;
|
||||
RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs;
|
||||
|
||||
for (mask = pbi->refresh_frame_flags; mask; mask >>= 1) {
|
||||
const int old_idx = cm->ref_frame_map[ref_index];
|
||||
// Current thread releases the holding of reference frame.
|
||||
decrease_ref_count(old_idx, frame_bufs, pool);
|
||||
|
||||
// Release the reference frame in reference map.
|
||||
if (mask & 1) {
|
||||
decrease_ref_count(old_idx, frame_bufs, pool);
|
||||
}
|
||||
cm->ref_frame_map[ref_index] = cm->next_ref_frame_map[ref_index];
|
||||
++ref_index;
|
||||
}
|
||||
|
||||
// Current thread releases the holding of reference frame.
|
||||
for (; ref_index < REF_FRAMES && !cm->show_existing_frame; ++ref_index) {
|
||||
const int old_idx = cm->ref_frame_map[ref_index];
|
||||
decrease_ref_count(old_idx, frame_bufs, pool);
|
||||
cm->ref_frame_map[ref_index] = cm->next_ref_frame_map[ref_index];
|
||||
}
|
||||
pbi->hold_ref_buf = 0;
|
||||
cm->frame_to_show = get_frame_new_buffer(cm);
|
||||
|
||||
--frame_bufs[cm->new_fb_idx].ref_count;
|
||||
|
||||
// Invalidate these references until the next frame starts.
|
||||
for (ref_index = 0; ref_index < 3; ref_index++)
|
||||
cm->frame_refs[ref_index].idx = -1;
|
||||
}
|
||||
|
||||
static void release_fb_on_decoder_exit(VP9Decoder *pbi) {
|
||||
const VPxWorkerInterface *const winterface = vpx_get_worker_interface();
|
||||
VP9_COMMON *volatile const cm = &pbi->common;
|
||||
BufferPool *volatile const pool = cm->buffer_pool;
|
||||
RefCntBuffer *volatile const frame_bufs = cm->buffer_pool->frame_bufs;
|
||||
int i;
|
||||
|
||||
// Synchronize all threads immediately as a subsequent decode call may
|
||||
// cause a resize invalidating some allocations.
|
||||
winterface->sync(&pbi->lf_worker);
|
||||
for (i = 0; i < pbi->num_tile_workers; ++i) {
|
||||
winterface->sync(&pbi->tile_workers[i]);
|
||||
}
|
||||
|
||||
// Release all the reference buffers if worker thread is holding them.
|
||||
if (pbi->hold_ref_buf == 1) {
|
||||
int ref_index = 0, mask;
|
||||
for (mask = pbi->refresh_frame_flags; mask; mask >>= 1) {
|
||||
const int old_idx = cm->ref_frame_map[ref_index];
|
||||
// Current thread releases the holding of reference frame.
|
||||
decrease_ref_count(old_idx, frame_bufs, pool);
|
||||
|
||||
// Release the reference frame in reference map.
|
||||
if (mask & 1) {
|
||||
decrease_ref_count(old_idx, frame_bufs, pool);
|
||||
}
|
||||
++ref_index;
|
||||
}
|
||||
|
||||
// Current thread releases the holding of reference frame.
|
||||
for (; ref_index < REF_FRAMES && !cm->show_existing_frame; ++ref_index) {
|
||||
const int old_idx = cm->ref_frame_map[ref_index];
|
||||
decrease_ref_count(old_idx, frame_bufs, pool);
|
||||
}
|
||||
pbi->hold_ref_buf = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int vp9_receive_compressed_data(VP9Decoder *pbi, size_t size,
|
||||
const uint8_t **psource) {
|
||||
VP9_COMMON *volatile const cm = &pbi->common;
|
||||
BufferPool *volatile const pool = cm->buffer_pool;
|
||||
RefCntBuffer *volatile const frame_bufs = cm->buffer_pool->frame_bufs;
|
||||
const uint8_t *source = *psource;
|
||||
int retcode = 0;
|
||||
cm->error.error_code = VPX_CODEC_OK;
|
||||
|
||||
if (size == 0) {
|
||||
// This is used to signal that we are missing frames.
|
||||
// We do not know if the missing frame(s) was supposed to update
|
||||
// any of the reference buffers, but we act conservative and
|
||||
// mark only the last buffer as corrupted.
|
||||
//
|
||||
// TODO(jkoleszar): Error concealment is undefined and non-normative
|
||||
// at this point, but if it becomes so, [0] may not always be the correct
|
||||
// thing to do here.
|
||||
if (cm->frame_refs[0].idx > 0) {
|
||||
assert(cm->frame_refs[0].buf != NULL);
|
||||
cm->frame_refs[0].buf->corrupted = 1;
|
||||
}
|
||||
}
|
||||
|
||||
pbi->ready_for_new_data = 0;
|
||||
|
||||
// Check if the previous frame was a frame without any references to it.
|
||||
if (cm->new_fb_idx >= 0 && frame_bufs[cm->new_fb_idx].ref_count == 0 &&
|
||||
!frame_bufs[cm->new_fb_idx].released) {
|
||||
pool->release_fb_cb(pool->cb_priv,
|
||||
&frame_bufs[cm->new_fb_idx].raw_frame_buffer);
|
||||
frame_bufs[cm->new_fb_idx].released = 1;
|
||||
}
|
||||
|
||||
// Find a free frame buffer. Return error if can not find any.
|
||||
cm->new_fb_idx = get_free_fb(cm);
|
||||
if (cm->new_fb_idx == INVALID_IDX) {
|
||||
pbi->ready_for_new_data = 1;
|
||||
release_fb_on_decoder_exit(pbi);
|
||||
vpx_clear_system_state();
|
||||
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
|
||||
"Unable to find free frame buffer");
|
||||
return cm->error.error_code;
|
||||
}
|
||||
|
||||
// Assign a MV array to the frame buffer.
|
||||
cm->cur_frame = &pool->frame_bufs[cm->new_fb_idx];
|
||||
|
||||
pbi->hold_ref_buf = 0;
|
||||
pbi->cur_buf = &frame_bufs[cm->new_fb_idx];
|
||||
|
||||
if (setjmp(cm->error.jmp)) {
|
||||
cm->error.setjmp = 0;
|
||||
pbi->ready_for_new_data = 1;
|
||||
release_fb_on_decoder_exit(pbi);
|
||||
// Release current frame.
|
||||
decrease_ref_count(cm->new_fb_idx, frame_bufs, pool);
|
||||
vpx_clear_system_state();
|
||||
return -1;
|
||||
}
|
||||
|
||||
cm->error.setjmp = 1;
|
||||
vp9_decode_frame(pbi, source, source + size, psource);
|
||||
|
||||
swap_frame_buffers(pbi);
|
||||
|
||||
vpx_clear_system_state();
|
||||
|
||||
if (!cm->show_existing_frame) {
|
||||
cm->last_show_frame = cm->show_frame;
|
||||
cm->prev_frame = cm->cur_frame;
|
||||
if (cm->seg.enabled) vp9_swap_current_and_last_seg_map(cm);
|
||||
}
|
||||
|
||||
if (cm->show_frame) cm->cur_show_frame_fb_idx = cm->new_fb_idx;
|
||||
|
||||
// Update progress in frame parallel decode.
|
||||
cm->last_width = cm->width;
|
||||
cm->last_height = cm->height;
|
||||
if (cm->show_frame) {
|
||||
cm->current_video_frame++;
|
||||
}
|
||||
|
||||
cm->error.setjmp = 0;
|
||||
return retcode;
|
||||
}
|
||||
|
||||
int vp9_get_raw_frame(VP9Decoder *pbi, YV12_BUFFER_CONFIG *sd,
|
||||
vp9_ppflags_t *flags) {
|
||||
VP9_COMMON *const cm = &pbi->common;
|
||||
int ret = -1;
|
||||
#if !CONFIG_VP9_POSTPROC
|
||||
(void)*flags;
|
||||
#endif
|
||||
|
||||
if (pbi->ready_for_new_data == 1) return ret;
|
||||
|
||||
pbi->ready_for_new_data = 1;
|
||||
|
||||
/* no raw frame to show!!! */
|
||||
if (!cm->show_frame) return ret;
|
||||
|
||||
pbi->ready_for_new_data = 1;
|
||||
|
||||
#if CONFIG_VP9_POSTPROC
|
||||
if (!cm->show_existing_frame) {
|
||||
ret = vp9_post_proc_frame(cm, sd, flags, cm->width);
|
||||
} else {
|
||||
*sd = *cm->frame_to_show;
|
||||
ret = 0;
|
||||
}
|
||||
#else
|
||||
*sd = *cm->frame_to_show;
|
||||
ret = 0;
|
||||
#endif /*!CONFIG_POSTPROC*/
|
||||
vpx_clear_system_state();
|
||||
return ret;
|
||||
}
|
||||
|
||||
vpx_codec_err_t vp9_parse_superframe_index(const uint8_t *data, size_t data_sz,
|
||||
uint32_t sizes[8], int *count,
|
||||
vpx_decrypt_cb decrypt_cb,
|
||||
void *decrypt_state) {
|
||||
// A chunk ending with a byte matching 0xc0 is an invalid chunk unless
|
||||
// it is a super frame index. If the last byte of real video compression
|
||||
// data is 0xc0 the encoder must add a 0 byte. If we have the marker but
|
||||
// not the associated matching marker byte at the front of the index we have
|
||||
// an invalid bitstream and need to return an error.
|
||||
|
||||
uint8_t marker;
|
||||
|
||||
assert(data_sz);
|
||||
marker = read_marker(decrypt_cb, decrypt_state, data + data_sz - 1);
|
||||
*count = 0;
|
||||
|
||||
if ((marker & 0xe0) == 0xc0) {
|
||||
const uint32_t frames = (marker & 0x7) + 1;
|
||||
const uint32_t mag = ((marker >> 3) & 0x3) + 1;
|
||||
const size_t index_sz = 2 + mag * frames;
|
||||
|
||||
// This chunk is marked as having a superframe index but doesn't have
|
||||
// enough data for it, thus it's an invalid superframe index.
|
||||
if (data_sz < index_sz) return VPX_CODEC_CORRUPT_FRAME;
|
||||
|
||||
{
|
||||
const uint8_t marker2 =
|
||||
read_marker(decrypt_cb, decrypt_state, data + data_sz - index_sz);
|
||||
|
||||
// This chunk is marked as having a superframe index but doesn't have
|
||||
// the matching marker byte at the front of the index therefore it's an
|
||||
// invalid chunk.
|
||||
if (marker != marker2) return VPX_CODEC_CORRUPT_FRAME;
|
||||
}
|
||||
|
||||
{
|
||||
// Found a valid superframe index.
|
||||
uint32_t i, j;
|
||||
const uint8_t *x = &data[data_sz - index_sz + 1];
|
||||
|
||||
// Frames has a maximum of 8 and mag has a maximum of 4.
|
||||
uint8_t clear_buffer[32];
|
||||
assert(sizeof(clear_buffer) >= frames * mag);
|
||||
if (decrypt_cb) {
|
||||
decrypt_cb(decrypt_state, x, clear_buffer, frames * mag);
|
||||
x = clear_buffer;
|
||||
}
|
||||
|
||||
for (i = 0; i < frames; ++i) {
|
||||
uint32_t this_sz = 0;
|
||||
|
||||
for (j = 0; j < mag; ++j) this_sz |= ((uint32_t)(*x++)) << (j * 8);
|
||||
sizes[i] = this_sz;
|
||||
}
|
||||
*count = frames;
|
||||
}
|
||||
}
|
||||
return VPX_CODEC_OK;
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* 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 VPX_VP9_DECODER_VP9_DECODER_H_
|
||||
#define VPX_VP9_DECODER_VP9_DECODER_H_
|
||||
|
||||
#include "./vpx_config.h"
|
||||
|
||||
#include "vpx/vpx_codec.h"
|
||||
#include "vpx_dsp/bitreader.h"
|
||||
#include "vpx_scale/yv12config.h"
|
||||
#include "vpx_util/vpx_thread.h"
|
||||
|
||||
#include "vp9/common/vp9_thread_common.h"
|
||||
#include "vp9/common/vp9_onyxc_int.h"
|
||||
#include "vp9/common/vp9_ppflags.h"
|
||||
#include "./vp9_job_queue.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define EOBS_PER_SB_LOG2 8
|
||||
#define DQCOEFFS_PER_SB_LOG2 12
|
||||
#define PARTITIONS_PER_SB 85
|
||||
|
||||
typedef enum JobType { PARSE_JOB, RECON_JOB, LPF_JOB } JobType;
|
||||
|
||||
typedef struct ThreadData {
|
||||
struct VP9Decoder *pbi;
|
||||
LFWorkerData *lf_data;
|
||||
VP9LfSync *lf_sync;
|
||||
} ThreadData;
|
||||
|
||||
typedef struct TileBuffer {
|
||||
const uint8_t *data;
|
||||
size_t size;
|
||||
int col; // only used with multi-threaded decoding
|
||||
} TileBuffer;
|
||||
|
||||
typedef struct TileWorkerData {
|
||||
const uint8_t *data_end;
|
||||
int buf_start, buf_end; // pbi->tile_buffers to decode, inclusive
|
||||
vpx_reader bit_reader;
|
||||
FRAME_COUNTS counts;
|
||||
LFWorkerData *lf_data;
|
||||
VP9LfSync *lf_sync;
|
||||
DECLARE_ALIGNED(16, MACROBLOCKD, xd);
|
||||
/* dqcoeff are shared by all the planes. So planes must be decoded serially */
|
||||
DECLARE_ALIGNED(16, tran_low_t, dqcoeff[32 * 32]);
|
||||
DECLARE_ALIGNED(16, uint16_t, extend_and_predict_buf[80 * 2 * 80 * 2]);
|
||||
struct vpx_internal_error_info error_info;
|
||||
} TileWorkerData;
|
||||
|
||||
typedef void (*process_block_fn_t)(TileWorkerData *twd,
|
||||
struct VP9Decoder *const pbi, int mi_row,
|
||||
int mi_col, BLOCK_SIZE bsize, int bwl,
|
||||
int bhl);
|
||||
|
||||
typedef struct RowMTWorkerData {
|
||||
int num_sbs;
|
||||
int *eob[MAX_MB_PLANE];
|
||||
PARTITION_TYPE *partition;
|
||||
tran_low_t *dqcoeff[MAX_MB_PLANE];
|
||||
int8_t *recon_map;
|
||||
const uint8_t *data_end;
|
||||
uint8_t *jobq_buf;
|
||||
JobQueueRowMt jobq;
|
||||
size_t jobq_size;
|
||||
int num_tiles_done;
|
||||
int num_jobs;
|
||||
#if CONFIG_MULTITHREAD
|
||||
pthread_mutex_t recon_done_mutex;
|
||||
pthread_mutex_t *recon_sync_mutex;
|
||||
pthread_cond_t *recon_sync_cond;
|
||||
#endif
|
||||
ThreadData *thread_data;
|
||||
} RowMTWorkerData;
|
||||
|
||||
/* Structure to queue and dequeue row decode jobs */
|
||||
typedef struct Job {
|
||||
int row_num;
|
||||
int tile_col;
|
||||
JobType job_type;
|
||||
} Job;
|
||||
|
||||
typedef struct VP9Decoder {
|
||||
DECLARE_ALIGNED(16, MACROBLOCKD, mb);
|
||||
|
||||
DECLARE_ALIGNED(16, VP9_COMMON, common);
|
||||
|
||||
int ready_for_new_data;
|
||||
|
||||
int refresh_frame_flags;
|
||||
|
||||
// TODO(hkuang): Combine this with cur_buf in macroblockd as they are
|
||||
// the same.
|
||||
RefCntBuffer *cur_buf; // Current decoding frame buffer.
|
||||
|
||||
VPxWorker lf_worker;
|
||||
VPxWorker *tile_workers;
|
||||
TileWorkerData *tile_worker_data;
|
||||
TileBuffer tile_buffers[64];
|
||||
int num_tile_workers;
|
||||
int total_tiles;
|
||||
|
||||
VP9LfSync lf_row_sync;
|
||||
|
||||
vpx_decrypt_cb decrypt_cb;
|
||||
void *decrypt_state;
|
||||
|
||||
int max_threads;
|
||||
int inv_tile_order;
|
||||
int need_resync; // wait for key/intra-only frame.
|
||||
int hold_ref_buf; // hold the reference buffer.
|
||||
|
||||
int row_mt;
|
||||
int lpf_mt_opt;
|
||||
RowMTWorkerData *row_mt_worker_data;
|
||||
} VP9Decoder;
|
||||
|
||||
int vp9_receive_compressed_data(struct VP9Decoder *pbi, size_t size,
|
||||
const uint8_t **psource);
|
||||
|
||||
int vp9_get_raw_frame(struct VP9Decoder *pbi, YV12_BUFFER_CONFIG *sd,
|
||||
vp9_ppflags_t *flags);
|
||||
|
||||
vpx_codec_err_t vp9_copy_reference_dec(struct VP9Decoder *pbi,
|
||||
VP9_REFFRAME ref_frame_flag,
|
||||
YV12_BUFFER_CONFIG *sd);
|
||||
|
||||
vpx_codec_err_t vp9_set_reference_dec(VP9_COMMON *cm,
|
||||
VP9_REFFRAME ref_frame_flag,
|
||||
YV12_BUFFER_CONFIG *sd);
|
||||
|
||||
static INLINE uint8_t read_marker(vpx_decrypt_cb decrypt_cb,
|
||||
void *decrypt_state, const uint8_t *data) {
|
||||
if (decrypt_cb) {
|
||||
uint8_t marker;
|
||||
decrypt_cb(decrypt_state, data, &marker, 1);
|
||||
return marker;
|
||||
}
|
||||
return *data;
|
||||
}
|
||||
|
||||
// This function is exposed for use in tests, as well as the inlined function
|
||||
// "read_marker".
|
||||
vpx_codec_err_t vp9_parse_superframe_index(const uint8_t *data, size_t data_sz,
|
||||
uint32_t sizes[8], int *count,
|
||||
vpx_decrypt_cb decrypt_cb,
|
||||
void *decrypt_state);
|
||||
|
||||
struct VP9Decoder *vp9_decoder_create(BufferPool *const pool);
|
||||
|
||||
void vp9_decoder_remove(struct VP9Decoder *pbi);
|
||||
|
||||
void vp9_dec_alloc_row_mt_mem(RowMTWorkerData *row_mt_worker_data,
|
||||
VP9_COMMON *cm, int num_sbs, int max_threads,
|
||||
int num_jobs);
|
||||
void vp9_dec_free_row_mt_mem(RowMTWorkerData *row_mt_worker_data);
|
||||
|
||||
static INLINE void decrease_ref_count(int idx, RefCntBuffer *const frame_bufs,
|
||||
BufferPool *const pool) {
|
||||
if (idx >= 0 && frame_bufs[idx].ref_count > 0) {
|
||||
--frame_bufs[idx].ref_count;
|
||||
// A worker may only get a free framebuffer index when calling get_free_fb.
|
||||
// But the private buffer is not set up until finish decoding header.
|
||||
// So any error happens during decoding header, the frame_bufs will not
|
||||
// have valid priv buffer.
|
||||
if (!frame_bufs[idx].released && frame_bufs[idx].ref_count == 0 &&
|
||||
frame_bufs[idx].raw_frame_buffer.priv) {
|
||||
pool->release_fb_cb(pool->cb_priv, &frame_bufs[idx].raw_frame_buffer);
|
||||
frame_bufs[idx].released = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_DECODER_VP9_DECODER_H_
|
||||
@@ -0,0 +1,333 @@
|
||||
/*
|
||||
* 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_blockd.h"
|
||||
#include "vp9/common/vp9_common.h"
|
||||
#include "vp9/common/vp9_entropy.h"
|
||||
#if CONFIG_COEFFICIENT_RANGE_CHECKING
|
||||
#include "vp9/common/vp9_idct.h"
|
||||
#endif
|
||||
|
||||
#include "vp9/decoder/vp9_detokenize.h"
|
||||
|
||||
#define EOB_CONTEXT_NODE 0
|
||||
#define ZERO_CONTEXT_NODE 1
|
||||
#define ONE_CONTEXT_NODE 2
|
||||
|
||||
#define INCREMENT_COUNT(token) \
|
||||
do { \
|
||||
if (counts) ++coef_counts[band][ctx][token]; \
|
||||
} while (0)
|
||||
|
||||
static INLINE int read_bool(vpx_reader *r, int prob, BD_VALUE *value,
|
||||
int *count, unsigned int *range) {
|
||||
const unsigned int split = (*range * prob + (256 - prob)) >> CHAR_BIT;
|
||||
const BD_VALUE bigsplit = (BD_VALUE)split << (BD_VALUE_SIZE - CHAR_BIT);
|
||||
#if CONFIG_BITSTREAM_DEBUG
|
||||
const int queue_r = bitstream_queue_get_read();
|
||||
const int frame_idx = bitstream_queue_get_frame_read();
|
||||
int ref_result, ref_prob;
|
||||
bitstream_queue_pop(&ref_result, &ref_prob);
|
||||
if (prob != ref_prob) {
|
||||
fprintf(stderr,
|
||||
"\n *** [bit] prob error, frame_idx_r %d prob %d ref_prob %d "
|
||||
"queue_r %d\n",
|
||||
frame_idx, prob, ref_prob, queue_r);
|
||||
|
||||
assert(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (*count < 0) {
|
||||
r->value = *value;
|
||||
r->count = *count;
|
||||
vpx_reader_fill(r);
|
||||
*value = r->value;
|
||||
*count = r->count;
|
||||
}
|
||||
|
||||
if (*value >= bigsplit) {
|
||||
*range = *range - split;
|
||||
*value = *value - bigsplit;
|
||||
{
|
||||
const int shift = vpx_norm[*range];
|
||||
*range <<= shift;
|
||||
*value <<= shift;
|
||||
*count -= shift;
|
||||
}
|
||||
#if CONFIG_BITSTREAM_DEBUG
|
||||
{
|
||||
const int bit = 1;
|
||||
if (bit != ref_result) {
|
||||
fprintf(
|
||||
stderr,
|
||||
"\n *** [bit] result error, frame_idx_r %d bit %d ref_result %d "
|
||||
"queue_r %d\n",
|
||||
frame_idx, bit, ref_result, queue_r);
|
||||
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
*range = split;
|
||||
{
|
||||
const int shift = vpx_norm[*range];
|
||||
*range <<= shift;
|
||||
*value <<= shift;
|
||||
*count -= shift;
|
||||
}
|
||||
#if CONFIG_BITSTREAM_DEBUG
|
||||
{
|
||||
const int bit = 0;
|
||||
if (bit != ref_result) {
|
||||
fprintf(stderr,
|
||||
"\n *** [bit] result error, frame_idx_r %d bit %d ref_result %d "
|
||||
"queue_r %d\n",
|
||||
frame_idx, bit, ref_result, queue_r);
|
||||
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static INLINE int read_coeff(vpx_reader *r, const vpx_prob *probs, int n,
|
||||
BD_VALUE *value, int *count, unsigned int *range) {
|
||||
int i, val = 0;
|
||||
for (i = 0; i < n; ++i)
|
||||
val = (val << 1) | read_bool(r, probs[i], value, count, range);
|
||||
return val;
|
||||
}
|
||||
|
||||
static int decode_coefs(const MACROBLOCKD *xd, PLANE_TYPE type,
|
||||
tran_low_t *dqcoeff, TX_SIZE tx_size, const int16_t *dq,
|
||||
int ctx, const int16_t *scan, const int16_t *nb,
|
||||
vpx_reader *r) {
|
||||
FRAME_COUNTS *counts = xd->counts;
|
||||
const int max_eob = 16 << (tx_size << 1);
|
||||
const FRAME_CONTEXT *const fc = xd->fc;
|
||||
const int ref = is_inter_block(xd->mi[0]);
|
||||
int band, c = 0;
|
||||
const vpx_prob(*coef_probs)[COEFF_CONTEXTS][UNCONSTRAINED_NODES] =
|
||||
fc->coef_probs[tx_size][type][ref];
|
||||
const vpx_prob *prob;
|
||||
unsigned int(*coef_counts)[COEFF_CONTEXTS][UNCONSTRAINED_NODES + 1];
|
||||
unsigned int(*eob_branch_count)[COEFF_CONTEXTS];
|
||||
uint8_t token_cache[32 * 32];
|
||||
const uint8_t *band_translate = get_band_translate(tx_size);
|
||||
const int dq_shift = (tx_size == TX_32X32);
|
||||
int v;
|
||||
int16_t dqv = dq[0];
|
||||
const uint8_t *const cat6_prob =
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
(xd->bd == VPX_BITS_12)
|
||||
? vp9_cat6_prob_high12
|
||||
: (xd->bd == VPX_BITS_10) ? vp9_cat6_prob_high12 + 2 :
|
||||
#endif // CONFIG_VP9_HIGHBITDEPTH
|
||||
vp9_cat6_prob;
|
||||
const int cat6_bits =
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
(xd->bd == VPX_BITS_12) ? 18
|
||||
: (xd->bd == VPX_BITS_10) ? 16 :
|
||||
#endif // CONFIG_VP9_HIGHBITDEPTH
|
||||
14;
|
||||
// Keep value, range, and count as locals. The compiler produces better
|
||||
// results with the locals than using r directly.
|
||||
BD_VALUE value = r->value;
|
||||
unsigned int range = r->range;
|
||||
int count = r->count;
|
||||
|
||||
if (counts) {
|
||||
coef_counts = counts->coef[tx_size][type][ref];
|
||||
eob_branch_count = counts->eob_branch[tx_size][type][ref];
|
||||
}
|
||||
|
||||
while (c < max_eob) {
|
||||
int val = -1;
|
||||
band = *band_translate++;
|
||||
prob = coef_probs[band][ctx];
|
||||
if (counts) ++eob_branch_count[band][ctx];
|
||||
if (!read_bool(r, prob[EOB_CONTEXT_NODE], &value, &count, &range)) {
|
||||
INCREMENT_COUNT(EOB_MODEL_TOKEN);
|
||||
break;
|
||||
}
|
||||
|
||||
while (!read_bool(r, prob[ZERO_CONTEXT_NODE], &value, &count, &range)) {
|
||||
INCREMENT_COUNT(ZERO_TOKEN);
|
||||
dqv = dq[1];
|
||||
token_cache[scan[c]] = 0;
|
||||
++c;
|
||||
if (c >= max_eob) {
|
||||
r->value = value;
|
||||
r->range = range;
|
||||
r->count = count;
|
||||
return c; // zero tokens at the end (no eob token)
|
||||
}
|
||||
ctx = get_coef_context(nb, token_cache, c);
|
||||
band = *band_translate++;
|
||||
prob = coef_probs[band][ctx];
|
||||
}
|
||||
|
||||
if (read_bool(r, prob[ONE_CONTEXT_NODE], &value, &count, &range)) {
|
||||
const vpx_prob *p = vp9_pareto8_full[prob[PIVOT_NODE] - 1];
|
||||
INCREMENT_COUNT(TWO_TOKEN);
|
||||
if (read_bool(r, p[0], &value, &count, &range)) {
|
||||
if (read_bool(r, p[3], &value, &count, &range)) {
|
||||
token_cache[scan[c]] = 5;
|
||||
if (read_bool(r, p[5], &value, &count, &range)) {
|
||||
if (read_bool(r, p[7], &value, &count, &range)) {
|
||||
val = CAT6_MIN_VAL +
|
||||
read_coeff(r, cat6_prob, cat6_bits, &value, &count, &range);
|
||||
} else {
|
||||
val = CAT5_MIN_VAL +
|
||||
read_coeff(r, vp9_cat5_prob, 5, &value, &count, &range);
|
||||
}
|
||||
} else if (read_bool(r, p[6], &value, &count, &range)) {
|
||||
val = CAT4_MIN_VAL +
|
||||
read_coeff(r, vp9_cat4_prob, 4, &value, &count, &range);
|
||||
} else {
|
||||
val = CAT3_MIN_VAL +
|
||||
read_coeff(r, vp9_cat3_prob, 3, &value, &count, &range);
|
||||
}
|
||||
} else {
|
||||
token_cache[scan[c]] = 4;
|
||||
if (read_bool(r, p[4], &value, &count, &range)) {
|
||||
val = CAT2_MIN_VAL +
|
||||
read_coeff(r, vp9_cat2_prob, 2, &value, &count, &range);
|
||||
} else {
|
||||
val = CAT1_MIN_VAL +
|
||||
read_coeff(r, vp9_cat1_prob, 1, &value, &count, &range);
|
||||
}
|
||||
}
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
// val may use 18-bits
|
||||
v = (int)(((int64_t)val * dqv) >> dq_shift);
|
||||
#else
|
||||
v = (val * dqv) >> dq_shift;
|
||||
#endif
|
||||
} else {
|
||||
if (read_bool(r, p[1], &value, &count, &range)) {
|
||||
token_cache[scan[c]] = 3;
|
||||
v = ((3 + read_bool(r, p[2], &value, &count, &range)) * dqv) >>
|
||||
dq_shift;
|
||||
} else {
|
||||
token_cache[scan[c]] = 2;
|
||||
v = (2 * dqv) >> dq_shift;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
INCREMENT_COUNT(ONE_TOKEN);
|
||||
token_cache[scan[c]] = 1;
|
||||
v = dqv >> dq_shift;
|
||||
}
|
||||
#if CONFIG_COEFFICIENT_RANGE_CHECKING
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
dqcoeff[scan[c]] = highbd_check_range(
|
||||
read_bool(r, 128, &value, &count, &range) ? -v : v, xd->bd);
|
||||
#else
|
||||
dqcoeff[scan[c]] =
|
||||
check_range(read_bool(r, 128, &value, &count, &range) ? -v : v);
|
||||
#endif // CONFIG_VP9_HIGHBITDEPTH
|
||||
#else
|
||||
if (read_bool(r, 128, &value, &count, &range)) {
|
||||
dqcoeff[scan[c]] = (tran_low_t)-v;
|
||||
} else {
|
||||
dqcoeff[scan[c]] = (tran_low_t)v;
|
||||
}
|
||||
#endif // CONFIG_COEFFICIENT_RANGE_CHECKING
|
||||
++c;
|
||||
ctx = get_coef_context(nb, token_cache, c);
|
||||
dqv = dq[1];
|
||||
}
|
||||
|
||||
r->value = value;
|
||||
r->range = range;
|
||||
r->count = count;
|
||||
return c;
|
||||
}
|
||||
|
||||
static void get_ctx_shift(MACROBLOCKD *xd, int *ctx_shift_a, int *ctx_shift_l,
|
||||
int x, int y, unsigned int tx_size_in_blocks) {
|
||||
if (xd->max_blocks_wide) {
|
||||
if (tx_size_in_blocks + x > xd->max_blocks_wide)
|
||||
*ctx_shift_a = (tx_size_in_blocks - (xd->max_blocks_wide - x)) * 8;
|
||||
}
|
||||
if (xd->max_blocks_high) {
|
||||
if (tx_size_in_blocks + y > xd->max_blocks_high)
|
||||
*ctx_shift_l = (tx_size_in_blocks - (xd->max_blocks_high - y)) * 8;
|
||||
}
|
||||
}
|
||||
|
||||
int vp9_decode_block_tokens(TileWorkerData *twd, int plane,
|
||||
const scan_order *sc, int x, int y, TX_SIZE tx_size,
|
||||
int seg_id) {
|
||||
vpx_reader *r = &twd->bit_reader;
|
||||
MACROBLOCKD *xd = &twd->xd;
|
||||
struct macroblockd_plane *const pd = &xd->plane[plane];
|
||||
const int16_t *const dequant = pd->seg_dequant[seg_id];
|
||||
int eob;
|
||||
ENTROPY_CONTEXT *a = pd->above_context + x;
|
||||
ENTROPY_CONTEXT *l = pd->left_context + y;
|
||||
int ctx;
|
||||
int ctx_shift_a = 0;
|
||||
int ctx_shift_l = 0;
|
||||
|
||||
switch (tx_size) {
|
||||
case TX_4X4:
|
||||
ctx = a[0] != 0;
|
||||
ctx += l[0] != 0;
|
||||
eob = decode_coefs(xd, get_plane_type(plane), pd->dqcoeff, tx_size,
|
||||
dequant, ctx, sc->scan, sc->neighbors, r);
|
||||
a[0] = l[0] = (eob > 0);
|
||||
break;
|
||||
case TX_8X8:
|
||||
get_ctx_shift(xd, &ctx_shift_a, &ctx_shift_l, x, y, 1 << TX_8X8);
|
||||
ctx = !!*(const uint16_t *)a;
|
||||
ctx += !!*(const uint16_t *)l;
|
||||
eob = decode_coefs(xd, get_plane_type(plane), pd->dqcoeff, tx_size,
|
||||
dequant, ctx, sc->scan, sc->neighbors, r);
|
||||
*(uint16_t *)a = ((eob > 0) * 0x0101) >> ctx_shift_a;
|
||||
*(uint16_t *)l = ((eob > 0) * 0x0101) >> ctx_shift_l;
|
||||
break;
|
||||
case TX_16X16:
|
||||
get_ctx_shift(xd, &ctx_shift_a, &ctx_shift_l, x, y, 1 << TX_16X16);
|
||||
ctx = !!*(const uint32_t *)a;
|
||||
ctx += !!*(const uint32_t *)l;
|
||||
eob = decode_coefs(xd, get_plane_type(plane), pd->dqcoeff, tx_size,
|
||||
dequant, ctx, sc->scan, sc->neighbors, r);
|
||||
*(uint32_t *)a = ((eob > 0) * 0x01010101) >> ctx_shift_a;
|
||||
*(uint32_t *)l = ((eob > 0) * 0x01010101) >> ctx_shift_l;
|
||||
break;
|
||||
case TX_32X32:
|
||||
get_ctx_shift(xd, &ctx_shift_a, &ctx_shift_l, x, y, 1 << TX_32X32);
|
||||
// NOTE: casting to uint64_t here is safe because the default memory
|
||||
// alignment is at least 8 bytes and the TX_32X32 is aligned on 8 byte
|
||||
// boundaries.
|
||||
ctx = !!*(const uint64_t *)a;
|
||||
ctx += !!*(const uint64_t *)l;
|
||||
eob = decode_coefs(xd, get_plane_type(plane), pd->dqcoeff, tx_size,
|
||||
dequant, ctx, sc->scan, sc->neighbors, r);
|
||||
*(uint64_t *)a = ((eob > 0) * 0x0101010101010101ULL) >> ctx_shift_a;
|
||||
*(uint64_t *)l = ((eob > 0) * 0x0101010101010101ULL) >> ctx_shift_l;
|
||||
break;
|
||||
default:
|
||||
assert(0 && "Invalid transform size.");
|
||||
eob = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return eob;
|
||||
}
|
||||
@@ -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 VPX_VP9_DECODER_VP9_DETOKENIZE_H_
|
||||
#define VPX_VP9_DECODER_VP9_DETOKENIZE_H_
|
||||
|
||||
#include "vpx_dsp/bitreader.h"
|
||||
#include "vp9/decoder/vp9_decoder.h"
|
||||
#include "vp9/common/vp9_scan.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int vp9_decode_block_tokens(TileWorkerData *twd, int plane,
|
||||
const scan_order *sc, int x, int y, TX_SIZE tx_size,
|
||||
int seg_id);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_DECODER_VP9_DETOKENIZE_H_
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
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/common/vp9_entropy.h"
|
||||
|
||||
#include "vp9/decoder/vp9_dsubexp.h"
|
||||
|
||||
static int inv_recenter_nonneg(int v, int m) {
|
||||
if (v > 2 * m) return v;
|
||||
|
||||
return (v & 1) ? m - ((v + 1) >> 1) : m + (v >> 1);
|
||||
}
|
||||
|
||||
static int decode_uniform(vpx_reader *r) {
|
||||
const int l = 8;
|
||||
const int m = (1 << l) - 191;
|
||||
const int v = vpx_read_literal(r, l - 1);
|
||||
return v < m ? v : (v << 1) - m + vpx_read_bit(r);
|
||||
}
|
||||
|
||||
static int inv_remap_prob(int v, int m) {
|
||||
static uint8_t inv_map_table[MAX_PROB] = {
|
||||
7, 20, 33, 46, 59, 72, 85, 98, 111, 124, 137, 150, 163, 176, 189,
|
||||
202, 215, 228, 241, 254, 1, 2, 3, 4, 5, 6, 8, 9, 10, 11,
|
||||
12, 13, 14, 15, 16, 17, 18, 19, 21, 22, 23, 24, 25, 26, 27,
|
||||
28, 29, 30, 31, 32, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
|
||||
44, 45, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 60,
|
||||
61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 73, 74, 75, 76,
|
||||
77, 78, 79, 80, 81, 82, 83, 84, 86, 87, 88, 89, 90, 91, 92,
|
||||
93, 94, 95, 96, 97, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108,
|
||||
109, 110, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 125,
|
||||
126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 138, 139, 140, 141,
|
||||
142, 143, 144, 145, 146, 147, 148, 149, 151, 152, 153, 154, 155, 156, 157,
|
||||
158, 159, 160, 161, 162, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173,
|
||||
174, 175, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 190,
|
||||
191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 203, 204, 205, 206,
|
||||
207, 208, 209, 210, 211, 212, 213, 214, 216, 217, 218, 219, 220, 221, 222,
|
||||
223, 224, 225, 226, 227, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238,
|
||||
239, 240, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 253
|
||||
};
|
||||
assert(v < (int)(sizeof(inv_map_table) / sizeof(inv_map_table[0])));
|
||||
v = inv_map_table[v];
|
||||
m--;
|
||||
if ((m << 1) <= MAX_PROB) {
|
||||
return 1 + inv_recenter_nonneg(v, m);
|
||||
} else {
|
||||
return MAX_PROB - inv_recenter_nonneg(v, MAX_PROB - 1 - m);
|
||||
}
|
||||
}
|
||||
|
||||
static int decode_term_subexp(vpx_reader *r) {
|
||||
if (!vpx_read_bit(r)) return vpx_read_literal(r, 4);
|
||||
if (!vpx_read_bit(r)) return vpx_read_literal(r, 4) + 16;
|
||||
if (!vpx_read_bit(r)) return vpx_read_literal(r, 5) + 32;
|
||||
return decode_uniform(r) + 64;
|
||||
}
|
||||
|
||||
void vp9_diff_update_prob(vpx_reader *r, vpx_prob *p) {
|
||||
if (vpx_read(r, DIFF_UPDATE_PROB)) {
|
||||
const int delp = decode_term_subexp(r);
|
||||
*p = (vpx_prob)inv_remap_prob(delp, *p);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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 VPX_VP9_DECODER_VP9_DSUBEXP_H_
|
||||
#define VPX_VP9_DECODER_VP9_DSUBEXP_H_
|
||||
|
||||
#include "vpx_dsp/bitreader.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void vp9_diff_update_prob(vpx_reader *r, vpx_prob *p);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_DECODER_VP9_DSUBEXP_H_
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (c) 2018 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 <string.h>
|
||||
|
||||
#include "vpx/vpx_integer.h"
|
||||
|
||||
#include "vp9/decoder/vp9_job_queue.h"
|
||||
|
||||
void vp9_jobq_init(JobQueueRowMt *jobq, uint8_t *buf, size_t buf_size) {
|
||||
#if CONFIG_MULTITHREAD
|
||||
pthread_mutex_init(&jobq->mutex, NULL);
|
||||
pthread_cond_init(&jobq->cond, NULL);
|
||||
#endif
|
||||
jobq->buf_base = buf;
|
||||
jobq->buf_wr = buf;
|
||||
jobq->buf_rd = buf;
|
||||
jobq->buf_end = buf + buf_size;
|
||||
jobq->terminate = 0;
|
||||
}
|
||||
|
||||
void vp9_jobq_reset(JobQueueRowMt *jobq) {
|
||||
#if CONFIG_MULTITHREAD
|
||||
pthread_mutex_lock(&jobq->mutex);
|
||||
#endif
|
||||
jobq->buf_wr = jobq->buf_base;
|
||||
jobq->buf_rd = jobq->buf_base;
|
||||
jobq->terminate = 0;
|
||||
#if CONFIG_MULTITHREAD
|
||||
pthread_mutex_unlock(&jobq->mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
void vp9_jobq_deinit(JobQueueRowMt *jobq) {
|
||||
vp9_jobq_reset(jobq);
|
||||
#if CONFIG_MULTITHREAD
|
||||
pthread_mutex_destroy(&jobq->mutex);
|
||||
pthread_cond_destroy(&jobq->cond);
|
||||
#endif
|
||||
}
|
||||
|
||||
void vp9_jobq_terminate(JobQueueRowMt *jobq) {
|
||||
#if CONFIG_MULTITHREAD
|
||||
pthread_mutex_lock(&jobq->mutex);
|
||||
#endif
|
||||
jobq->terminate = 1;
|
||||
#if CONFIG_MULTITHREAD
|
||||
pthread_cond_broadcast(&jobq->cond);
|
||||
pthread_mutex_unlock(&jobq->mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
int vp9_jobq_queue(JobQueueRowMt *jobq, void *job, size_t job_size) {
|
||||
int ret = 0;
|
||||
#if CONFIG_MULTITHREAD
|
||||
pthread_mutex_lock(&jobq->mutex);
|
||||
#endif
|
||||
if (jobq->buf_end >= jobq->buf_wr + job_size) {
|
||||
memcpy(jobq->buf_wr, job, job_size);
|
||||
jobq->buf_wr = jobq->buf_wr + job_size;
|
||||
#if CONFIG_MULTITHREAD
|
||||
pthread_cond_signal(&jobq->cond);
|
||||
#endif
|
||||
ret = 0;
|
||||
} else {
|
||||
/* Wrap around case is not supported */
|
||||
assert(0);
|
||||
ret = 1;
|
||||
}
|
||||
#if CONFIG_MULTITHREAD
|
||||
pthread_mutex_unlock(&jobq->mutex);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
int vp9_jobq_dequeue(JobQueueRowMt *jobq, void *job, size_t job_size,
|
||||
int blocking) {
|
||||
int ret = 0;
|
||||
#if CONFIG_MULTITHREAD
|
||||
pthread_mutex_lock(&jobq->mutex);
|
||||
#endif
|
||||
if (jobq->buf_end >= jobq->buf_rd + job_size) {
|
||||
while (1) {
|
||||
if (jobq->buf_wr >= jobq->buf_rd + job_size) {
|
||||
memcpy(job, jobq->buf_rd, job_size);
|
||||
jobq->buf_rd = jobq->buf_rd + job_size;
|
||||
ret = 0;
|
||||
break;
|
||||
} else {
|
||||
/* If all the entries have been dequeued, then break and return */
|
||||
if (jobq->terminate == 1) {
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
if (blocking == 1) {
|
||||
#if CONFIG_MULTITHREAD
|
||||
pthread_cond_wait(&jobq->cond, &jobq->mutex);
|
||||
#endif
|
||||
} else {
|
||||
/* If there is no job available,
|
||||
* and this is non blocking call then return fail */
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Wrap around case is not supported */
|
||||
ret = 1;
|
||||
}
|
||||
#if CONFIG_MULTITHREAD
|
||||
pthread_mutex_unlock(&jobq->mutex);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2018 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 VPX_VP9_DECODER_VP9_JOB_QUEUE_H_
|
||||
#define VPX_VP9_DECODER_VP9_JOB_QUEUE_H_
|
||||
|
||||
#include "vpx_util/vpx_thread.h"
|
||||
|
||||
typedef struct {
|
||||
// Pointer to buffer base which contains the jobs
|
||||
uint8_t *buf_base;
|
||||
|
||||
// Pointer to current address where new job can be added
|
||||
uint8_t *volatile buf_wr;
|
||||
|
||||
// Pointer to current address from where next job can be obtained
|
||||
uint8_t *volatile buf_rd;
|
||||
|
||||
// Pointer to end of job buffer
|
||||
uint8_t *buf_end;
|
||||
|
||||
int terminate;
|
||||
|
||||
#if CONFIG_MULTITHREAD
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t cond;
|
||||
#endif
|
||||
} JobQueueRowMt;
|
||||
|
||||
void vp9_jobq_init(JobQueueRowMt *jobq, uint8_t *buf, size_t buf_size);
|
||||
void vp9_jobq_reset(JobQueueRowMt *jobq);
|
||||
void vp9_jobq_deinit(JobQueueRowMt *jobq);
|
||||
void vp9_jobq_terminate(JobQueueRowMt *jobq);
|
||||
int vp9_jobq_queue(JobQueueRowMt *jobq, void *job, size_t job_size);
|
||||
int vp9_jobq_dequeue(JobQueueRowMt *jobq, void *job, size_t job_size,
|
||||
int blocking);
|
||||
|
||||
#endif // VPX_VP9_DECODER_VP9_JOB_QUEUE_H_
|
||||
@@ -0,0 +1,352 @@
|
||||
/*
|
||||
* Copyright (c) 2017 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 "./vpx_config.h"
|
||||
#include "./vp9_rtcd.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 horizontal_add_s8x16(const int8x16_t v_sum_diff_total) {
|
||||
const int16x8_t fe_dc_ba_98_76_54_32_10 = vpaddlq_s8(v_sum_diff_total);
|
||||
const int32x4_t fedc_ba98_7654_3210 = vpaddlq_s16(fe_dc_ba_98_76_54_32_10);
|
||||
const int64x2_t fedcba98_76543210 = vpaddlq_s32(fedc_ba98_7654_3210);
|
||||
const int64x1_t x = vqadd_s64(vget_high_s64(fedcba98_76543210),
|
||||
vget_low_s64(fedcba98_76543210));
|
||||
const int sum_diff = vget_lane_s32(vreinterpret_s32_s64(x), 0);
|
||||
return sum_diff;
|
||||
}
|
||||
|
||||
// Denoise a 16x1 vector.
|
||||
static INLINE int8x16_t denoiser_16x1_neon(
|
||||
const uint8_t *sig, const uint8_t *mc_running_avg_y, uint8_t *running_avg_y,
|
||||
const uint8x16_t v_level1_threshold, const uint8x16_t v_level2_threshold,
|
||||
const uint8x16_t v_level3_threshold, const uint8x16_t v_level1_adjustment,
|
||||
const uint8x16_t v_delta_level_1_and_2,
|
||||
const uint8x16_t v_delta_level_2_and_3, int8x16_t v_sum_diff_total) {
|
||||
const uint8x16_t v_sig = vld1q_u8(sig);
|
||||
const uint8x16_t v_mc_running_avg_y = vld1q_u8(mc_running_avg_y);
|
||||
|
||||
/* Calculate absolute difference and sign masks. */
|
||||
const uint8x16_t v_abs_diff = vabdq_u8(v_sig, v_mc_running_avg_y);
|
||||
const uint8x16_t v_diff_pos_mask = vcltq_u8(v_sig, v_mc_running_avg_y);
|
||||
const uint8x16_t v_diff_neg_mask = vcgtq_u8(v_sig, v_mc_running_avg_y);
|
||||
|
||||
/* Figure out which level that put us in. */
|
||||
const uint8x16_t v_level1_mask = vcleq_u8(v_level1_threshold, v_abs_diff);
|
||||
const uint8x16_t v_level2_mask = vcleq_u8(v_level2_threshold, v_abs_diff);
|
||||
const uint8x16_t v_level3_mask = vcleq_u8(v_level3_threshold, v_abs_diff);
|
||||
|
||||
/* Calculate absolute adjustments for level 1, 2 and 3. */
|
||||
const uint8x16_t v_level2_adjustment =
|
||||
vandq_u8(v_level2_mask, v_delta_level_1_and_2);
|
||||
const uint8x16_t v_level3_adjustment =
|
||||
vandq_u8(v_level3_mask, v_delta_level_2_and_3);
|
||||
const uint8x16_t v_level1and2_adjustment =
|
||||
vaddq_u8(v_level1_adjustment, v_level2_adjustment);
|
||||
const uint8x16_t v_level1and2and3_adjustment =
|
||||
vaddq_u8(v_level1and2_adjustment, v_level3_adjustment);
|
||||
|
||||
/* Figure adjustment absolute value by selecting between the absolute
|
||||
* difference if in level0 or the value for level 1, 2 and 3.
|
||||
*/
|
||||
const uint8x16_t v_abs_adjustment =
|
||||
vbslq_u8(v_level1_mask, v_level1and2and3_adjustment, v_abs_diff);
|
||||
|
||||
/* Calculate positive and negative adjustments. Apply them to the signal
|
||||
* and accumulate them. Adjustments are less than eight and the maximum
|
||||
* sum of them (7 * 16) can fit in a signed char.
|
||||
*/
|
||||
const uint8x16_t v_pos_adjustment =
|
||||
vandq_u8(v_diff_pos_mask, v_abs_adjustment);
|
||||
const uint8x16_t v_neg_adjustment =
|
||||
vandq_u8(v_diff_neg_mask, v_abs_adjustment);
|
||||
|
||||
uint8x16_t v_running_avg_y = vqaddq_u8(v_sig, v_pos_adjustment);
|
||||
v_running_avg_y = vqsubq_u8(v_running_avg_y, v_neg_adjustment);
|
||||
|
||||
/* Store results. */
|
||||
vst1q_u8(running_avg_y, v_running_avg_y);
|
||||
|
||||
/* Sum all the accumulators to have the sum of all pixel differences
|
||||
* for this macroblock.
|
||||
*/
|
||||
{
|
||||
const int8x16_t v_sum_diff =
|
||||
vqsubq_s8(vreinterpretq_s8_u8(v_pos_adjustment),
|
||||
vreinterpretq_s8_u8(v_neg_adjustment));
|
||||
v_sum_diff_total = vaddq_s8(v_sum_diff_total, v_sum_diff);
|
||||
}
|
||||
return v_sum_diff_total;
|
||||
}
|
||||
|
||||
static INLINE int8x16_t denoiser_adjust_16x1_neon(
|
||||
const uint8_t *sig, const uint8_t *mc_running_avg_y, uint8_t *running_avg_y,
|
||||
const uint8x16_t k_delta, int8x16_t v_sum_diff_total) {
|
||||
uint8x16_t v_running_avg_y = vld1q_u8(running_avg_y);
|
||||
const uint8x16_t v_sig = vld1q_u8(sig);
|
||||
const uint8x16_t v_mc_running_avg_y = vld1q_u8(mc_running_avg_y);
|
||||
|
||||
/* Calculate absolute difference and sign masks. */
|
||||
const uint8x16_t v_abs_diff = vabdq_u8(v_sig, v_mc_running_avg_y);
|
||||
const uint8x16_t v_diff_pos_mask = vcltq_u8(v_sig, v_mc_running_avg_y);
|
||||
const uint8x16_t v_diff_neg_mask = vcgtq_u8(v_sig, v_mc_running_avg_y);
|
||||
// Clamp absolute difference to delta to get the adjustment.
|
||||
const uint8x16_t v_abs_adjustment = vminq_u8(v_abs_diff, (k_delta));
|
||||
|
||||
const uint8x16_t v_pos_adjustment =
|
||||
vandq_u8(v_diff_pos_mask, v_abs_adjustment);
|
||||
const uint8x16_t v_neg_adjustment =
|
||||
vandq_u8(v_diff_neg_mask, v_abs_adjustment);
|
||||
|
||||
v_running_avg_y = vqsubq_u8(v_running_avg_y, v_pos_adjustment);
|
||||
v_running_avg_y = vqaddq_u8(v_running_avg_y, v_neg_adjustment);
|
||||
|
||||
/* Store results. */
|
||||
vst1q_u8(running_avg_y, v_running_avg_y);
|
||||
|
||||
{
|
||||
const int8x16_t v_sum_diff =
|
||||
vqsubq_s8(vreinterpretq_s8_u8(v_neg_adjustment),
|
||||
vreinterpretq_s8_u8(v_pos_adjustment));
|
||||
v_sum_diff_total = vaddq_s8(v_sum_diff_total, v_sum_diff);
|
||||
}
|
||||
return v_sum_diff_total;
|
||||
}
|
||||
|
||||
// Denoise 8x8 and 8x16 blocks.
|
||||
static int vp9_denoiser_8xN_neon(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];
|
||||
|
||||
const uint8x16_t v_level1_adjustment = vmovq_n_u8(
|
||||
(motion_magnitude <= MOTION_MAGNITUDE_THRESHOLD) ? 4 + shift_inc : 3);
|
||||
const uint8x16_t v_delta_level_1_and_2 = vdupq_n_u8(1);
|
||||
const uint8x16_t v_delta_level_2_and_3 = vdupq_n_u8(2);
|
||||
const uint8x16_t v_level1_threshold = vdupq_n_u8(4 + shift_inc);
|
||||
const uint8x16_t v_level2_threshold = vdupq_n_u8(8);
|
||||
const uint8x16_t v_level3_threshold = vdupq_n_u8(16);
|
||||
|
||||
const int b_height = (4 << b_height_log2_lookup[bs]) >> 1;
|
||||
|
||||
int8x16_t v_sum_diff_total = vdupq_n_s8(0);
|
||||
|
||||
for (r = 0; r < b_height; ++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);
|
||||
v_sum_diff_total = denoiser_16x1_neon(
|
||||
sig_buffer[r], mc_running_buffer[r], running_buffer[r],
|
||||
v_level1_threshold, v_level2_threshold, v_level3_threshold,
|
||||
v_level1_adjustment, v_delta_level_1_and_2, v_delta_level_2_and_3,
|
||||
v_sum_diff_total);
|
||||
{
|
||||
const uint8x16_t v_running_buffer = vld1q_u8(running_buffer[r]);
|
||||
const uint8x8_t v_running_buffer_high = vget_high_u8(v_running_buffer);
|
||||
const uint8x8_t v_running_buffer_low = vget_low_u8(v_running_buffer);
|
||||
vst1_u8(running_avg_y, v_running_buffer_low);
|
||||
vst1_u8(running_avg_y + avg_y_stride, v_running_buffer_high);
|
||||
}
|
||||
// Update pointers for next iteration.
|
||||
sig += (sig_stride << 1);
|
||||
mc_running_avg_y += (mc_avg_y_stride << 1);
|
||||
running_avg_y += (avg_y_stride << 1);
|
||||
}
|
||||
|
||||
{
|
||||
sum_diff = horizontal_add_s8x16(v_sum_diff_total);
|
||||
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 uint8x16_t k_delta = vmovq_n_u8(delta);
|
||||
running_avg_y -= avg_y_stride * (b_height << 1);
|
||||
for (r = 0; r < b_height; ++r) {
|
||||
v_sum_diff_total = denoiser_adjust_16x1_neon(
|
||||
sig_buffer[r], mc_running_buffer[r], running_buffer[r], k_delta,
|
||||
v_sum_diff_total);
|
||||
{
|
||||
const uint8x16_t v_running_buffer = vld1q_u8(running_buffer[r]);
|
||||
const uint8x8_t v_running_buffer_high =
|
||||
vget_high_u8(v_running_buffer);
|
||||
const uint8x8_t v_running_buffer_low =
|
||||
vget_low_u8(v_running_buffer);
|
||||
vst1_u8(running_avg_y, v_running_buffer_low);
|
||||
vst1_u8(running_avg_y + avg_y_stride, v_running_buffer_high);
|
||||
}
|
||||
// Update pointers for next iteration.
|
||||
running_avg_y += (avg_y_stride << 1);
|
||||
}
|
||||
sum_diff = horizontal_add_s8x16(v_sum_diff_total);
|
||||
if (abs(sum_diff) > sum_diff_thresh) {
|
||||
return COPY_BLOCK;
|
||||
}
|
||||
} else {
|
||||
return COPY_BLOCK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FILTER_BLOCK;
|
||||
}
|
||||
|
||||
// Denoise 16x16, 16x32, 32x16, 32x32, 32x64, 64x32 and 64x64 blocks.
|
||||
static int vp9_denoiser_NxM_neon(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) {
|
||||
const int shift_inc =
|
||||
(increase_denoising && motion_magnitude <= MOTION_MAGNITUDE_THRESHOLD)
|
||||
? 1
|
||||
: 0;
|
||||
const uint8x16_t v_level1_adjustment = vmovq_n_u8(
|
||||
(motion_magnitude <= MOTION_MAGNITUDE_THRESHOLD) ? 4 + shift_inc : 3);
|
||||
const uint8x16_t v_delta_level_1_and_2 = vdupq_n_u8(1);
|
||||
const uint8x16_t v_delta_level_2_and_3 = vdupq_n_u8(2);
|
||||
const uint8x16_t v_level1_threshold = vmovq_n_u8(4 + shift_inc);
|
||||
const uint8x16_t v_level2_threshold = vdupq_n_u8(8);
|
||||
const uint8x16_t v_level3_threshold = vdupq_n_u8(16);
|
||||
|
||||
const int b_width = (4 << b_width_log2_lookup[bs]);
|
||||
const int b_height = (4 << b_height_log2_lookup[bs]);
|
||||
const int b_width_shift4 = b_width >> 4;
|
||||
|
||||
int8x16_t v_sum_diff_total[4][4];
|
||||
int r, c, sum_diff = 0;
|
||||
|
||||
for (r = 0; r < 4; ++r) {
|
||||
for (c = 0; c < b_width_shift4; ++c) {
|
||||
v_sum_diff_total[c][r] = vdupq_n_s8(0);
|
||||
}
|
||||
}
|
||||
|
||||
for (r = 0; r < b_height; ++r) {
|
||||
for (c = 0; c < b_width_shift4; ++c) {
|
||||
v_sum_diff_total[c][r >> 4] = denoiser_16x1_neon(
|
||||
sig, mc_running_avg_y, running_avg_y, v_level1_threshold,
|
||||
v_level2_threshold, v_level3_threshold, v_level1_adjustment,
|
||||
v_delta_level_1_and_2, v_delta_level_2_and_3,
|
||||
v_sum_diff_total[c][r >> 4]);
|
||||
|
||||
// Update pointers for next iteration.
|
||||
sig += 16;
|
||||
mc_running_avg_y += 16;
|
||||
running_avg_y += 16;
|
||||
}
|
||||
|
||||
if ((r & 0xf) == 0xf || (bs == BLOCK_16X8 && r == 7)) {
|
||||
for (c = 0; c < b_width_shift4; ++c) {
|
||||
sum_diff += horizontal_add_s8x16(v_sum_diff_total[c][r >> 4]);
|
||||
}
|
||||
}
|
||||
|
||||
// Update pointers for next iteration.
|
||||
sig = sig - b_width + sig_stride;
|
||||
mc_running_avg_y = mc_running_avg_y - b_width + mc_avg_y_stride;
|
||||
running_avg_y = running_avg_y - b_width + avg_y_stride;
|
||||
}
|
||||
|
||||
{
|
||||
const int 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 uint8x16_t k_delta = vdupq_n_u8(delta);
|
||||
sig -= sig_stride * b_height;
|
||||
mc_running_avg_y -= mc_avg_y_stride * b_height;
|
||||
running_avg_y -= avg_y_stride * b_height;
|
||||
sum_diff = 0;
|
||||
|
||||
for (r = 0; r < b_height; ++r) {
|
||||
for (c = 0; c < b_width_shift4; ++c) {
|
||||
v_sum_diff_total[c][r >> 4] =
|
||||
denoiser_adjust_16x1_neon(sig, mc_running_avg_y, running_avg_y,
|
||||
k_delta, v_sum_diff_total[c][r >> 4]);
|
||||
|
||||
// Update pointers for next iteration.
|
||||
sig += 16;
|
||||
mc_running_avg_y += 16;
|
||||
running_avg_y += 16;
|
||||
}
|
||||
if ((r & 0xf) == 0xf || (bs == BLOCK_16X8 && r == 7)) {
|
||||
for (c = 0; c < b_width_shift4; ++c) {
|
||||
sum_diff += horizontal_add_s8x16(v_sum_diff_total[c][r >> 4]);
|
||||
}
|
||||
}
|
||||
|
||||
sig = sig - b_width + sig_stride;
|
||||
mc_running_avg_y = mc_running_avg_y - b_width + mc_avg_y_stride;
|
||||
running_avg_y = running_avg_y - b_width + avg_y_stride;
|
||||
}
|
||||
|
||||
if (abs(sum_diff) > sum_diff_thresh) {
|
||||
return COPY_BLOCK;
|
||||
}
|
||||
} else {
|
||||
return COPY_BLOCK;
|
||||
}
|
||||
}
|
||||
}
|
||||
return FILTER_BLOCK;
|
||||
}
|
||||
|
||||
int vp9_denoiser_filter_neon(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) {
|
||||
// Rank by frequency of the block type to have an early termination.
|
||||
if (bs == BLOCK_16X16 || bs == BLOCK_32X32 || bs == BLOCK_64X64 ||
|
||||
bs == BLOCK_16X32 || bs == BLOCK_16X8 || bs == BLOCK_32X16 ||
|
||||
bs == BLOCK_32X64 || bs == BLOCK_64X32) {
|
||||
return vp9_denoiser_NxM_neon(sig, sig_stride, mc_avg, mc_avg_stride, avg,
|
||||
avg_stride, increase_denoising, bs,
|
||||
motion_magnitude);
|
||||
} else if (bs == BLOCK_8X8 || bs == BLOCK_8X16) {
|
||||
return vp9_denoiser_8xN_neon(sig, sig_stride, mc_avg, mc_avg_stride, avg,
|
||||
avg_stride, increase_denoising, bs,
|
||||
motion_magnitude, 8);
|
||||
}
|
||||
return COPY_BLOCK;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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 <assert.h>
|
||||
|
||||
#include "./vp9_rtcd.h"
|
||||
|
||||
int64_t vp9_block_error_fp_neon(const int16_t *coeff, const int16_t *dqcoeff,
|
||||
int block_size) {
|
||||
int64x2_t error = vdupq_n_s64(0);
|
||||
|
||||
assert(block_size >= 8);
|
||||
assert((block_size % 8) == 0);
|
||||
|
||||
do {
|
||||
const int16x8_t c = vld1q_s16(coeff);
|
||||
const int16x8_t d = vld1q_s16(dqcoeff);
|
||||
const int16x8_t diff = vsubq_s16(c, d);
|
||||
const int16x4_t diff_lo = vget_low_s16(diff);
|
||||
const int16x4_t diff_hi = vget_high_s16(diff);
|
||||
// diff is 15-bits, the squares 30, so we can store 2 in 31-bits before
|
||||
// accumulating them in 64-bits.
|
||||
const int32x4_t err0 = vmull_s16(diff_lo, diff_lo);
|
||||
const int32x4_t err1 = vmlal_s16(err0, diff_hi, diff_hi);
|
||||
const int64x2_t err2 = vaddl_s32(vget_low_s32(err1), vget_high_s32(err1));
|
||||
error = vaddq_s64(error, err2);
|
||||
coeff += 8;
|
||||
dqcoeff += 8;
|
||||
block_size -= 8;
|
||||
} while (block_size != 0);
|
||||
|
||||
return vgetq_lane_s64(error, 0) + vgetq_lane_s64(error, 1);
|
||||
}
|
||||
@@ -0,0 +1,843 @@
|
||||
/*
|
||||
* Copyright (c) 2017 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_scale_rtcd.h"
|
||||
#include "vp9/common/vp9_blockd.h"
|
||||
#include "vpx_dsp/arm/transpose_neon.h"
|
||||
#include "vpx_dsp/arm/vpx_convolve8_neon.h"
|
||||
#include "vpx_dsp/vpx_filter.h"
|
||||
#include "vpx_scale/yv12config.h"
|
||||
|
||||
// Note: The scaling functions could write extra rows and columns in dst, which
|
||||
// exceed the right and bottom boundaries of the destination frame. We rely on
|
||||
// the following frame extension function to fix these rows and columns.
|
||||
|
||||
static INLINE void scale_plane_2_to_1_phase_0(const uint8_t *src,
|
||||
const int src_stride,
|
||||
uint8_t *dst,
|
||||
const int dst_stride, const int w,
|
||||
const int h) {
|
||||
const int max_width = (w + 15) & ~15;
|
||||
int y = h;
|
||||
|
||||
assert(w && h);
|
||||
|
||||
do {
|
||||
int x = max_width;
|
||||
do {
|
||||
const uint8x16x2_t s = vld2q_u8(src);
|
||||
vst1q_u8(dst, s.val[0]);
|
||||
src += 32;
|
||||
dst += 16;
|
||||
x -= 16;
|
||||
} while (x);
|
||||
src += 2 * (src_stride - max_width);
|
||||
dst += dst_stride - max_width;
|
||||
} while (--y);
|
||||
}
|
||||
|
||||
static INLINE void scale_plane_4_to_1_phase_0(const uint8_t *src,
|
||||
const int src_stride,
|
||||
uint8_t *dst,
|
||||
const int dst_stride, const int w,
|
||||
const int h) {
|
||||
const int max_width = (w + 15) & ~15;
|
||||
int y = h;
|
||||
|
||||
assert(w && h);
|
||||
|
||||
do {
|
||||
int x = max_width;
|
||||
do {
|
||||
const uint8x16x4_t s = vld4q_u8(src);
|
||||
vst1q_u8(dst, s.val[0]);
|
||||
src += 64;
|
||||
dst += 16;
|
||||
x -= 16;
|
||||
} while (x);
|
||||
src += 4 * (src_stride - max_width);
|
||||
dst += dst_stride - max_width;
|
||||
} while (--y);
|
||||
}
|
||||
|
||||
static INLINE void scale_plane_bilinear_kernel(
|
||||
const uint8x16_t in0, const uint8x16_t in1, const uint8x16_t in2,
|
||||
const uint8x16_t in3, const uint8x8_t coef0, const uint8x8_t coef1,
|
||||
uint8_t *const dst) {
|
||||
const uint16x8_t h0 = vmull_u8(vget_low_u8(in0), coef0);
|
||||
const uint16x8_t h1 = vmull_u8(vget_high_u8(in0), coef0);
|
||||
const uint16x8_t h2 = vmull_u8(vget_low_u8(in2), coef0);
|
||||
const uint16x8_t h3 = vmull_u8(vget_high_u8(in2), coef0);
|
||||
const uint16x8_t h4 = vmlal_u8(h0, vget_low_u8(in1), coef1);
|
||||
const uint16x8_t h5 = vmlal_u8(h1, vget_high_u8(in1), coef1);
|
||||
const uint16x8_t h6 = vmlal_u8(h2, vget_low_u8(in3), coef1);
|
||||
const uint16x8_t h7 = vmlal_u8(h3, vget_high_u8(in3), coef1);
|
||||
|
||||
const uint8x8_t hor0 = vrshrn_n_u16(h4, 7); // temp: 00 01 02 03 04 05 06 07
|
||||
const uint8x8_t hor1 = vrshrn_n_u16(h5, 7); // temp: 08 09 0A 0B 0C 0D 0E 0F
|
||||
const uint8x8_t hor2 = vrshrn_n_u16(h6, 7); // temp: 10 11 12 13 14 15 16 17
|
||||
const uint8x8_t hor3 = vrshrn_n_u16(h7, 7); // temp: 18 19 1A 1B 1C 1D 1E 1F
|
||||
const uint16x8_t v0 = vmull_u8(hor0, coef0);
|
||||
const uint16x8_t v1 = vmull_u8(hor1, coef0);
|
||||
const uint16x8_t v2 = vmlal_u8(v0, hor2, coef1);
|
||||
const uint16x8_t v3 = vmlal_u8(v1, hor3, coef1);
|
||||
// dst: 0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
const uint8x16_t d = vcombine_u8(vrshrn_n_u16(v2, 7), vrshrn_n_u16(v3, 7));
|
||||
vst1q_u8(dst, d);
|
||||
}
|
||||
|
||||
static INLINE void scale_plane_2_to_1_bilinear(
|
||||
const uint8_t *const src, const int src_stride, uint8_t *dst,
|
||||
const int dst_stride, const int w, const int h, const int16_t c0,
|
||||
const int16_t c1) {
|
||||
const int max_width = (w + 15) & ~15;
|
||||
const uint8_t *src0 = src;
|
||||
const uint8_t *src1 = src + src_stride;
|
||||
const uint8x8_t coef0 = vdup_n_u8(c0);
|
||||
const uint8x8_t coef1 = vdup_n_u8(c1);
|
||||
int y = h;
|
||||
|
||||
assert(w && h);
|
||||
|
||||
do {
|
||||
int x = max_width;
|
||||
do {
|
||||
// 000 002 004 006 008 00A 00C 00E 010 012 014 016 018 01A 01C 01E
|
||||
// 001 003 005 007 009 00B 00D 00F 011 013 015 017 019 01B 01D 01F
|
||||
const uint8x16x2_t s0 = vld2q_u8(src0);
|
||||
// 100 102 104 106 108 10A 10C 10E 110 112 114 116 118 11A 11C 11E
|
||||
// 101 103 105 107 109 10B 10D 10F 111 113 115 117 119 11B 11D 11F
|
||||
const uint8x16x2_t s1 = vld2q_u8(src1);
|
||||
scale_plane_bilinear_kernel(s0.val[0], s0.val[1], s1.val[0], s1.val[1],
|
||||
coef0, coef1, dst);
|
||||
src0 += 32;
|
||||
src1 += 32;
|
||||
dst += 16;
|
||||
x -= 16;
|
||||
} while (x);
|
||||
src0 += 2 * (src_stride - max_width);
|
||||
src1 += 2 * (src_stride - max_width);
|
||||
dst += dst_stride - max_width;
|
||||
} while (--y);
|
||||
}
|
||||
|
||||
static INLINE void scale_plane_4_to_1_bilinear(
|
||||
const uint8_t *const src, const int src_stride, uint8_t *dst,
|
||||
const int dst_stride, const int w, const int h, const int16_t c0,
|
||||
const int16_t c1) {
|
||||
const int max_width = (w + 15) & ~15;
|
||||
const uint8_t *src0 = src;
|
||||
const uint8_t *src1 = src + src_stride;
|
||||
const uint8x8_t coef0 = vdup_n_u8(c0);
|
||||
const uint8x8_t coef1 = vdup_n_u8(c1);
|
||||
int y = h;
|
||||
|
||||
assert(w && h);
|
||||
|
||||
do {
|
||||
int x = max_width;
|
||||
do {
|
||||
// (*) -- useless
|
||||
// 000 004 008 00C 010 014 018 01C 020 024 028 02C 030 034 038 03C
|
||||
// 001 005 009 00D 011 015 019 01D 021 025 029 02D 031 035 039 03D
|
||||
// 002 006 00A 00E 012 016 01A 01E 022 026 02A 02E 032 036 03A 03E (*)
|
||||
// 003 007 00B 00F 013 017 01B 01F 023 027 02B 02F 033 037 03B 03F (*)
|
||||
const uint8x16x4_t s0 = vld4q_u8(src0);
|
||||
// 100 104 108 10C 110 114 118 11C 120 124 128 12C 130 134 138 13C
|
||||
// 101 105 109 10D 111 115 119 11D 121 125 129 12D 131 135 139 13D
|
||||
// 102 106 10A 10E 112 116 11A 11E 122 126 12A 12E 132 136 13A 13E (*)
|
||||
// 103 107 10B 10F 113 117 11B 11F 123 127 12B 12F 133 137 13B 13F (*)
|
||||
const uint8x16x4_t s1 = vld4q_u8(src1);
|
||||
scale_plane_bilinear_kernel(s0.val[0], s0.val[1], s1.val[0], s1.val[1],
|
||||
coef0, coef1, dst);
|
||||
src0 += 64;
|
||||
src1 += 64;
|
||||
dst += 16;
|
||||
x -= 16;
|
||||
} while (x);
|
||||
src0 += 4 * (src_stride - max_width);
|
||||
src1 += 4 * (src_stride - max_width);
|
||||
dst += dst_stride - max_width;
|
||||
} while (--y);
|
||||
}
|
||||
|
||||
static INLINE uint8x8_t scale_filter_bilinear(const uint8x8_t *const s,
|
||||
const uint8x8_t *const coef) {
|
||||
const uint16x8_t h0 = vmull_u8(s[0], coef[0]);
|
||||
const uint16x8_t h1 = vmlal_u8(h0, s[1], coef[1]);
|
||||
|
||||
return vrshrn_n_u16(h1, 7);
|
||||
}
|
||||
|
||||
static void scale_plane_2_to_1_general(const uint8_t *src, const int src_stride,
|
||||
uint8_t *dst, const int dst_stride,
|
||||
const int w, const int h,
|
||||
const int16_t *const coef,
|
||||
uint8_t *const temp_buffer) {
|
||||
const int width_hor = (w + 3) & ~3;
|
||||
const int width_ver = (w + 7) & ~7;
|
||||
const int height_hor = (2 * h + SUBPEL_TAPS - 2 + 7) & ~7;
|
||||
const int height_ver = (h + 3) & ~3;
|
||||
const int16x8_t filters = vld1q_s16(coef);
|
||||
int x, y = height_hor;
|
||||
uint8_t *t = temp_buffer;
|
||||
uint8x8_t s[14], d[4];
|
||||
|
||||
assert(w && h);
|
||||
|
||||
src -= (SUBPEL_TAPS / 2 - 1) * src_stride + SUBPEL_TAPS / 2 + 1;
|
||||
|
||||
// horizontal 4x8
|
||||
// Note: processing 4x8 is about 20% faster than processing row by row using
|
||||
// vld4_u8().
|
||||
do {
|
||||
load_u8_8x8(src + 2, src_stride, &s[0], &s[1], &s[2], &s[3], &s[4], &s[5],
|
||||
&s[6], &s[7]);
|
||||
transpose_u8_8x8(&s[0], &s[1], &s[2], &s[3], &s[4], &s[5], &s[6], &s[7]);
|
||||
x = width_hor;
|
||||
|
||||
do {
|
||||
src += 8;
|
||||
load_u8_8x8(src, src_stride, &s[6], &s[7], &s[8], &s[9], &s[10], &s[11],
|
||||
&s[12], &s[13]);
|
||||
transpose_u8_8x8(&s[6], &s[7], &s[8], &s[9], &s[10], &s[11], &s[12],
|
||||
&s[13]);
|
||||
|
||||
d[0] = scale_filter_8(&s[0], filters); // 00 10 20 30 40 50 60 70
|
||||
d[1] = scale_filter_8(&s[2], filters); // 01 11 21 31 41 51 61 71
|
||||
d[2] = scale_filter_8(&s[4], filters); // 02 12 22 32 42 52 62 72
|
||||
d[3] = scale_filter_8(&s[6], filters); // 03 13 23 33 43 53 63 73
|
||||
// 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
|
||||
transpose_u8_8x4(&d[0], &d[1], &d[2], &d[3]);
|
||||
vst1_lane_u32((uint32_t *)(t + 0 * width_hor), vreinterpret_u32_u8(d[0]),
|
||||
0);
|
||||
vst1_lane_u32((uint32_t *)(t + 1 * width_hor), vreinterpret_u32_u8(d[1]),
|
||||
0);
|
||||
vst1_lane_u32((uint32_t *)(t + 2 * width_hor), vreinterpret_u32_u8(d[2]),
|
||||
0);
|
||||
vst1_lane_u32((uint32_t *)(t + 3 * width_hor), vreinterpret_u32_u8(d[3]),
|
||||
0);
|
||||
vst1_lane_u32((uint32_t *)(t + 4 * width_hor), vreinterpret_u32_u8(d[0]),
|
||||
1);
|
||||
vst1_lane_u32((uint32_t *)(t + 5 * width_hor), vreinterpret_u32_u8(d[1]),
|
||||
1);
|
||||
vst1_lane_u32((uint32_t *)(t + 6 * width_hor), vreinterpret_u32_u8(d[2]),
|
||||
1);
|
||||
vst1_lane_u32((uint32_t *)(t + 7 * width_hor), vreinterpret_u32_u8(d[3]),
|
||||
1);
|
||||
|
||||
s[0] = s[8];
|
||||
s[1] = s[9];
|
||||
s[2] = s[10];
|
||||
s[3] = s[11];
|
||||
s[4] = s[12];
|
||||
s[5] = s[13];
|
||||
|
||||
t += 4;
|
||||
x -= 4;
|
||||
} while (x);
|
||||
src += 8 * src_stride - 2 * width_hor;
|
||||
t += 7 * width_hor;
|
||||
y -= 8;
|
||||
} while (y);
|
||||
|
||||
// vertical 8x4
|
||||
x = width_ver;
|
||||
t = temp_buffer;
|
||||
do {
|
||||
load_u8_8x8(t, width_hor, &s[0], &s[1], &s[2], &s[3], &s[4], &s[5], &s[6],
|
||||
&s[7]);
|
||||
t += 6 * width_hor;
|
||||
y = height_ver;
|
||||
|
||||
do {
|
||||
load_u8_8x8(t, width_hor, &s[6], &s[7], &s[8], &s[9], &s[10], &s[11],
|
||||
&s[12], &s[13]);
|
||||
t += 8 * width_hor;
|
||||
|
||||
d[0] = scale_filter_8(&s[0], filters); // 00 01 02 03 04 05 06 07
|
||||
d[1] = scale_filter_8(&s[2], filters); // 10 11 12 13 14 15 16 17
|
||||
d[2] = scale_filter_8(&s[4], filters); // 20 21 22 23 24 25 26 27
|
||||
d[3] = scale_filter_8(&s[6], filters); // 30 31 32 33 34 35 36 37
|
||||
vst1_u8(dst + 0 * dst_stride, d[0]);
|
||||
vst1_u8(dst + 1 * dst_stride, d[1]);
|
||||
vst1_u8(dst + 2 * dst_stride, d[2]);
|
||||
vst1_u8(dst + 3 * dst_stride, d[3]);
|
||||
|
||||
s[0] = s[8];
|
||||
s[1] = s[9];
|
||||
s[2] = s[10];
|
||||
s[3] = s[11];
|
||||
s[4] = s[12];
|
||||
s[5] = s[13];
|
||||
|
||||
dst += 4 * dst_stride;
|
||||
y -= 4;
|
||||
} while (y);
|
||||
t -= width_hor * (2 * height_ver + 6);
|
||||
t += 8;
|
||||
dst -= height_ver * dst_stride;
|
||||
dst += 8;
|
||||
x -= 8;
|
||||
} while (x);
|
||||
}
|
||||
|
||||
static void scale_plane_4_to_1_general(const uint8_t *src, const int src_stride,
|
||||
uint8_t *dst, const int dst_stride,
|
||||
const int w, const int h,
|
||||
const int16_t *const coef,
|
||||
uint8_t *const temp_buffer) {
|
||||
const int width_hor = (w + 1) & ~1;
|
||||
const int width_ver = (w + 7) & ~7;
|
||||
const int height_hor = (4 * h + SUBPEL_TAPS - 2 + 7) & ~7;
|
||||
const int height_ver = (h + 1) & ~1;
|
||||
const int16x8_t filters = vld1q_s16(coef);
|
||||
int x, y = height_hor;
|
||||
uint8_t *t = temp_buffer;
|
||||
uint8x8_t s[12], d[2];
|
||||
|
||||
assert(w && h);
|
||||
|
||||
src -= (SUBPEL_TAPS / 2 - 1) * src_stride + SUBPEL_TAPS / 2 + 3;
|
||||
|
||||
// horizontal 2x8
|
||||
// Note: processing 2x8 is about 20% faster than processing row by row using
|
||||
// vld4_u8().
|
||||
do {
|
||||
load_u8_8x8(src + 4, src_stride, &s[0], &s[1], &s[2], &s[3], &s[4], &s[5],
|
||||
&s[6], &s[7]);
|
||||
transpose_u8_4x8(&s[0], &s[1], &s[2], &s[3], s[4], s[5], s[6], s[7]);
|
||||
x = width_hor;
|
||||
|
||||
do {
|
||||
uint8x8x2_t dd;
|
||||
src += 8;
|
||||
load_u8_8x8(src, src_stride, &s[4], &s[5], &s[6], &s[7], &s[8], &s[9],
|
||||
&s[10], &s[11]);
|
||||
transpose_u8_8x8(&s[4], &s[5], &s[6], &s[7], &s[8], &s[9], &s[10],
|
||||
&s[11]);
|
||||
|
||||
d[0] = scale_filter_8(&s[0], filters); // 00 10 20 30 40 50 60 70
|
||||
d[1] = scale_filter_8(&s[4], filters); // 01 11 21 31 41 51 61 71
|
||||
// dd.val[0]: 00 01 20 21 40 41 60 61
|
||||
// dd.val[1]: 10 11 30 31 50 51 70 71
|
||||
dd = vtrn_u8(d[0], d[1]);
|
||||
vst1_lane_u16((uint16_t *)(t + 0 * width_hor),
|
||||
vreinterpret_u16_u8(dd.val[0]), 0);
|
||||
vst1_lane_u16((uint16_t *)(t + 1 * width_hor),
|
||||
vreinterpret_u16_u8(dd.val[1]), 0);
|
||||
vst1_lane_u16((uint16_t *)(t + 2 * width_hor),
|
||||
vreinterpret_u16_u8(dd.val[0]), 1);
|
||||
vst1_lane_u16((uint16_t *)(t + 3 * width_hor),
|
||||
vreinterpret_u16_u8(dd.val[1]), 1);
|
||||
vst1_lane_u16((uint16_t *)(t + 4 * width_hor),
|
||||
vreinterpret_u16_u8(dd.val[0]), 2);
|
||||
vst1_lane_u16((uint16_t *)(t + 5 * width_hor),
|
||||
vreinterpret_u16_u8(dd.val[1]), 2);
|
||||
vst1_lane_u16((uint16_t *)(t + 6 * width_hor),
|
||||
vreinterpret_u16_u8(dd.val[0]), 3);
|
||||
vst1_lane_u16((uint16_t *)(t + 7 * width_hor),
|
||||
vreinterpret_u16_u8(dd.val[1]), 3);
|
||||
|
||||
s[0] = s[8];
|
||||
s[1] = s[9];
|
||||
s[2] = s[10];
|
||||
s[3] = s[11];
|
||||
|
||||
t += 2;
|
||||
x -= 2;
|
||||
} while (x);
|
||||
src += 8 * src_stride - 4 * width_hor;
|
||||
t += 7 * width_hor;
|
||||
y -= 8;
|
||||
} while (y);
|
||||
|
||||
// vertical 8x2
|
||||
x = width_ver;
|
||||
t = temp_buffer;
|
||||
do {
|
||||
load_u8_8x4(t, width_hor, &s[0], &s[1], &s[2], &s[3]);
|
||||
t += 4 * width_hor;
|
||||
y = height_ver;
|
||||
|
||||
do {
|
||||
load_u8_8x8(t, width_hor, &s[4], &s[5], &s[6], &s[7], &s[8], &s[9],
|
||||
&s[10], &s[11]);
|
||||
t += 8 * width_hor;
|
||||
|
||||
d[0] = scale_filter_8(&s[0], filters); // 00 01 02 03 04 05 06 07
|
||||
d[1] = scale_filter_8(&s[4], filters); // 10 11 12 13 14 15 16 17
|
||||
vst1_u8(dst + 0 * dst_stride, d[0]);
|
||||
vst1_u8(dst + 1 * dst_stride, d[1]);
|
||||
|
||||
s[0] = s[8];
|
||||
s[1] = s[9];
|
||||
s[2] = s[10];
|
||||
s[3] = s[11];
|
||||
|
||||
dst += 2 * dst_stride;
|
||||
y -= 2;
|
||||
} while (y);
|
||||
t -= width_hor * (4 * height_ver + 4);
|
||||
t += 8;
|
||||
dst -= height_ver * dst_stride;
|
||||
dst += 8;
|
||||
x -= 8;
|
||||
} while (x);
|
||||
}
|
||||
|
||||
// Notes for 4 to 3 scaling:
|
||||
//
|
||||
// 1. 6 rows are calculated in each horizontal inner loop, so width_hor must be
|
||||
// multiple of 6, and no less than w.
|
||||
//
|
||||
// 2. 8 rows are calculated in each vertical inner loop, so width_ver must be
|
||||
// multiple of 8, and no less than w.
|
||||
//
|
||||
// 3. 8 columns are calculated in each horizontal inner loop for further
|
||||
// vertical scaling, so height_hor must be multiple of 8, and no less than
|
||||
// 4 * h / 3.
|
||||
//
|
||||
// 4. 6 columns are calculated in each vertical inner loop, so height_ver must
|
||||
// be multiple of 6, and no less than h.
|
||||
//
|
||||
// 5. The physical location of the last row of the 4 to 3 scaled frame is
|
||||
// decided by phase_scaler, and are always less than 1 pixel below the last row
|
||||
// of the original image.
|
||||
|
||||
static void scale_plane_4_to_3_bilinear(const uint8_t *src,
|
||||
const int src_stride, uint8_t *dst,
|
||||
const int dst_stride, const int w,
|
||||
const int h, const int phase_scaler,
|
||||
uint8_t *const temp_buffer) {
|
||||
static const int step_q4 = 16 * 4 / 3;
|
||||
const int width_hor = (w + 5) - ((w + 5) % 6);
|
||||
const int stride_hor = width_hor + 2; // store 2 extra pixels
|
||||
const int width_ver = (w + 7) & ~7;
|
||||
// We only need 1 extra row below because there are only 2 bilinear
|
||||
// coefficients.
|
||||
const int height_hor = (4 * h / 3 + 1 + 7) & ~7;
|
||||
const int height_ver = (h + 5) - ((h + 5) % 6);
|
||||
int x, y = height_hor;
|
||||
uint8_t *t = temp_buffer;
|
||||
uint8x8_t s[9], d[8], c[6];
|
||||
|
||||
assert(w && h);
|
||||
|
||||
c[0] = vdup_n_u8((uint8_t)vp9_filter_kernels[BILINEAR][phase_scaler][3]);
|
||||
c[1] = vdup_n_u8((uint8_t)vp9_filter_kernels[BILINEAR][phase_scaler][4]);
|
||||
c[2] = vdup_n_u8(
|
||||
(uint8_t)vp9_filter_kernels[BILINEAR][(phase_scaler + 1 * step_q4) &
|
||||
SUBPEL_MASK][3]);
|
||||
c[3] = vdup_n_u8(
|
||||
(uint8_t)vp9_filter_kernels[BILINEAR][(phase_scaler + 1 * step_q4) &
|
||||
SUBPEL_MASK][4]);
|
||||
c[4] = vdup_n_u8(
|
||||
(uint8_t)vp9_filter_kernels[BILINEAR][(phase_scaler + 2 * step_q4) &
|
||||
SUBPEL_MASK][3]);
|
||||
c[5] = vdup_n_u8(
|
||||
(uint8_t)vp9_filter_kernels[BILINEAR][(phase_scaler + 2 * step_q4) &
|
||||
SUBPEL_MASK][4]);
|
||||
|
||||
d[6] = vdup_n_u8(0);
|
||||
d[7] = vdup_n_u8(0);
|
||||
|
||||
// horizontal 6x8
|
||||
do {
|
||||
load_u8_8x8(src, src_stride, &s[0], &s[1], &s[2], &s[3], &s[4], &s[5],
|
||||
&s[6], &s[7]);
|
||||
src += 1;
|
||||
transpose_u8_8x8(&s[0], &s[1], &s[2], &s[3], &s[4], &s[5], &s[6], &s[7]);
|
||||
x = width_hor;
|
||||
|
||||
do {
|
||||
load_u8_8x8(src, src_stride, &s[1], &s[2], &s[3], &s[4], &s[5], &s[6],
|
||||
&s[7], &s[8]);
|
||||
src += 8;
|
||||
transpose_u8_8x8(&s[1], &s[2], &s[3], &s[4], &s[5], &s[6], &s[7], &s[8]);
|
||||
|
||||
// 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
|
||||
d[0] = scale_filter_bilinear(&s[0], &c[0]);
|
||||
d[1] =
|
||||
scale_filter_bilinear(&s[(phase_scaler + 1 * step_q4) >> 4], &c[2]);
|
||||
d[2] =
|
||||
scale_filter_bilinear(&s[(phase_scaler + 2 * step_q4) >> 4], &c[4]);
|
||||
d[3] = scale_filter_bilinear(&s[4], &c[0]);
|
||||
d[4] = scale_filter_bilinear(&s[4 + ((phase_scaler + 1 * step_q4) >> 4)],
|
||||
&c[2]);
|
||||
d[5] = scale_filter_bilinear(&s[4 + ((phase_scaler + 2 * step_q4) >> 4)],
|
||||
&c[4]);
|
||||
|
||||
// 00 01 02 03 04 05 xx xx
|
||||
// 10 11 12 13 14 15 xx xx
|
||||
// 20 21 22 23 24 25 xx xx
|
||||
// 30 31 32 33 34 35 xx xx
|
||||
// 40 41 42 43 44 45 xx xx
|
||||
// 50 51 52 53 54 55 xx xx
|
||||
// 60 61 62 63 64 65 xx xx
|
||||
// 70 71 72 73 74 75 xx xx
|
||||
transpose_u8_8x8(&d[0], &d[1], &d[2], &d[3], &d[4], &d[5], &d[6], &d[7]);
|
||||
// store 2 extra pixels
|
||||
vst1_u8(t + 0 * stride_hor, d[0]);
|
||||
vst1_u8(t + 1 * stride_hor, d[1]);
|
||||
vst1_u8(t + 2 * stride_hor, d[2]);
|
||||
vst1_u8(t + 3 * stride_hor, d[3]);
|
||||
vst1_u8(t + 4 * stride_hor, d[4]);
|
||||
vst1_u8(t + 5 * stride_hor, d[5]);
|
||||
vst1_u8(t + 6 * stride_hor, d[6]);
|
||||
vst1_u8(t + 7 * stride_hor, d[7]);
|
||||
|
||||
s[0] = s[8];
|
||||
|
||||
t += 6;
|
||||
x -= 6;
|
||||
} while (x);
|
||||
src += 8 * src_stride - 4 * width_hor / 3 - 1;
|
||||
t += 7 * stride_hor + 2;
|
||||
y -= 8;
|
||||
} while (y);
|
||||
|
||||
// vertical 8x6
|
||||
x = width_ver;
|
||||
t = temp_buffer;
|
||||
do {
|
||||
load_u8_8x8(t, stride_hor, &s[0], &s[1], &s[2], &s[3], &s[4], &s[5], &s[6],
|
||||
&s[7]);
|
||||
t += stride_hor;
|
||||
y = height_ver;
|
||||
|
||||
do {
|
||||
load_u8_8x8(t, stride_hor, &s[1], &s[2], &s[3], &s[4], &s[5], &s[6],
|
||||
&s[7], &s[8]);
|
||||
t += 8 * stride_hor;
|
||||
|
||||
d[0] = scale_filter_bilinear(&s[0], &c[0]);
|
||||
d[1] =
|
||||
scale_filter_bilinear(&s[(phase_scaler + 1 * step_q4) >> 4], &c[2]);
|
||||
d[2] =
|
||||
scale_filter_bilinear(&s[(phase_scaler + 2 * step_q4) >> 4], &c[4]);
|
||||
d[3] = scale_filter_bilinear(&s[4], &c[0]);
|
||||
d[4] = scale_filter_bilinear(&s[4 + ((phase_scaler + 1 * step_q4) >> 4)],
|
||||
&c[2]);
|
||||
d[5] = scale_filter_bilinear(&s[4 + ((phase_scaler + 2 * step_q4) >> 4)],
|
||||
&c[4]);
|
||||
vst1_u8(dst + 0 * dst_stride, d[0]);
|
||||
vst1_u8(dst + 1 * dst_stride, d[1]);
|
||||
vst1_u8(dst + 2 * dst_stride, d[2]);
|
||||
vst1_u8(dst + 3 * dst_stride, d[3]);
|
||||
vst1_u8(dst + 4 * dst_stride, d[4]);
|
||||
vst1_u8(dst + 5 * dst_stride, d[5]);
|
||||
|
||||
s[0] = s[8];
|
||||
|
||||
dst += 6 * dst_stride;
|
||||
y -= 6;
|
||||
} while (y);
|
||||
t -= stride_hor * (4 * height_ver / 3 + 1);
|
||||
t += 8;
|
||||
dst -= height_ver * dst_stride;
|
||||
dst += 8;
|
||||
x -= 8;
|
||||
} while (x);
|
||||
}
|
||||
|
||||
static void scale_plane_4_to_3_general(const uint8_t *src, const int src_stride,
|
||||
uint8_t *dst, const int dst_stride,
|
||||
const int w, const int h,
|
||||
const InterpKernel *const coef,
|
||||
const int phase_scaler,
|
||||
uint8_t *const temp_buffer) {
|
||||
static const int step_q4 = 16 * 4 / 3;
|
||||
const int width_hor = (w + 5) - ((w + 5) % 6);
|
||||
const int stride_hor = width_hor + 2; // store 2 extra pixels
|
||||
const int width_ver = (w + 7) & ~7;
|
||||
// We need (SUBPEL_TAPS - 1) extra rows: (SUBPEL_TAPS / 2 - 1) extra rows
|
||||
// above and (SUBPEL_TAPS / 2) extra rows below.
|
||||
const int height_hor = (4 * h / 3 + SUBPEL_TAPS - 1 + 7) & ~7;
|
||||
const int height_ver = (h + 5) - ((h + 5) % 6);
|
||||
const int16x8_t filters0 =
|
||||
vld1q_s16(coef[(phase_scaler + 0 * step_q4) & SUBPEL_MASK]);
|
||||
const int16x8_t filters1 =
|
||||
vld1q_s16(coef[(phase_scaler + 1 * step_q4) & SUBPEL_MASK]);
|
||||
const int16x8_t filters2 =
|
||||
vld1q_s16(coef[(phase_scaler + 2 * step_q4) & SUBPEL_MASK]);
|
||||
int x, y = height_hor;
|
||||
uint8_t *t = temp_buffer;
|
||||
uint8x8_t s[15], d[8];
|
||||
|
||||
assert(w && h);
|
||||
|
||||
src -= (SUBPEL_TAPS / 2 - 1) * src_stride + SUBPEL_TAPS / 2;
|
||||
d[6] = vdup_n_u8(0);
|
||||
d[7] = vdup_n_u8(0);
|
||||
|
||||
// horizontal 6x8
|
||||
do {
|
||||
load_u8_8x8(src + 1, src_stride, &s[0], &s[1], &s[2], &s[3], &s[4], &s[5],
|
||||
&s[6], &s[7]);
|
||||
transpose_u8_8x8(&s[0], &s[1], &s[2], &s[3], &s[4], &s[5], &s[6], &s[7]);
|
||||
x = width_hor;
|
||||
|
||||
do {
|
||||
src += 8;
|
||||
load_u8_8x8(src, src_stride, &s[7], &s[8], &s[9], &s[10], &s[11], &s[12],
|
||||
&s[13], &s[14]);
|
||||
transpose_u8_8x8(&s[7], &s[8], &s[9], &s[10], &s[11], &s[12], &s[13],
|
||||
&s[14]);
|
||||
|
||||
// 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
|
||||
d[0] = scale_filter_8(&s[0], filters0);
|
||||
d[1] = scale_filter_8(&s[(phase_scaler + 1 * step_q4) >> 4], filters1);
|
||||
d[2] = scale_filter_8(&s[(phase_scaler + 2 * step_q4) >> 4], filters2);
|
||||
d[3] = scale_filter_8(&s[4], filters0);
|
||||
d[4] =
|
||||
scale_filter_8(&s[4 + ((phase_scaler + 1 * step_q4) >> 4)], filters1);
|
||||
d[5] =
|
||||
scale_filter_8(&s[4 + ((phase_scaler + 2 * step_q4) >> 4)], filters2);
|
||||
|
||||
// 00 01 02 03 04 05 xx xx
|
||||
// 10 11 12 13 14 15 xx xx
|
||||
// 20 21 22 23 24 25 xx xx
|
||||
// 30 31 32 33 34 35 xx xx
|
||||
// 40 41 42 43 44 45 xx xx
|
||||
// 50 51 52 53 54 55 xx xx
|
||||
// 60 61 62 63 64 65 xx xx
|
||||
// 70 71 72 73 74 75 xx xx
|
||||
transpose_u8_8x8(&d[0], &d[1], &d[2], &d[3], &d[4], &d[5], &d[6], &d[7]);
|
||||
// store 2 extra pixels
|
||||
vst1_u8(t + 0 * stride_hor, d[0]);
|
||||
vst1_u8(t + 1 * stride_hor, d[1]);
|
||||
vst1_u8(t + 2 * stride_hor, d[2]);
|
||||
vst1_u8(t + 3 * stride_hor, d[3]);
|
||||
vst1_u8(t + 4 * stride_hor, d[4]);
|
||||
vst1_u8(t + 5 * stride_hor, d[5]);
|
||||
vst1_u8(t + 6 * stride_hor, d[6]);
|
||||
vst1_u8(t + 7 * stride_hor, d[7]);
|
||||
|
||||
s[0] = s[8];
|
||||
s[1] = s[9];
|
||||
s[2] = s[10];
|
||||
s[3] = s[11];
|
||||
s[4] = s[12];
|
||||
s[5] = s[13];
|
||||
s[6] = s[14];
|
||||
|
||||
t += 6;
|
||||
x -= 6;
|
||||
} while (x);
|
||||
src += 8 * src_stride - 4 * width_hor / 3;
|
||||
t += 7 * stride_hor + 2;
|
||||
y -= 8;
|
||||
} while (y);
|
||||
|
||||
// vertical 8x6
|
||||
x = width_ver;
|
||||
t = temp_buffer;
|
||||
do {
|
||||
load_u8_8x8(t, stride_hor, &s[0], &s[1], &s[2], &s[3], &s[4], &s[5], &s[6],
|
||||
&s[7]);
|
||||
t += 7 * stride_hor;
|
||||
y = height_ver;
|
||||
|
||||
do {
|
||||
load_u8_8x8(t, stride_hor, &s[7], &s[8], &s[9], &s[10], &s[11], &s[12],
|
||||
&s[13], &s[14]);
|
||||
t += 8 * stride_hor;
|
||||
|
||||
d[0] = scale_filter_8(&s[0], filters0);
|
||||
d[1] = scale_filter_8(&s[(phase_scaler + 1 * step_q4) >> 4], filters1);
|
||||
d[2] = scale_filter_8(&s[(phase_scaler + 2 * step_q4) >> 4], filters2);
|
||||
d[3] = scale_filter_8(&s[4], filters0);
|
||||
d[4] =
|
||||
scale_filter_8(&s[4 + ((phase_scaler + 1 * step_q4) >> 4)], filters1);
|
||||
d[5] =
|
||||
scale_filter_8(&s[4 + ((phase_scaler + 2 * step_q4) >> 4)], filters2);
|
||||
vst1_u8(dst + 0 * dst_stride, d[0]);
|
||||
vst1_u8(dst + 1 * dst_stride, d[1]);
|
||||
vst1_u8(dst + 2 * dst_stride, d[2]);
|
||||
vst1_u8(dst + 3 * dst_stride, d[3]);
|
||||
vst1_u8(dst + 4 * dst_stride, d[4]);
|
||||
vst1_u8(dst + 5 * dst_stride, d[5]);
|
||||
|
||||
s[0] = s[8];
|
||||
s[1] = s[9];
|
||||
s[2] = s[10];
|
||||
s[3] = s[11];
|
||||
s[4] = s[12];
|
||||
s[5] = s[13];
|
||||
s[6] = s[14];
|
||||
|
||||
dst += 6 * dst_stride;
|
||||
y -= 6;
|
||||
} while (y);
|
||||
t -= stride_hor * (4 * height_ver / 3 + 7);
|
||||
t += 8;
|
||||
dst -= height_ver * dst_stride;
|
||||
dst += 8;
|
||||
x -= 8;
|
||||
} while (x);
|
||||
}
|
||||
|
||||
void vp9_scale_and_extend_frame_neon(const YV12_BUFFER_CONFIG *src,
|
||||
YV12_BUFFER_CONFIG *dst,
|
||||
INTERP_FILTER filter_type,
|
||||
int phase_scaler) {
|
||||
const int src_w = src->y_crop_width;
|
||||
const int src_h = src->y_crop_height;
|
||||
const int dst_w = dst->y_crop_width;
|
||||
const int dst_h = dst->y_crop_height;
|
||||
const int dst_uv_w = dst_w / 2;
|
||||
const int dst_uv_h = dst_h / 2;
|
||||
int scaled = 0;
|
||||
|
||||
// phase_scaler is usually 0 or 8.
|
||||
assert(phase_scaler >= 0 && phase_scaler < 16);
|
||||
|
||||
if (2 * dst_w == src_w && 2 * dst_h == src_h) {
|
||||
// 2 to 1
|
||||
scaled = 1;
|
||||
if (phase_scaler == 0) {
|
||||
scale_plane_2_to_1_phase_0(src->y_buffer, src->y_stride, dst->y_buffer,
|
||||
dst->y_stride, dst_w, dst_h);
|
||||
scale_plane_2_to_1_phase_0(src->u_buffer, src->uv_stride, dst->u_buffer,
|
||||
dst->uv_stride, dst_uv_w, dst_uv_h);
|
||||
scale_plane_2_to_1_phase_0(src->v_buffer, src->uv_stride, dst->v_buffer,
|
||||
dst->uv_stride, dst_uv_w, dst_uv_h);
|
||||
} else if (filter_type == BILINEAR) {
|
||||
const int16_t c0 = vp9_filter_kernels[BILINEAR][phase_scaler][3];
|
||||
const int16_t c1 = vp9_filter_kernels[BILINEAR][phase_scaler][4];
|
||||
scale_plane_2_to_1_bilinear(src->y_buffer, src->y_stride, dst->y_buffer,
|
||||
dst->y_stride, dst_w, dst_h, c0, c1);
|
||||
scale_plane_2_to_1_bilinear(src->u_buffer, src->uv_stride, dst->u_buffer,
|
||||
dst->uv_stride, dst_uv_w, dst_uv_h, c0, c1);
|
||||
scale_plane_2_to_1_bilinear(src->v_buffer, src->uv_stride, dst->v_buffer,
|
||||
dst->uv_stride, dst_uv_w, dst_uv_h, c0, c1);
|
||||
} else {
|
||||
const int buffer_stride = (dst_w + 3) & ~3;
|
||||
const int buffer_height = (2 * dst_h + SUBPEL_TAPS - 2 + 7) & ~7;
|
||||
uint8_t *const temp_buffer =
|
||||
(uint8_t *)malloc(buffer_stride * buffer_height);
|
||||
if (temp_buffer) {
|
||||
scale_plane_2_to_1_general(
|
||||
src->y_buffer, src->y_stride, dst->y_buffer, dst->y_stride, dst_w,
|
||||
dst_h, vp9_filter_kernels[filter_type][phase_scaler], temp_buffer);
|
||||
scale_plane_2_to_1_general(
|
||||
src->u_buffer, src->uv_stride, dst->u_buffer, dst->uv_stride,
|
||||
dst_uv_w, dst_uv_h, vp9_filter_kernels[filter_type][phase_scaler],
|
||||
temp_buffer);
|
||||
scale_plane_2_to_1_general(
|
||||
src->v_buffer, src->uv_stride, dst->v_buffer, dst->uv_stride,
|
||||
dst_uv_w, dst_uv_h, vp9_filter_kernels[filter_type][phase_scaler],
|
||||
temp_buffer);
|
||||
free(temp_buffer);
|
||||
} else {
|
||||
scaled = 0;
|
||||
}
|
||||
}
|
||||
} else if (4 * dst_w == src_w && 4 * dst_h == src_h) {
|
||||
// 4 to 1
|
||||
scaled = 1;
|
||||
if (phase_scaler == 0) {
|
||||
scale_plane_4_to_1_phase_0(src->y_buffer, src->y_stride, dst->y_buffer,
|
||||
dst->y_stride, dst_w, dst_h);
|
||||
scale_plane_4_to_1_phase_0(src->u_buffer, src->uv_stride, dst->u_buffer,
|
||||
dst->uv_stride, dst_uv_w, dst_uv_h);
|
||||
scale_plane_4_to_1_phase_0(src->v_buffer, src->uv_stride, dst->v_buffer,
|
||||
dst->uv_stride, dst_uv_w, dst_uv_h);
|
||||
} else if (filter_type == BILINEAR) {
|
||||
const int16_t c0 = vp9_filter_kernels[BILINEAR][phase_scaler][3];
|
||||
const int16_t c1 = vp9_filter_kernels[BILINEAR][phase_scaler][4];
|
||||
scale_plane_4_to_1_bilinear(src->y_buffer, src->y_stride, dst->y_buffer,
|
||||
dst->y_stride, dst_w, dst_h, c0, c1);
|
||||
scale_plane_4_to_1_bilinear(src->u_buffer, src->uv_stride, dst->u_buffer,
|
||||
dst->uv_stride, dst_uv_w, dst_uv_h, c0, c1);
|
||||
scale_plane_4_to_1_bilinear(src->v_buffer, src->uv_stride, dst->v_buffer,
|
||||
dst->uv_stride, dst_uv_w, dst_uv_h, c0, c1);
|
||||
} else {
|
||||
const int buffer_stride = (dst_w + 1) & ~1;
|
||||
const int buffer_height = (4 * dst_h + SUBPEL_TAPS - 2 + 7) & ~7;
|
||||
uint8_t *const temp_buffer =
|
||||
(uint8_t *)malloc(buffer_stride * buffer_height);
|
||||
if (temp_buffer) {
|
||||
scale_plane_4_to_1_general(
|
||||
src->y_buffer, src->y_stride, dst->y_buffer, dst->y_stride, dst_w,
|
||||
dst_h, vp9_filter_kernels[filter_type][phase_scaler], temp_buffer);
|
||||
scale_plane_4_to_1_general(
|
||||
src->u_buffer, src->uv_stride, dst->u_buffer, dst->uv_stride,
|
||||
dst_uv_w, dst_uv_h, vp9_filter_kernels[filter_type][phase_scaler],
|
||||
temp_buffer);
|
||||
scale_plane_4_to_1_general(
|
||||
src->v_buffer, src->uv_stride, dst->v_buffer, dst->uv_stride,
|
||||
dst_uv_w, dst_uv_h, vp9_filter_kernels[filter_type][phase_scaler],
|
||||
temp_buffer);
|
||||
free(temp_buffer);
|
||||
} else {
|
||||
scaled = 0;
|
||||
}
|
||||
}
|
||||
} else if (4 * dst_w == 3 * src_w && 4 * dst_h == 3 * src_h) {
|
||||
// 4 to 3
|
||||
const int buffer_stride = (dst_w + 5) - ((dst_w + 5) % 6) + 2;
|
||||
const int buffer_height = (4 * dst_h / 3 + SUBPEL_TAPS - 1 + 7) & ~7;
|
||||
uint8_t *const temp_buffer =
|
||||
(uint8_t *)malloc(buffer_stride * buffer_height);
|
||||
if (temp_buffer) {
|
||||
scaled = 1;
|
||||
if (filter_type == BILINEAR) {
|
||||
scale_plane_4_to_3_bilinear(src->y_buffer, src->y_stride, dst->y_buffer,
|
||||
dst->y_stride, dst_w, dst_h, phase_scaler,
|
||||
temp_buffer);
|
||||
scale_plane_4_to_3_bilinear(src->u_buffer, src->uv_stride,
|
||||
dst->u_buffer, dst->uv_stride, dst_uv_w,
|
||||
dst_uv_h, phase_scaler, temp_buffer);
|
||||
scale_plane_4_to_3_bilinear(src->v_buffer, src->uv_stride,
|
||||
dst->v_buffer, dst->uv_stride, dst_uv_w,
|
||||
dst_uv_h, phase_scaler, temp_buffer);
|
||||
} else {
|
||||
scale_plane_4_to_3_general(
|
||||
src->y_buffer, src->y_stride, dst->y_buffer, dst->y_stride, dst_w,
|
||||
dst_h, vp9_filter_kernels[filter_type], phase_scaler, temp_buffer);
|
||||
scale_plane_4_to_3_general(src->u_buffer, src->uv_stride, dst->u_buffer,
|
||||
dst->uv_stride, dst_uv_w, dst_uv_h,
|
||||
vp9_filter_kernels[filter_type],
|
||||
phase_scaler, temp_buffer);
|
||||
scale_plane_4_to_3_general(src->v_buffer, src->uv_stride, dst->v_buffer,
|
||||
dst->uv_stride, dst_uv_w, dst_uv_h,
|
||||
vp9_filter_kernels[filter_type],
|
||||
phase_scaler, temp_buffer);
|
||||
}
|
||||
free(temp_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
if (scaled) {
|
||||
vpx_extend_frame_borders(dst);
|
||||
} else {
|
||||
// Call c version for all other scaling ratios.
|
||||
vp9_scale_and_extend_frame_c(src, dst, filter_type, phase_scaler);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,268 @@
|
||||
/*
|
||||
* 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 <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "./vpx_config.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"
|
||||
|
||||
#include "vpx_dsp/arm/idct_neon.h"
|
||||
#include "vpx_dsp/arm/mem_neon.h"
|
||||
#include "vpx_dsp/vpx_dsp_common.h"
|
||||
|
||||
static INLINE void calculate_dqcoeff_and_store(const int16x8_t qcoeff,
|
||||
const int16x8_t dequant,
|
||||
tran_low_t *dqcoeff) {
|
||||
const int32x4_t dqcoeff_0 =
|
||||
vmull_s16(vget_low_s16(qcoeff), vget_low_s16(dequant));
|
||||
const int32x4_t dqcoeff_1 =
|
||||
vmull_s16(vget_high_s16(qcoeff), vget_high_s16(dequant));
|
||||
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
vst1q_s32(dqcoeff, dqcoeff_0);
|
||||
vst1q_s32(dqcoeff + 4, dqcoeff_1);
|
||||
#else
|
||||
vst1q_s16(dqcoeff, vcombine_s16(vmovn_s32(dqcoeff_0), vmovn_s32(dqcoeff_1)));
|
||||
#endif // CONFIG_VP9_HIGHBITDEPTH
|
||||
}
|
||||
|
||||
void vp9_quantize_fp_neon(const tran_low_t *coeff_ptr, intptr_t count,
|
||||
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, const int16_t *scan,
|
||||
const int16_t *iscan) {
|
||||
// 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]);
|
||||
|
||||
(void)scan;
|
||||
(void)skip_block;
|
||||
assert(!skip_block);
|
||||
|
||||
// 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 = load_tran_low_to_s16q(coeff_ptr);
|
||||
const int16x8_t v_coeff_sign = vshrq_n_s16(v_coeff, 15);
|
||||
const int16x8_t v_abs = vabsq_s16(v_coeff);
|
||||
const int16x8_t v_tmp = vqaddq_s16(v_abs, v_round);
|
||||
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);
|
||||
calculate_dqcoeff_and_store(v_qcoeff, v_dequant, dqcoeff_ptr);
|
||||
v_eobmax_76543210 = vmaxq_s16(v_eobmax_76543210, v_nz_iscan);
|
||||
store_s16q_to_tran_low(qcoeff_ptr, v_qcoeff);
|
||||
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 = load_tran_low_to_s16q(coeff_ptr + i);
|
||||
const int16x8_t v_coeff_sign = vshrq_n_s16(v_coeff, 15);
|
||||
const int16x8_t v_abs = vabsq_s16(v_coeff);
|
||||
const int16x8_t v_tmp = vqaddq_s16(v_abs, v_round);
|
||||
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);
|
||||
calculate_dqcoeff_and_store(v_qcoeff, v_dequant, dqcoeff_ptr + i);
|
||||
v_eobmax_76543210 = vmaxq_s16(v_eobmax_76543210, v_nz_iscan);
|
||||
store_s16q_to_tran_low(qcoeff_ptr + i, v_qcoeff);
|
||||
}
|
||||
#ifdef __aarch64__
|
||||
*eob_ptr = vmaxvq_s16(v_eobmax_76543210);
|
||||
#else
|
||||
{
|
||||
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);
|
||||
}
|
||||
#endif // __aarch64__
|
||||
}
|
||||
|
||||
static INLINE int32x4_t extract_sign_bit(int32x4_t a) {
|
||||
return vreinterpretq_s32_u32(vshrq_n_u32(vreinterpretq_u32_s32(a), 31));
|
||||
}
|
||||
|
||||
void vp9_quantize_fp_32x32_neon(const tran_low_t *coeff_ptr, intptr_t count,
|
||||
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,
|
||||
const int16_t *scan, const int16_t *iscan) {
|
||||
const int16x8_t one = vdupq_n_s16(1);
|
||||
const int16x8_t neg_one = vdupq_n_s16(-1);
|
||||
|
||||
// ROUND_POWER_OF_TWO(round_ptr[], 1)
|
||||
const int16x8_t round = vrshrq_n_s16(vld1q_s16(round_ptr), 1);
|
||||
const int16x8_t quant = vld1q_s16(quant_ptr);
|
||||
const int16x4_t dequant = vld1_s16(dequant_ptr);
|
||||
// dequant >> 2 is used similar to zbin as a threshold.
|
||||
const int16x8_t dequant_thresh = vshrq_n_s16(vld1q_s16(dequant_ptr), 2);
|
||||
|
||||
// Process dc and the first seven ac coeffs.
|
||||
const uint16x8_t v_iscan =
|
||||
vreinterpretq_u16_s16(vaddq_s16(vld1q_s16(iscan), one));
|
||||
const int16x8_t coeff = load_tran_low_to_s16q(coeff_ptr);
|
||||
const int16x8_t coeff_sign = vshrq_n_s16(coeff, 15);
|
||||
const int16x8_t coeff_abs = vabsq_s16(coeff);
|
||||
const int16x8_t dequant_mask =
|
||||
vreinterpretq_s16_u16(vcgeq_s16(coeff_abs, dequant_thresh));
|
||||
|
||||
int16x8_t qcoeff = vqaddq_s16(coeff_abs, round);
|
||||
int32x4_t dqcoeff_0, dqcoeff_1;
|
||||
uint16x8_t eob_max;
|
||||
(void)scan;
|
||||
(void)count;
|
||||
(void)skip_block;
|
||||
assert(!skip_block);
|
||||
|
||||
// coeff * quant_ptr[]) >> 15
|
||||
qcoeff = vqdmulhq_s16(qcoeff, quant);
|
||||
|
||||
// Restore sign.
|
||||
qcoeff = veorq_s16(qcoeff, coeff_sign);
|
||||
qcoeff = vsubq_s16(qcoeff, coeff_sign);
|
||||
qcoeff = vandq_s16(qcoeff, dequant_mask);
|
||||
|
||||
// qcoeff * dequant[] / 2
|
||||
dqcoeff_0 = vmull_s16(vget_low_s16(qcoeff), dequant);
|
||||
dqcoeff_1 = vmull_n_s16(vget_high_s16(qcoeff), dequant_ptr[1]);
|
||||
|
||||
// Add 1 if negative to round towards zero because the C uses division.
|
||||
dqcoeff_0 = vaddq_s32(dqcoeff_0, extract_sign_bit(dqcoeff_0));
|
||||
dqcoeff_1 = vaddq_s32(dqcoeff_1, extract_sign_bit(dqcoeff_1));
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
vst1q_s32(dqcoeff_ptr, vshrq_n_s32(dqcoeff_0, 1));
|
||||
vst1q_s32(dqcoeff_ptr + 4, vshrq_n_s32(dqcoeff_1, 1));
|
||||
#else
|
||||
store_s16q_to_tran_low(dqcoeff_ptr, vcombine_s16(vshrn_n_s32(dqcoeff_0, 1),
|
||||
vshrn_n_s32(dqcoeff_1, 1)));
|
||||
#endif
|
||||
|
||||
eob_max = vandq_u16(vtstq_s16(qcoeff, neg_one), v_iscan);
|
||||
|
||||
store_s16q_to_tran_low(qcoeff_ptr, qcoeff);
|
||||
|
||||
iscan += 8;
|
||||
coeff_ptr += 8;
|
||||
qcoeff_ptr += 8;
|
||||
dqcoeff_ptr += 8;
|
||||
|
||||
{
|
||||
int i;
|
||||
const int16x8_t round = vrshrq_n_s16(vmovq_n_s16(round_ptr[1]), 1);
|
||||
const int16x8_t quant = vmovq_n_s16(quant_ptr[1]);
|
||||
const int16x8_t dequant_thresh =
|
||||
vshrq_n_s16(vmovq_n_s16(dequant_ptr[1]), 2);
|
||||
|
||||
// Process the rest of the ac coeffs.
|
||||
for (i = 8; i < 32 * 32; i += 8) {
|
||||
const uint16x8_t v_iscan =
|
||||
vreinterpretq_u16_s16(vaddq_s16(vld1q_s16(iscan), one));
|
||||
const int16x8_t coeff = load_tran_low_to_s16q(coeff_ptr);
|
||||
const int16x8_t coeff_sign = vshrq_n_s16(coeff, 15);
|
||||
const int16x8_t coeff_abs = vabsq_s16(coeff);
|
||||
const int16x8_t dequant_mask =
|
||||
vreinterpretq_s16_u16(vcgeq_s16(coeff_abs, dequant_thresh));
|
||||
|
||||
int16x8_t qcoeff = vqaddq_s16(coeff_abs, round);
|
||||
int32x4_t dqcoeff_0, dqcoeff_1;
|
||||
|
||||
qcoeff = vqdmulhq_s16(qcoeff, quant);
|
||||
qcoeff = veorq_s16(qcoeff, coeff_sign);
|
||||
qcoeff = vsubq_s16(qcoeff, coeff_sign);
|
||||
qcoeff = vandq_s16(qcoeff, dequant_mask);
|
||||
|
||||
dqcoeff_0 = vmull_n_s16(vget_low_s16(qcoeff), dequant_ptr[1]);
|
||||
dqcoeff_1 = vmull_n_s16(vget_high_s16(qcoeff), dequant_ptr[1]);
|
||||
|
||||
dqcoeff_0 = vaddq_s32(dqcoeff_0, extract_sign_bit(dqcoeff_0));
|
||||
dqcoeff_1 = vaddq_s32(dqcoeff_1, extract_sign_bit(dqcoeff_1));
|
||||
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
vst1q_s32(dqcoeff_ptr, vshrq_n_s32(dqcoeff_0, 1));
|
||||
vst1q_s32(dqcoeff_ptr + 4, vshrq_n_s32(dqcoeff_1, 1));
|
||||
#else
|
||||
store_s16q_to_tran_low(
|
||||
dqcoeff_ptr,
|
||||
vcombine_s16(vshrn_n_s32(dqcoeff_0, 1), vshrn_n_s32(dqcoeff_1, 1)));
|
||||
#endif
|
||||
|
||||
eob_max =
|
||||
vmaxq_u16(eob_max, vandq_u16(vtstq_s16(qcoeff, neg_one), v_iscan));
|
||||
|
||||
store_s16q_to_tran_low(qcoeff_ptr, qcoeff);
|
||||
|
||||
iscan += 8;
|
||||
coeff_ptr += 8;
|
||||
qcoeff_ptr += 8;
|
||||
dqcoeff_ptr += 8;
|
||||
}
|
||||
|
||||
#ifdef __aarch64__
|
||||
*eob_ptr = vmaxvq_u16(eob_max);
|
||||
#else
|
||||
{
|
||||
const uint16x4_t eob_max_0 =
|
||||
vmax_u16(vget_low_u16(eob_max), vget_high_u16(eob_max));
|
||||
const uint16x4_t eob_max_1 = vpmax_u16(eob_max_0, eob_max_0);
|
||||
const uint16x4_t eob_max_2 = vpmax_u16(eob_max_1, eob_max_1);
|
||||
vst1_lane_u16(eob_ptr, eob_max_2, 0);
|
||||
}
|
||||
#endif // __aarch64__
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* 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 "./vpx_config.h"
|
||||
#include "./vp9_rtcd.h"
|
||||
#include "vpx_dsp/mips/macros_msa.h"
|
||||
|
||||
#define BLOCK_ERROR_BLOCKSIZE_MSA(BSize) \
|
||||
static int64_t block_error_##BSize##size_msa( \
|
||||
const int16_t *coeff_ptr, const int16_t *dq_coeff_ptr, int64_t *ssz) { \
|
||||
int64_t err = 0; \
|
||||
uint32_t loop_cnt; \
|
||||
v8i16 coeff, dq_coeff, coeff_r_h, coeff_l_h; \
|
||||
v4i32 diff_r, diff_l, coeff_r_w, coeff_l_w; \
|
||||
v2i64 sq_coeff_r, sq_coeff_l; \
|
||||
v2i64 err0, err_dup0, err1, err_dup1; \
|
||||
\
|
||||
coeff = LD_SH(coeff_ptr); \
|
||||
dq_coeff = LD_SH(dq_coeff_ptr); \
|
||||
UNPCK_SH_SW(coeff, coeff_r_w, coeff_l_w); \
|
||||
ILVRL_H2_SH(coeff, dq_coeff, coeff_r_h, coeff_l_h); \
|
||||
HSUB_UH2_SW(coeff_r_h, coeff_l_h, diff_r, diff_l); \
|
||||
DOTP_SW2_SD(coeff_r_w, coeff_l_w, coeff_r_w, coeff_l_w, sq_coeff_r, \
|
||||
sq_coeff_l); \
|
||||
DOTP_SW2_SD(diff_r, diff_l, diff_r, diff_l, err0, err1); \
|
||||
\
|
||||
coeff = LD_SH(coeff_ptr + 8); \
|
||||
dq_coeff = LD_SH(dq_coeff_ptr + 8); \
|
||||
UNPCK_SH_SW(coeff, coeff_r_w, coeff_l_w); \
|
||||
ILVRL_H2_SH(coeff, dq_coeff, coeff_r_h, coeff_l_h); \
|
||||
HSUB_UH2_SW(coeff_r_h, coeff_l_h, diff_r, diff_l); \
|
||||
DPADD_SD2_SD(coeff_r_w, coeff_l_w, sq_coeff_r, sq_coeff_l); \
|
||||
DPADD_SD2_SD(diff_r, diff_l, err0, err1); \
|
||||
\
|
||||
coeff_ptr += 16; \
|
||||
dq_coeff_ptr += 16; \
|
||||
\
|
||||
for (loop_cnt = ((BSize >> 4) - 1); loop_cnt--;) { \
|
||||
coeff = LD_SH(coeff_ptr); \
|
||||
dq_coeff = LD_SH(dq_coeff_ptr); \
|
||||
UNPCK_SH_SW(coeff, coeff_r_w, coeff_l_w); \
|
||||
ILVRL_H2_SH(coeff, dq_coeff, coeff_r_h, coeff_l_h); \
|
||||
HSUB_UH2_SW(coeff_r_h, coeff_l_h, diff_r, diff_l); \
|
||||
DPADD_SD2_SD(coeff_r_w, coeff_l_w, sq_coeff_r, sq_coeff_l); \
|
||||
DPADD_SD2_SD(diff_r, diff_l, err0, err1); \
|
||||
\
|
||||
coeff = LD_SH(coeff_ptr + 8); \
|
||||
dq_coeff = LD_SH(dq_coeff_ptr + 8); \
|
||||
UNPCK_SH_SW(coeff, coeff_r_w, coeff_l_w); \
|
||||
ILVRL_H2_SH(coeff, dq_coeff, coeff_r_h, coeff_l_h); \
|
||||
HSUB_UH2_SW(coeff_r_h, coeff_l_h, diff_r, diff_l); \
|
||||
DPADD_SD2_SD(coeff_r_w, coeff_l_w, sq_coeff_r, sq_coeff_l); \
|
||||
DPADD_SD2_SD(diff_r, diff_l, err0, err1); \
|
||||
\
|
||||
coeff_ptr += 16; \
|
||||
dq_coeff_ptr += 16; \
|
||||
} \
|
||||
\
|
||||
err_dup0 = __msa_splati_d(sq_coeff_r, 1); \
|
||||
err_dup1 = __msa_splati_d(sq_coeff_l, 1); \
|
||||
sq_coeff_r += err_dup0; \
|
||||
sq_coeff_l += err_dup1; \
|
||||
*ssz = __msa_copy_s_d(sq_coeff_r, 0); \
|
||||
*ssz += __msa_copy_s_d(sq_coeff_l, 0); \
|
||||
\
|
||||
err_dup0 = __msa_splati_d(err0, 1); \
|
||||
err_dup1 = __msa_splati_d(err1, 1); \
|
||||
err0 += err_dup0; \
|
||||
err1 += err_dup1; \
|
||||
err = __msa_copy_s_d(err0, 0); \
|
||||
err += __msa_copy_s_d(err1, 0); \
|
||||
\
|
||||
return err; \
|
||||
}
|
||||
|
||||
#if !CONFIG_VP9_HIGHBITDEPTH
|
||||
BLOCK_ERROR_BLOCKSIZE_MSA(16);
|
||||
BLOCK_ERROR_BLOCKSIZE_MSA(64);
|
||||
BLOCK_ERROR_BLOCKSIZE_MSA(256);
|
||||
BLOCK_ERROR_BLOCKSIZE_MSA(1024);
|
||||
|
||||
int64_t vp9_block_error_msa(const tran_low_t *coeff_ptr,
|
||||
const tran_low_t *dq_coeff_ptr, intptr_t blk_size,
|
||||
int64_t *ssz) {
|
||||
int64_t err;
|
||||
const int16_t *coeff = (const int16_t *)coeff_ptr;
|
||||
const int16_t *dq_coeff = (const int16_t *)dq_coeff_ptr;
|
||||
|
||||
switch (blk_size) {
|
||||
case 16: err = block_error_16size_msa(coeff, dq_coeff, ssz); break;
|
||||
case 64: err = block_error_64size_msa(coeff, dq_coeff, ssz); break;
|
||||
case 256: err = block_error_256size_msa(coeff, dq_coeff, ssz); break;
|
||||
case 1024: err = block_error_1024size_msa(coeff, dq_coeff, ssz); break;
|
||||
default:
|
||||
err = vp9_block_error_c(coeff_ptr, dq_coeff_ptr, blk_size, ssz);
|
||||
break;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
#endif // !CONFIG_VP9_HIGHBITDEPTH
|
||||
@@ -0,0 +1,501 @@
|
||||
/*
|
||||
* 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 <assert.h>
|
||||
|
||||
#include "./vp9_rtcd.h"
|
||||
#include "vp9/common/vp9_enums.h"
|
||||
#include "vp9/encoder/mips/msa/vp9_fdct_msa.h"
|
||||
#include "vpx_dsp/mips/fwd_txfm_msa.h"
|
||||
|
||||
static void fadst16_cols_step1_msa(const int16_t *input, int32_t stride,
|
||||
const int32_t *const0, int16_t *int_buf) {
|
||||
v8i16 r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15;
|
||||
v8i16 tp0, tp1, tp2, tp3, g0, g1, g2, g3, g8, g9, g10, g11, h0, h1, h2, h3;
|
||||
v4i32 k0, k1, k2, k3;
|
||||
|
||||
/* load input data */
|
||||
r0 = LD_SH(input);
|
||||
r15 = LD_SH(input + 15 * stride);
|
||||
r7 = LD_SH(input + 7 * stride);
|
||||
r8 = LD_SH(input + 8 * stride);
|
||||
SLLI_4V(r0, r15, r7, r8, 2);
|
||||
|
||||
/* stage 1 */
|
||||
LD_SW2(const0, 4, k0, k1);
|
||||
LD_SW2(const0 + 8, 4, k2, k3);
|
||||
MADD_BF(r15, r0, r7, r8, k0, k1, k2, k3, g0, g1, g2, g3);
|
||||
|
||||
r3 = LD_SH(input + 3 * stride);
|
||||
r4 = LD_SH(input + 4 * stride);
|
||||
r11 = LD_SH(input + 11 * stride);
|
||||
r12 = LD_SH(input + 12 * stride);
|
||||
SLLI_4V(r3, r4, r11, r12, 2);
|
||||
|
||||
LD_SW2(const0 + 4 * 4, 4, k0, k1);
|
||||
LD_SW2(const0 + 4 * 6, 4, k2, k3);
|
||||
MADD_BF(r11, r4, r3, r12, k0, k1, k2, k3, g8, g9, g10, g11);
|
||||
|
||||
/* stage 2 */
|
||||
BUTTERFLY_4(g0, g2, g10, g8, tp0, tp2, tp3, tp1);
|
||||
ST_SH2(tp0, tp2, int_buf, 8);
|
||||
ST_SH2(tp1, tp3, int_buf + 4 * 8, 8);
|
||||
|
||||
LD_SW2(const0 + 4 * 8, 4, k0, k1);
|
||||
k2 = LD_SW(const0 + 4 * 10);
|
||||
MADD_BF(g1, g3, g9, g11, k0, k1, k2, k0, h0, h1, h2, h3);
|
||||
|
||||
ST_SH2(h0, h1, int_buf + 8 * 8, 8);
|
||||
ST_SH2(h3, h2, int_buf + 12 * 8, 8);
|
||||
|
||||
r9 = LD_SH(input + 9 * stride);
|
||||
r6 = LD_SH(input + 6 * stride);
|
||||
r1 = LD_SH(input + stride);
|
||||
r14 = LD_SH(input + 14 * stride);
|
||||
SLLI_4V(r9, r6, r1, r14, 2);
|
||||
|
||||
LD_SW2(const0 + 4 * 11, 4, k0, k1);
|
||||
LD_SW2(const0 + 4 * 13, 4, k2, k3);
|
||||
MADD_BF(r9, r6, r1, r14, k0, k1, k2, k3, g0, g1, g2, g3);
|
||||
|
||||
ST_SH2(g1, g3, int_buf + 3 * 8, 4 * 8);
|
||||
|
||||
r13 = LD_SH(input + 13 * stride);
|
||||
r2 = LD_SH(input + 2 * stride);
|
||||
r5 = LD_SH(input + 5 * stride);
|
||||
r10 = LD_SH(input + 10 * stride);
|
||||
SLLI_4V(r13, r2, r5, r10, 2);
|
||||
|
||||
LD_SW2(const0 + 4 * 15, 4, k0, k1);
|
||||
LD_SW2(const0 + 4 * 17, 4, k2, k3);
|
||||
MADD_BF(r13, r2, r5, r10, k0, k1, k2, k3, h0, h1, h2, h3);
|
||||
|
||||
ST_SH2(h1, h3, int_buf + 11 * 8, 4 * 8);
|
||||
|
||||
BUTTERFLY_4(h0, h2, g2, g0, tp0, tp1, tp2, tp3);
|
||||
ST_SH4(tp0, tp1, tp2, tp3, int_buf + 2 * 8, 4 * 8);
|
||||
}
|
||||
|
||||
static void fadst16_cols_step2_msa(int16_t *int_buf, const int32_t *const0,
|
||||
int16_t *out) {
|
||||
int16_t *out_ptr = out + 128;
|
||||
v8i16 tp0, tp1, tp2, tp3, g5, g7, g13, g15;
|
||||
v8i16 h0, h1, h2, h3, h4, h5, h6, h7, h10, h11;
|
||||
v8i16 out0, out1, out2, out3, out4, out5, out6, out7;
|
||||
v8i16 out8, out9, out10, out11, out12, out13, out14, out15;
|
||||
v4i32 k0, k1, k2, k3;
|
||||
|
||||
LD_SH2(int_buf + 3 * 8, 4 * 8, g13, g15);
|
||||
LD_SH2(int_buf + 11 * 8, 4 * 8, g5, g7);
|
||||
LD_SW2(const0 + 4 * 19, 4, k0, k1);
|
||||
k2 = LD_SW(const0 + 4 * 21);
|
||||
MADD_BF(g7, g5, g15, g13, k0, k1, k2, k0, h4, h5, h6, h7);
|
||||
|
||||
tp0 = LD_SH(int_buf + 4 * 8);
|
||||
tp1 = LD_SH(int_buf + 5 * 8);
|
||||
tp3 = LD_SH(int_buf + 10 * 8);
|
||||
tp2 = LD_SH(int_buf + 14 * 8);
|
||||
LD_SW2(const0 + 4 * 22, 4, k0, k1);
|
||||
k2 = LD_SW(const0 + 4 * 24);
|
||||
MADD_BF(tp0, tp1, tp2, tp3, k0, k1, k2, k0, out4, out6, out5, out7);
|
||||
out4 = -out4;
|
||||
ST_SH(out4, (out + 3 * 16));
|
||||
ST_SH(out5, (out_ptr + 4 * 16));
|
||||
|
||||
h1 = LD_SH(int_buf + 9 * 8);
|
||||
h3 = LD_SH(int_buf + 12 * 8);
|
||||
MADD_BF(h1, h3, h5, h7, k0, k1, k2, k0, out12, out14, out13, out15);
|
||||
out13 = -out13;
|
||||
ST_SH(out12, (out + 2 * 16));
|
||||
ST_SH(out13, (out_ptr + 5 * 16));
|
||||
|
||||
tp0 = LD_SH(int_buf);
|
||||
tp1 = LD_SH(int_buf + 8);
|
||||
tp2 = LD_SH(int_buf + 2 * 8);
|
||||
tp3 = LD_SH(int_buf + 6 * 8);
|
||||
|
||||
BUTTERFLY_4(tp0, tp1, tp3, tp2, out0, out1, h11, h10);
|
||||
out1 = -out1;
|
||||
ST_SH(out0, (out));
|
||||
ST_SH(out1, (out_ptr + 7 * 16));
|
||||
|
||||
h0 = LD_SH(int_buf + 8 * 8);
|
||||
h2 = LD_SH(int_buf + 13 * 8);
|
||||
|
||||
BUTTERFLY_4(h0, h2, h6, h4, out8, out9, out11, out10);
|
||||
out8 = -out8;
|
||||
ST_SH(out8, (out + 16));
|
||||
ST_SH(out9, (out_ptr + 6 * 16));
|
||||
|
||||
/* stage 4 */
|
||||
LD_SW2(const0 + 4 * 25, 4, k0, k1);
|
||||
LD_SW2(const0 + 4 * 27, 4, k2, k3);
|
||||
MADD_SHORT(h10, h11, k1, k2, out2, out3);
|
||||
ST_SH(out2, (out + 7 * 16));
|
||||
ST_SH(out3, (out_ptr));
|
||||
|
||||
MADD_SHORT(out6, out7, k0, k3, out6, out7);
|
||||
ST_SH(out6, (out + 4 * 16));
|
||||
ST_SH(out7, (out_ptr + 3 * 16));
|
||||
|
||||
MADD_SHORT(out10, out11, k0, k3, out10, out11);
|
||||
ST_SH(out10, (out + 6 * 16));
|
||||
ST_SH(out11, (out_ptr + 16));
|
||||
|
||||
MADD_SHORT(out14, out15, k1, k2, out14, out15);
|
||||
ST_SH(out14, (out + 5 * 16));
|
||||
ST_SH(out15, (out_ptr + 2 * 16));
|
||||
}
|
||||
|
||||
static void fadst16_transpose_postproc_msa(int16_t *input, int16_t *out) {
|
||||
v8i16 r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15;
|
||||
v8i16 l0, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, l14, l15;
|
||||
|
||||
/* load input data */
|
||||
LD_SH8(input, 16, l0, l1, l2, l3, l4, l5, l6, l7);
|
||||
TRANSPOSE8x8_SH_SH(l0, l1, l2, l3, l4, l5, l6, l7, r0, r1, r2, r3, r4, r5, r6,
|
||||
r7);
|
||||
FDCT_POSTPROC_2V_NEG_H(r0, r1);
|
||||
FDCT_POSTPROC_2V_NEG_H(r2, r3);
|
||||
FDCT_POSTPROC_2V_NEG_H(r4, r5);
|
||||
FDCT_POSTPROC_2V_NEG_H(r6, r7);
|
||||
ST_SH8(r0, r1, r2, r3, r4, r5, r6, r7, out, 8);
|
||||
out += 64;
|
||||
|
||||
LD_SH8(input + 8, 16, l8, l9, l10, l11, l12, l13, l14, l15);
|
||||
TRANSPOSE8x8_SH_SH(l8, l9, l10, l11, l12, l13, l14, l15, r8, r9, r10, r11,
|
||||
r12, r13, r14, r15);
|
||||
FDCT_POSTPROC_2V_NEG_H(r8, r9);
|
||||
FDCT_POSTPROC_2V_NEG_H(r10, r11);
|
||||
FDCT_POSTPROC_2V_NEG_H(r12, r13);
|
||||
FDCT_POSTPROC_2V_NEG_H(r14, r15);
|
||||
ST_SH8(r8, r9, r10, r11, r12, r13, r14, r15, out, 8);
|
||||
out += 64;
|
||||
|
||||
/* load input data */
|
||||
input += 128;
|
||||
LD_SH8(input, 16, l0, l1, l2, l3, l4, l5, l6, l7);
|
||||
TRANSPOSE8x8_SH_SH(l0, l1, l2, l3, l4, l5, l6, l7, r0, r1, r2, r3, r4, r5, r6,
|
||||
r7);
|
||||
FDCT_POSTPROC_2V_NEG_H(r0, r1);
|
||||
FDCT_POSTPROC_2V_NEG_H(r2, r3);
|
||||
FDCT_POSTPROC_2V_NEG_H(r4, r5);
|
||||
FDCT_POSTPROC_2V_NEG_H(r6, r7);
|
||||
ST_SH8(r0, r1, r2, r3, r4, r5, r6, r7, out, 8);
|
||||
out += 64;
|
||||
|
||||
LD_SH8(input + 8, 16, l8, l9, l10, l11, l12, l13, l14, l15);
|
||||
TRANSPOSE8x8_SH_SH(l8, l9, l10, l11, l12, l13, l14, l15, r8, r9, r10, r11,
|
||||
r12, r13, r14, r15);
|
||||
FDCT_POSTPROC_2V_NEG_H(r8, r9);
|
||||
FDCT_POSTPROC_2V_NEG_H(r10, r11);
|
||||
FDCT_POSTPROC_2V_NEG_H(r12, r13);
|
||||
FDCT_POSTPROC_2V_NEG_H(r14, r15);
|
||||
ST_SH8(r8, r9, r10, r11, r12, r13, r14, r15, out, 8);
|
||||
}
|
||||
|
||||
static void fadst16_rows_step1_msa(int16_t *input, const int32_t *const0,
|
||||
int16_t *int_buf) {
|
||||
v8i16 r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15;
|
||||
v8i16 tp0, tp1, tp2, tp3, g0, g1, g2, g3, g8, g9, g10, g11, h0, h1, h2, h3;
|
||||
v4i32 k0, k1, k2, k3;
|
||||
|
||||
/* load input data */
|
||||
r0 = LD_SH(input);
|
||||
r7 = LD_SH(input + 7 * 8);
|
||||
r8 = LD_SH(input + 8 * 8);
|
||||
r15 = LD_SH(input + 15 * 8);
|
||||
|
||||
/* stage 1 */
|
||||
LD_SW2(const0, 4, k0, k1);
|
||||
LD_SW2(const0 + 4 * 2, 4, k2, k3);
|
||||
MADD_BF(r15, r0, r7, r8, k0, k1, k2, k3, g0, g1, g2, g3);
|
||||
|
||||
r3 = LD_SH(input + 3 * 8);
|
||||
r4 = LD_SH(input + 4 * 8);
|
||||
r11 = LD_SH(input + 11 * 8);
|
||||
r12 = LD_SH(input + 12 * 8);
|
||||
|
||||
LD_SW2(const0 + 4 * 4, 4, k0, k1);
|
||||
LD_SW2(const0 + 4 * 6, 4, k2, k3);
|
||||
MADD_BF(r11, r4, r3, r12, k0, k1, k2, k3, g8, g9, g10, g11);
|
||||
|
||||
/* stage 2 */
|
||||
BUTTERFLY_4(g0, g2, g10, g8, tp0, tp2, tp3, tp1);
|
||||
ST_SH2(tp0, tp1, int_buf, 4 * 8);
|
||||
ST_SH2(tp2, tp3, int_buf + 8, 4 * 8);
|
||||
|
||||
LD_SW2(const0 + 4 * 8, 4, k0, k1);
|
||||
k2 = LD_SW(const0 + 4 * 10);
|
||||
MADD_BF(g1, g3, g9, g11, k0, k1, k2, k0, h0, h1, h2, h3);
|
||||
ST_SH2(h0, h3, int_buf + 8 * 8, 4 * 8);
|
||||
ST_SH2(h1, h2, int_buf + 9 * 8, 4 * 8);
|
||||
|
||||
r1 = LD_SH(input + 8);
|
||||
r6 = LD_SH(input + 6 * 8);
|
||||
r9 = LD_SH(input + 9 * 8);
|
||||
r14 = LD_SH(input + 14 * 8);
|
||||
|
||||
LD_SW2(const0 + 4 * 11, 4, k0, k1);
|
||||
LD_SW2(const0 + 4 * 13, 4, k2, k3);
|
||||
MADD_BF(r9, r6, r1, r14, k0, k1, k2, k3, g0, g1, g2, g3);
|
||||
ST_SH2(g1, g3, int_buf + 3 * 8, 4 * 8);
|
||||
|
||||
r2 = LD_SH(input + 2 * 8);
|
||||
r5 = LD_SH(input + 5 * 8);
|
||||
r10 = LD_SH(input + 10 * 8);
|
||||
r13 = LD_SH(input + 13 * 8);
|
||||
|
||||
LD_SW2(const0 + 4 * 15, 4, k0, k1);
|
||||
LD_SW2(const0 + 4 * 17, 4, k2, k3);
|
||||
MADD_BF(r13, r2, r5, r10, k0, k1, k2, k3, h0, h1, h2, h3);
|
||||
ST_SH2(h1, h3, int_buf + 11 * 8, 4 * 8);
|
||||
BUTTERFLY_4(h0, h2, g2, g0, tp0, tp1, tp2, tp3);
|
||||
ST_SH4(tp0, tp1, tp2, tp3, int_buf + 2 * 8, 4 * 8);
|
||||
}
|
||||
|
||||
static void fadst16_rows_step2_msa(int16_t *int_buf, const int32_t *const0,
|
||||
int16_t *out) {
|
||||
int16_t *out_ptr = out + 8;
|
||||
v8i16 tp0, tp1, tp2, tp3, g5, g7, g13, g15;
|
||||
v8i16 h0, h1, h2, h3, h4, h5, h6, h7, h10, h11;
|
||||
v8i16 out0, out1, out2, out3, out4, out5, out6, out7;
|
||||
v8i16 out8, out9, out10, out11, out12, out13, out14, out15;
|
||||
v4i32 k0, k1, k2, k3;
|
||||
|
||||
g13 = LD_SH(int_buf + 3 * 8);
|
||||
g15 = LD_SH(int_buf + 7 * 8);
|
||||
g5 = LD_SH(int_buf + 11 * 8);
|
||||
g7 = LD_SH(int_buf + 15 * 8);
|
||||
|
||||
LD_SW2(const0 + 4 * 19, 4, k0, k1);
|
||||
k2 = LD_SW(const0 + 4 * 21);
|
||||
MADD_BF(g7, g5, g15, g13, k0, k1, k2, k0, h4, h5, h6, h7);
|
||||
|
||||
tp0 = LD_SH(int_buf + 4 * 8);
|
||||
tp1 = LD_SH(int_buf + 5 * 8);
|
||||
tp3 = LD_SH(int_buf + 10 * 8);
|
||||
tp2 = LD_SH(int_buf + 14 * 8);
|
||||
|
||||
LD_SW2(const0 + 4 * 22, 4, k0, k1);
|
||||
k2 = LD_SW(const0 + 4 * 24);
|
||||
MADD_BF(tp0, tp1, tp2, tp3, k0, k1, k2, k0, out4, out6, out5, out7);
|
||||
out4 = -out4;
|
||||
ST_SH(out4, (out + 3 * 16));
|
||||
ST_SH(out5, (out_ptr + 4 * 16));
|
||||
|
||||
h1 = LD_SH(int_buf + 9 * 8);
|
||||
h3 = LD_SH(int_buf + 12 * 8);
|
||||
MADD_BF(h1, h3, h5, h7, k0, k1, k2, k0, out12, out14, out13, out15);
|
||||
out13 = -out13;
|
||||
ST_SH(out12, (out + 2 * 16));
|
||||
ST_SH(out13, (out_ptr + 5 * 16));
|
||||
|
||||
tp0 = LD_SH(int_buf);
|
||||
tp1 = LD_SH(int_buf + 8);
|
||||
tp2 = LD_SH(int_buf + 2 * 8);
|
||||
tp3 = LD_SH(int_buf + 6 * 8);
|
||||
|
||||
BUTTERFLY_4(tp0, tp1, tp3, tp2, out0, out1, h11, h10);
|
||||
out1 = -out1;
|
||||
ST_SH(out0, (out));
|
||||
ST_SH(out1, (out_ptr + 7 * 16));
|
||||
|
||||
h0 = LD_SH(int_buf + 8 * 8);
|
||||
h2 = LD_SH(int_buf + 13 * 8);
|
||||
BUTTERFLY_4(h0, h2, h6, h4, out8, out9, out11, out10);
|
||||
out8 = -out8;
|
||||
ST_SH(out8, (out + 16));
|
||||
ST_SH(out9, (out_ptr + 6 * 16));
|
||||
|
||||
/* stage 4 */
|
||||
LD_SW2(const0 + 4 * 25, 4, k0, k1);
|
||||
LD_SW2(const0 + 4 * 27, 4, k2, k3);
|
||||
MADD_SHORT(h10, h11, k1, k2, out2, out3);
|
||||
ST_SH(out2, (out + 7 * 16));
|
||||
ST_SH(out3, (out_ptr));
|
||||
|
||||
MADD_SHORT(out6, out7, k0, k3, out6, out7);
|
||||
ST_SH(out6, (out + 4 * 16));
|
||||
ST_SH(out7, (out_ptr + 3 * 16));
|
||||
|
||||
MADD_SHORT(out10, out11, k0, k3, out10, out11);
|
||||
ST_SH(out10, (out + 6 * 16));
|
||||
ST_SH(out11, (out_ptr + 16));
|
||||
|
||||
MADD_SHORT(out14, out15, k1, k2, out14, out15);
|
||||
ST_SH(out14, (out + 5 * 16));
|
||||
ST_SH(out15, (out_ptr + 2 * 16));
|
||||
}
|
||||
|
||||
static void fadst16_transpose_msa(int16_t *input, int16_t *out) {
|
||||
v8i16 r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15;
|
||||
v8i16 l0, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, l14, l15;
|
||||
|
||||
/* load input data */
|
||||
LD_SH16(input, 8, l0, l8, l1, l9, l2, l10, l3, l11, l4, l12, l5, l13, l6, l14,
|
||||
l7, l15);
|
||||
TRANSPOSE8x8_SH_SH(l0, l1, l2, l3, l4, l5, l6, l7, r0, r1, r2, r3, r4, r5, r6,
|
||||
r7);
|
||||
TRANSPOSE8x8_SH_SH(l8, l9, l10, l11, l12, l13, l14, l15, r8, r9, r10, r11,
|
||||
r12, r13, r14, r15);
|
||||
ST_SH8(r0, r8, r1, r9, r2, r10, r3, r11, out, 8);
|
||||
ST_SH8(r4, r12, r5, r13, r6, r14, r7, r15, (out + 64), 8);
|
||||
out += 16 * 8;
|
||||
|
||||
/* load input data */
|
||||
input += 128;
|
||||
LD_SH16(input, 8, l0, l8, l1, l9, l2, l10, l3, l11, l4, l12, l5, l13, l6, l14,
|
||||
l7, l15);
|
||||
TRANSPOSE8x8_SH_SH(l0, l1, l2, l3, l4, l5, l6, l7, r0, r1, r2, r3, r4, r5, r6,
|
||||
r7);
|
||||
TRANSPOSE8x8_SH_SH(l8, l9, l10, l11, l12, l13, l14, l15, r8, r9, r10, r11,
|
||||
r12, r13, r14, r15);
|
||||
ST_SH8(r0, r8, r1, r9, r2, r10, r3, r11, out, 8);
|
||||
ST_SH8(r4, r12, r5, r13, r6, r14, r7, r15, (out + 64), 8);
|
||||
}
|
||||
|
||||
static void postproc_fdct16x8_1d_row(int16_t *intermediate, int16_t *output) {
|
||||
int16_t *temp = intermediate;
|
||||
int16_t *out = output;
|
||||
v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
|
||||
v8i16 in0, in1, in2, in3, in4, in5, in6, in7, in8, in9, in10, in11;
|
||||
v8i16 in12, in13, in14, in15;
|
||||
|
||||
LD_SH8(temp, 16, in0, in1, in2, in3, in4, in5, in6, in7);
|
||||
temp = intermediate + 8;
|
||||
LD_SH8(temp, 16, in8, in9, in10, in11, in12, in13, in14, in15);
|
||||
TRANSPOSE8x8_SH_SH(in0, in1, in2, in3, in4, in5, in6, in7, in0, in1, in2, in3,
|
||||
in4, in5, in6, in7);
|
||||
TRANSPOSE8x8_SH_SH(in8, in9, in10, in11, in12, in13, in14, in15, in8, in9,
|
||||
in10, in11, in12, in13, in14, in15);
|
||||
FDCT_POSTPROC_2V_NEG_H(in0, in1);
|
||||
FDCT_POSTPROC_2V_NEG_H(in2, in3);
|
||||
FDCT_POSTPROC_2V_NEG_H(in4, in5);
|
||||
FDCT_POSTPROC_2V_NEG_H(in6, in7);
|
||||
FDCT_POSTPROC_2V_NEG_H(in8, in9);
|
||||
FDCT_POSTPROC_2V_NEG_H(in10, in11);
|
||||
FDCT_POSTPROC_2V_NEG_H(in12, in13);
|
||||
FDCT_POSTPROC_2V_NEG_H(in14, in15);
|
||||
BUTTERFLY_16(in0, in1, in2, in3, in4, in5, in6, in7, in8, in9, in10, in11,
|
||||
in12, in13, in14, in15, tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6,
|
||||
tmp7, in8, in9, in10, in11, in12, in13, in14, in15);
|
||||
temp = intermediate;
|
||||
ST_SH8(in8, in9, in10, in11, in12, in13, in14, in15, temp, 16);
|
||||
FDCT8x16_EVEN(tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp0, tmp1,
|
||||
tmp2, tmp3, tmp4, tmp5, tmp6, tmp7);
|
||||
temp = intermediate;
|
||||
LD_SH8(temp, 16, in8, in9, in10, in11, in12, in13, in14, in15);
|
||||
FDCT8x16_ODD(in8, in9, in10, in11, in12, in13, in14, in15, in0, in1, in2, in3,
|
||||
in4, in5, in6, in7);
|
||||
TRANSPOSE8x8_SH_SH(tmp0, in0, tmp1, in1, tmp2, in2, tmp3, in3, tmp0, in0,
|
||||
tmp1, in1, tmp2, in2, tmp3, in3);
|
||||
ST_SH8(tmp0, in0, tmp1, in1, tmp2, in2, tmp3, in3, out, 16);
|
||||
TRANSPOSE8x8_SH_SH(tmp4, in4, tmp5, in5, tmp6, in6, tmp7, in7, tmp4, in4,
|
||||
tmp5, in5, tmp6, in6, tmp7, in7);
|
||||
out = output + 8;
|
||||
ST_SH8(tmp4, in4, tmp5, in5, tmp6, in6, tmp7, in7, out, 16);
|
||||
}
|
||||
|
||||
void vp9_fht16x16_msa(const int16_t *input, int16_t *output, int32_t stride,
|
||||
int32_t tx_type) {
|
||||
DECLARE_ALIGNED(32, int16_t, tmp[256]);
|
||||
DECLARE_ALIGNED(32, int16_t, trans_buf[256]);
|
||||
DECLARE_ALIGNED(32, int16_t, tmp_buf[128]);
|
||||
int32_t i;
|
||||
int16_t *ptmpbuf = &tmp_buf[0];
|
||||
int16_t *trans = &trans_buf[0];
|
||||
const int32_t const_arr[29 * 4] = {
|
||||
52707308, 52707308, 52707308, 52707308, -1072430300,
|
||||
-1072430300, -1072430300, -1072430300, 795618043, 795618043,
|
||||
795618043, 795618043, -721080468, -721080468, -721080468,
|
||||
-721080468, 459094491, 459094491, 459094491, 459094491,
|
||||
-970646691, -970646691, -970646691, -970646691, 1010963856,
|
||||
1010963856, 1010963856, 1010963856, -361743294, -361743294,
|
||||
-361743294, -361743294, 209469125, 209469125, 209469125,
|
||||
209469125, -1053094788, -1053094788, -1053094788, -1053094788,
|
||||
1053160324, 1053160324, 1053160324, 1053160324, 639644520,
|
||||
639644520, 639644520, 639644520, -862444000, -862444000,
|
||||
-862444000, -862444000, 1062144356, 1062144356, 1062144356,
|
||||
1062144356, -157532337, -157532337, -157532337, -157532337,
|
||||
260914709, 260914709, 260914709, 260914709, -1041559667,
|
||||
-1041559667, -1041559667, -1041559667, 920985831, 920985831,
|
||||
920985831, 920985831, -551995675, -551995675, -551995675,
|
||||
-551995675, 596522295, 596522295, 596522295, 596522295,
|
||||
892853362, 892853362, 892853362, 892853362, -892787826,
|
||||
-892787826, -892787826, -892787826, 410925857, 410925857,
|
||||
410925857, 410925857, -992012162, -992012162, -992012162,
|
||||
-992012162, 992077698, 992077698, 992077698, 992077698,
|
||||
759246145, 759246145, 759246145, 759246145, -759180609,
|
||||
-759180609, -759180609, -759180609, -759222975, -759222975,
|
||||
-759222975, -759222975, 759288511, 759288511, 759288511,
|
||||
759288511
|
||||
};
|
||||
|
||||
switch (tx_type) {
|
||||
case DCT_DCT:
|
||||
/* column transform */
|
||||
for (i = 0; i < 2; ++i) {
|
||||
fdct8x16_1d_column(input + 8 * i, tmp + 8 * i, stride);
|
||||
}
|
||||
|
||||
/* row transform */
|
||||
for (i = 0; i < 2; ++i) {
|
||||
fdct16x8_1d_row(tmp + (128 * i), output + (128 * i));
|
||||
}
|
||||
break;
|
||||
case ADST_DCT:
|
||||
/* column transform */
|
||||
for (i = 0; i < 2; ++i) {
|
||||
fadst16_cols_step1_msa(input + (i << 3), stride, const_arr, ptmpbuf);
|
||||
fadst16_cols_step2_msa(ptmpbuf, const_arr, tmp + (i << 3));
|
||||
}
|
||||
|
||||
/* row transform */
|
||||
for (i = 0; i < 2; ++i) {
|
||||
postproc_fdct16x8_1d_row(tmp + (128 * i), output + (128 * i));
|
||||
}
|
||||
break;
|
||||
case DCT_ADST:
|
||||
/* column transform */
|
||||
for (i = 0; i < 2; ++i) {
|
||||
fdct8x16_1d_column(input + 8 * i, tmp + 8 * i, stride);
|
||||
}
|
||||
|
||||
fadst16_transpose_postproc_msa(tmp, trans);
|
||||
|
||||
/* row transform */
|
||||
for (i = 0; i < 2; ++i) {
|
||||
fadst16_rows_step1_msa(trans + (i << 7), const_arr, ptmpbuf);
|
||||
fadst16_rows_step2_msa(ptmpbuf, const_arr, tmp + (i << 7));
|
||||
}
|
||||
|
||||
fadst16_transpose_msa(tmp, output);
|
||||
break;
|
||||
case ADST_ADST:
|
||||
/* column transform */
|
||||
for (i = 0; i < 2; ++i) {
|
||||
fadst16_cols_step1_msa(input + (i << 3), stride, const_arr, ptmpbuf);
|
||||
fadst16_cols_step2_msa(ptmpbuf, const_arr, tmp + (i << 3));
|
||||
}
|
||||
|
||||
fadst16_transpose_postproc_msa(tmp, trans);
|
||||
|
||||
/* row transform */
|
||||
for (i = 0; i < 2; ++i) {
|
||||
fadst16_rows_step1_msa(trans + (i << 7), const_arr, ptmpbuf);
|
||||
fadst16_rows_step2_msa(ptmpbuf, const_arr, tmp + (i << 7));
|
||||
}
|
||||
|
||||
fadst16_transpose_msa(tmp, output);
|
||||
break;
|
||||
default: assert(0); break;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* 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 <assert.h>
|
||||
|
||||
#include "./vp9_rtcd.h"
|
||||
#include "vp9/common/vp9_enums.h"
|
||||
#include "vp9/encoder/mips/msa/vp9_fdct_msa.h"
|
||||
|
||||
void vp9_fwht4x4_msa(const int16_t *input, int16_t *output,
|
||||
int32_t src_stride) {
|
||||
v8i16 in0, in1, in2, in3, in4;
|
||||
|
||||
LD_SH4(input, src_stride, in0, in1, in2, in3);
|
||||
|
||||
in0 += in1;
|
||||
in3 -= in2;
|
||||
in4 = (in0 - in3) >> 1;
|
||||
SUB2(in4, in1, in4, in2, in1, in2);
|
||||
in0 -= in2;
|
||||
in3 += in1;
|
||||
|
||||
TRANSPOSE4x4_SH_SH(in0, in2, in3, in1, in0, in2, in3, in1);
|
||||
|
||||
in0 += in2;
|
||||
in1 -= in3;
|
||||
in4 = (in0 - in1) >> 1;
|
||||
SUB2(in4, in2, in4, in3, in2, in3);
|
||||
in0 -= in3;
|
||||
in1 += in2;
|
||||
|
||||
SLLI_4V(in0, in1, in2, in3, 2);
|
||||
|
||||
TRANSPOSE4x4_SH_SH(in0, in3, in1, in2, in0, in3, in1, in2);
|
||||
|
||||
ST4x2_UB(in0, output, 4);
|
||||
ST4x2_UB(in3, output + 4, 4);
|
||||
ST4x2_UB(in1, output + 8, 4);
|
||||
ST4x2_UB(in2, output + 12, 4);
|
||||
}
|
||||
|
||||
void vp9_fht4x4_msa(const int16_t *input, int16_t *output, int32_t stride,
|
||||
int32_t tx_type) {
|
||||
v8i16 in0, in1, in2, in3;
|
||||
|
||||
LD_SH4(input, stride, in0, in1, in2, in3);
|
||||
|
||||
/* fdct4 pre-process */
|
||||
{
|
||||
v8i16 temp, mask;
|
||||
v16i8 zero = { 0 };
|
||||
v16i8 one = __msa_ldi_b(1);
|
||||
|
||||
mask = (v8i16)__msa_sldi_b(zero, one, 15);
|
||||
SLLI_4V(in0, in1, in2, in3, 4);
|
||||
temp = __msa_ceqi_h(in0, 0);
|
||||
temp = (v8i16)__msa_xori_b((v16u8)temp, 255);
|
||||
temp = mask & temp;
|
||||
in0 += temp;
|
||||
}
|
||||
|
||||
switch (tx_type) {
|
||||
case DCT_DCT:
|
||||
VP9_FDCT4(in0, in1, in2, in3, in0, in1, in2, in3);
|
||||
TRANSPOSE4x4_SH_SH(in0, in1, in2, in3, in0, in1, in2, in3);
|
||||
VP9_FDCT4(in0, in1, in2, in3, in0, in1, in2, in3);
|
||||
break;
|
||||
case ADST_DCT:
|
||||
VP9_FADST4(in0, in1, in2, in3, in0, in1, in2, in3);
|
||||
TRANSPOSE4x4_SH_SH(in0, in1, in2, in3, in0, in1, in2, in3);
|
||||
VP9_FDCT4(in0, in1, in2, in3, in0, in1, in2, in3);
|
||||
break;
|
||||
case DCT_ADST:
|
||||
VP9_FDCT4(in0, in1, in2, in3, in0, in1, in2, in3);
|
||||
TRANSPOSE4x4_SH_SH(in0, in1, in2, in3, in0, in1, in2, in3);
|
||||
VP9_FADST4(in0, in1, in2, in3, in0, in1, in2, in3);
|
||||
break;
|
||||
case ADST_ADST:
|
||||
VP9_FADST4(in0, in1, in2, in3, in0, in1, in2, in3);
|
||||
TRANSPOSE4x4_SH_SH(in0, in1, in2, in3, in0, in1, in2, in3);
|
||||
VP9_FADST4(in0, in1, in2, in3, in0, in1, in2, in3);
|
||||
break;
|
||||
default: assert(0); break;
|
||||
}
|
||||
|
||||
TRANSPOSE4x4_SH_SH(in0, in1, in2, in3, in0, in1, in2, in3);
|
||||
ADD4(in0, 1, in1, 1, in2, 1, in3, 1, in0, in1, in2, in3);
|
||||
SRA_4V(in0, in1, in2, in3, 2);
|
||||
PCKEV_D2_SH(in1, in0, in3, in2, in0, in2);
|
||||
ST_SH2(in0, in2, output, 8);
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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 <assert.h>
|
||||
|
||||
#include "./vp9_rtcd.h"
|
||||
#include "vp9/common/vp9_enums.h"
|
||||
#include "vp9/encoder/mips/msa/vp9_fdct_msa.h"
|
||||
|
||||
void vp9_fht8x8_msa(const int16_t *input, int16_t *output, int32_t stride,
|
||||
int32_t tx_type) {
|
||||
v8i16 in0, in1, in2, in3, in4, in5, in6, in7;
|
||||
|
||||
LD_SH8(input, stride, in0, in1, in2, in3, in4, in5, in6, in7);
|
||||
SLLI_4V(in0, in1, in2, in3, 2);
|
||||
SLLI_4V(in4, in5, in6, in7, 2);
|
||||
|
||||
switch (tx_type) {
|
||||
case DCT_DCT:
|
||||
VP9_FDCT8(in0, in1, in2, in3, in4, in5, in6, in7, in0, in1, in2, in3, in4,
|
||||
in5, in6, in7);
|
||||
TRANSPOSE8x8_SH_SH(in0, in1, in2, in3, in4, in5, in6, in7, in0, in1, in2,
|
||||
in3, in4, in5, in6, in7);
|
||||
VP9_FDCT8(in0, in1, in2, in3, in4, in5, in6, in7, in0, in1, in2, in3, in4,
|
||||
in5, in6, in7);
|
||||
break;
|
||||
case ADST_DCT:
|
||||
VP9_ADST8(in0, in1, in2, in3, in4, in5, in6, in7, in0, in1, in2, in3, in4,
|
||||
in5, in6, in7);
|
||||
TRANSPOSE8x8_SH_SH(in0, in1, in2, in3, in4, in5, in6, in7, in0, in1, in2,
|
||||
in3, in4, in5, in6, in7);
|
||||
VP9_FDCT8(in0, in1, in2, in3, in4, in5, in6, in7, in0, in1, in2, in3, in4,
|
||||
in5, in6, in7);
|
||||
break;
|
||||
case DCT_ADST:
|
||||
VP9_FDCT8(in0, in1, in2, in3, in4, in5, in6, in7, in0, in1, in2, in3, in4,
|
||||
in5, in6, in7);
|
||||
TRANSPOSE8x8_SH_SH(in0, in1, in2, in3, in4, in5, in6, in7, in0, in1, in2,
|
||||
in3, in4, in5, in6, in7);
|
||||
VP9_ADST8(in0, in1, in2, in3, in4, in5, in6, in7, in0, in1, in2, in3, in4,
|
||||
in5, in6, in7);
|
||||
break;
|
||||
case ADST_ADST:
|
||||
VP9_ADST8(in0, in1, in2, in3, in4, in5, in6, in7, in0, in1, in2, in3, in4,
|
||||
in5, in6, in7);
|
||||
TRANSPOSE8x8_SH_SH(in0, in1, in2, in3, in4, in5, in6, in7, in0, in1, in2,
|
||||
in3, in4, in5, in6, in7);
|
||||
VP9_ADST8(in0, in1, in2, in3, in4, in5, in6, in7, in0, in1, in2, in3, in4,
|
||||
in5, in6, in7);
|
||||
break;
|
||||
default: assert(0); break;
|
||||
}
|
||||
|
||||
TRANSPOSE8x8_SH_SH(in0, in1, in2, in3, in4, in5, in6, in7, in0, in1, in2, in3,
|
||||
in4, in5, in6, in7);
|
||||
SRLI_AVE_S_4V_H(in0, in1, in2, in3, in4, in5, in6, in7);
|
||||
ST_SH8(in0, in1, in2, in3, in4, in5, in6, in7, output, 8);
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* 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 VPX_VP9_ENCODER_MIPS_MSA_VP9_FDCT_MSA_H_
|
||||
#define VPX_VP9_ENCODER_MIPS_MSA_VP9_FDCT_MSA_H_
|
||||
|
||||
#include "vpx_dsp/mips/fwd_txfm_msa.h"
|
||||
#include "vpx_dsp/mips/txfm_macros_msa.h"
|
||||
#include "vpx_ports/mem.h"
|
||||
|
||||
#define VP9_ADST8(in0, in1, in2, in3, in4, in5, in6, in7, out0, out1, out2, \
|
||||
out3, out4, out5, out6, out7) \
|
||||
{ \
|
||||
v8i16 cnst0_m, cnst1_m, cnst2_m, cnst3_m, cnst4_m; \
|
||||
v8i16 vec0_m, vec1_m, vec2_m, vec3_m, s0_m, s1_m; \
|
||||
v8i16 coeff0_m = { cospi_2_64, cospi_6_64, cospi_10_64, cospi_14_64, \
|
||||
cospi_18_64, cospi_22_64, cospi_26_64, cospi_30_64 }; \
|
||||
v8i16 coeff1_m = { cospi_8_64, -cospi_8_64, cospi_16_64, -cospi_16_64, \
|
||||
cospi_24_64, -cospi_24_64, 0, 0 }; \
|
||||
\
|
||||
SPLATI_H2_SH(coeff0_m, 0, 7, cnst0_m, cnst1_m); \
|
||||
cnst2_m = -cnst0_m; \
|
||||
ILVEV_H2_SH(cnst0_m, cnst1_m, cnst1_m, cnst2_m, cnst0_m, cnst1_m); \
|
||||
SPLATI_H2_SH(coeff0_m, 4, 3, cnst2_m, cnst3_m); \
|
||||
cnst4_m = -cnst2_m; \
|
||||
ILVEV_H2_SH(cnst2_m, cnst3_m, cnst3_m, cnst4_m, cnst2_m, cnst3_m); \
|
||||
\
|
||||
ILVRL_H2_SH(in0, in7, vec1_m, vec0_m); \
|
||||
ILVRL_H2_SH(in4, in3, vec3_m, vec2_m); \
|
||||
DOT_ADD_SUB_SRARI_PCK(vec0_m, vec1_m, vec2_m, vec3_m, cnst0_m, cnst1_m, \
|
||||
cnst2_m, cnst3_m, in7, in0, in4, in3); \
|
||||
\
|
||||
SPLATI_H2_SH(coeff0_m, 2, 5, cnst0_m, cnst1_m); \
|
||||
cnst2_m = -cnst0_m; \
|
||||
ILVEV_H2_SH(cnst0_m, cnst1_m, cnst1_m, cnst2_m, cnst0_m, cnst1_m); \
|
||||
SPLATI_H2_SH(coeff0_m, 6, 1, cnst2_m, cnst3_m); \
|
||||
cnst4_m = -cnst2_m; \
|
||||
ILVEV_H2_SH(cnst2_m, cnst3_m, cnst3_m, cnst4_m, cnst2_m, cnst3_m); \
|
||||
\
|
||||
ILVRL_H2_SH(in2, in5, vec1_m, vec0_m); \
|
||||
ILVRL_H2_SH(in6, in1, vec3_m, vec2_m); \
|
||||
\
|
||||
DOT_ADD_SUB_SRARI_PCK(vec0_m, vec1_m, vec2_m, vec3_m, cnst0_m, cnst1_m, \
|
||||
cnst2_m, cnst3_m, in5, in2, in6, in1); \
|
||||
BUTTERFLY_4(in7, in0, in2, in5, s1_m, s0_m, in2, in5); \
|
||||
out7 = -s0_m; \
|
||||
out0 = s1_m; \
|
||||
\
|
||||
SPLATI_H4_SH(coeff1_m, 0, 4, 1, 5, cnst0_m, cnst1_m, cnst2_m, cnst3_m); \
|
||||
\
|
||||
ILVEV_H2_SH(cnst3_m, cnst0_m, cnst1_m, cnst2_m, cnst3_m, cnst2_m); \
|
||||
cnst0_m = __msa_ilvev_h(cnst1_m, cnst0_m); \
|
||||
cnst1_m = cnst0_m; \
|
||||
\
|
||||
ILVRL_H2_SH(in4, in3, vec1_m, vec0_m); \
|
||||
ILVRL_H2_SH(in6, in1, vec3_m, vec2_m); \
|
||||
DOT_ADD_SUB_SRARI_PCK(vec0_m, vec1_m, vec2_m, vec3_m, cnst0_m, cnst2_m, \
|
||||
cnst3_m, cnst1_m, out1, out6, s0_m, s1_m); \
|
||||
\
|
||||
SPLATI_H2_SH(coeff1_m, 2, 3, cnst0_m, cnst1_m); \
|
||||
cnst1_m = __msa_ilvev_h(cnst1_m, cnst0_m); \
|
||||
\
|
||||
ILVRL_H2_SH(in2, in5, vec1_m, vec0_m); \
|
||||
ILVRL_H2_SH(s0_m, s1_m, vec3_m, vec2_m); \
|
||||
out3 = DOT_SHIFT_RIGHT_PCK_H(vec0_m, vec1_m, cnst0_m); \
|
||||
out4 = DOT_SHIFT_RIGHT_PCK_H(vec0_m, vec1_m, cnst1_m); \
|
||||
out2 = DOT_SHIFT_RIGHT_PCK_H(vec2_m, vec3_m, cnst0_m); \
|
||||
out5 = DOT_SHIFT_RIGHT_PCK_H(vec2_m, vec3_m, cnst1_m); \
|
||||
\
|
||||
out1 = -out1; \
|
||||
out3 = -out3; \
|
||||
out5 = -out5; \
|
||||
}
|
||||
|
||||
#define VP9_FADST4(in0, in1, in2, in3, out0, out1, out2, out3) \
|
||||
{ \
|
||||
v4i32 s0_m, s1_m, s2_m, s3_m, constant_m; \
|
||||
v4i32 in0_r_m, in1_r_m, in2_r_m, in3_r_m; \
|
||||
\
|
||||
UNPCK_R_SH_SW(in0, in0_r_m); \
|
||||
UNPCK_R_SH_SW(in1, in1_r_m); \
|
||||
UNPCK_R_SH_SW(in2, in2_r_m); \
|
||||
UNPCK_R_SH_SW(in3, in3_r_m); \
|
||||
\
|
||||
constant_m = __msa_fill_w(sinpi_4_9); \
|
||||
MUL2(in0_r_m, constant_m, in3_r_m, constant_m, s1_m, s0_m); \
|
||||
\
|
||||
constant_m = __msa_fill_w(sinpi_1_9); \
|
||||
s0_m += in0_r_m * constant_m; \
|
||||
s1_m -= in1_r_m * constant_m; \
|
||||
\
|
||||
constant_m = __msa_fill_w(sinpi_2_9); \
|
||||
s0_m += in1_r_m * constant_m; \
|
||||
s1_m += in3_r_m * constant_m; \
|
||||
\
|
||||
s2_m = in0_r_m + in1_r_m - in3_r_m; \
|
||||
\
|
||||
constant_m = __msa_fill_w(sinpi_3_9); \
|
||||
MUL2(in2_r_m, constant_m, s2_m, constant_m, s3_m, in1_r_m); \
|
||||
\
|
||||
in0_r_m = s0_m + s3_m; \
|
||||
s2_m = s1_m - s3_m; \
|
||||
s3_m = s1_m - s0_m + s3_m; \
|
||||
\
|
||||
SRARI_W4_SW(in0_r_m, in1_r_m, s2_m, s3_m, DCT_CONST_BITS); \
|
||||
PCKEV_H4_SH(in0_r_m, in0_r_m, in1_r_m, in1_r_m, s2_m, s2_m, s3_m, s3_m, \
|
||||
out0, out1, out2, out3); \
|
||||
}
|
||||
#endif // VPX_VP9_ENCODER_MIPS_MSA_VP9_FDCT_MSA_H_
|
||||
@@ -0,0 +1,292 @@
|
||||
/*
|
||||
* Copyright (c) 2018 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 "vpx_dsp/ppc/types_vsx.h"
|
||||
|
||||
// Multiply the packed 16-bit integers in a and b, producing intermediate 32-bit
|
||||
// integers, and return the high 16 bits of the intermediate integers.
|
||||
// (a * b) >> 16
|
||||
// Note: Because this is done in 2 operations, a and b cannot both be UINT16_MIN
|
||||
static INLINE int16x8_t vec_mulhi(int16x8_t a, int16x8_t b) {
|
||||
// madds does ((A * B) >> 15) + C, we need >> 16, so we perform an extra right
|
||||
// shift.
|
||||
return vec_sra(vec_madds(a, b, vec_zeros_s16), vec_ones_u16);
|
||||
}
|
||||
|
||||
// Negate 16-bit integers in a when the corresponding signed 16-bit
|
||||
// integer in b is negative.
|
||||
static INLINE int16x8_t vec_sign(int16x8_t a, int16x8_t b) {
|
||||
const int16x8_t mask = vec_sra(b, vec_shift_sign_s16);
|
||||
return vec_xor(vec_add(a, mask), mask);
|
||||
}
|
||||
|
||||
// Compare packed 16-bit integers across a, and return the maximum value in
|
||||
// every element. Returns a vector containing the biggest value across vector a.
|
||||
static INLINE int16x8_t vec_max_across(int16x8_t a) {
|
||||
a = vec_max(a, vec_perm(a, a, vec_perm64));
|
||||
a = vec_max(a, vec_perm(a, a, vec_perm32));
|
||||
return vec_max(a, vec_perm(a, a, vec_perm16));
|
||||
}
|
||||
|
||||
void vp9_quantize_fp_vsx(const tran_low_t *coeff_ptr, intptr_t 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, const int16_t *scan,
|
||||
const int16_t *iscan) {
|
||||
int16x8_t qcoeff0, qcoeff1, dqcoeff0, dqcoeff1, eob;
|
||||
bool16x8_t zero_coeff0, zero_coeff1;
|
||||
|
||||
int16x8_t round = vec_vsx_ld(0, round_ptr);
|
||||
int16x8_t quant = vec_vsx_ld(0, quant_ptr);
|
||||
int16x8_t dequant = vec_vsx_ld(0, dequant_ptr);
|
||||
int16x8_t coeff0 = vec_vsx_ld(0, coeff_ptr);
|
||||
int16x8_t coeff1 = vec_vsx_ld(16, coeff_ptr);
|
||||
int16x8_t scan0 = vec_vsx_ld(0, iscan);
|
||||
int16x8_t scan1 = vec_vsx_ld(16, iscan);
|
||||
|
||||
(void)scan;
|
||||
(void)skip_block;
|
||||
assert(!skip_block);
|
||||
|
||||
// First set of 8 coeff starts with DC + 7 AC
|
||||
qcoeff0 = vec_mulhi(vec_vaddshs(vec_abs(coeff0), round), quant);
|
||||
zero_coeff0 = vec_cmpeq(qcoeff0, vec_zeros_s16);
|
||||
qcoeff0 = vec_sign(qcoeff0, coeff0);
|
||||
vec_vsx_st(qcoeff0, 0, qcoeff_ptr);
|
||||
|
||||
dqcoeff0 = vec_mladd(qcoeff0, dequant, vec_zeros_s16);
|
||||
vec_vsx_st(dqcoeff0, 0, dqcoeff_ptr);
|
||||
|
||||
// Remove DC value from round and quant
|
||||
round = vec_splat(round, 1);
|
||||
quant = vec_splat(quant, 1);
|
||||
|
||||
// Remove DC value from dequant
|
||||
dequant = vec_splat(dequant, 1);
|
||||
|
||||
// Second set of 8 coeff starts with (all AC)
|
||||
qcoeff1 = vec_mulhi(vec_vaddshs(vec_abs(coeff1), round), quant);
|
||||
zero_coeff1 = vec_cmpeq(qcoeff1, vec_zeros_s16);
|
||||
qcoeff1 = vec_sign(qcoeff1, coeff1);
|
||||
vec_vsx_st(qcoeff1, 16, qcoeff_ptr);
|
||||
|
||||
dqcoeff1 = vec_mladd(qcoeff1, dequant, vec_zeros_s16);
|
||||
vec_vsx_st(dqcoeff1, 16, dqcoeff_ptr);
|
||||
|
||||
eob = vec_max(vec_or(scan0, zero_coeff0), vec_or(scan1, zero_coeff1));
|
||||
|
||||
// We quantize 16 coeff up front (enough for a 4x4) and process 24 coeff per
|
||||
// loop iteration.
|
||||
// for 8x8: 16 + 2 x 24 = 64
|
||||
// for 16x16: 16 + 10 x 24 = 256
|
||||
if (n_coeffs > 16) {
|
||||
int16x8_t coeff2, qcoeff2, dqcoeff2, eob2, scan2;
|
||||
bool16x8_t zero_coeff2;
|
||||
|
||||
int index = 16;
|
||||
int off0 = 32;
|
||||
int off1 = 48;
|
||||
int off2 = 64;
|
||||
|
||||
do {
|
||||
coeff0 = vec_vsx_ld(off0, coeff_ptr);
|
||||
coeff1 = vec_vsx_ld(off1, coeff_ptr);
|
||||
coeff2 = vec_vsx_ld(off2, coeff_ptr);
|
||||
scan0 = vec_vsx_ld(off0, iscan);
|
||||
scan1 = vec_vsx_ld(off1, iscan);
|
||||
scan2 = vec_vsx_ld(off2, iscan);
|
||||
|
||||
qcoeff0 = vec_mulhi(vec_vaddshs(vec_abs(coeff0), round), quant);
|
||||
zero_coeff0 = vec_cmpeq(qcoeff0, vec_zeros_s16);
|
||||
qcoeff0 = vec_sign(qcoeff0, coeff0);
|
||||
vec_vsx_st(qcoeff0, off0, qcoeff_ptr);
|
||||
dqcoeff0 = vec_mladd(qcoeff0, dequant, vec_zeros_s16);
|
||||
vec_vsx_st(dqcoeff0, off0, dqcoeff_ptr);
|
||||
|
||||
qcoeff1 = vec_mulhi(vec_vaddshs(vec_abs(coeff1), round), quant);
|
||||
zero_coeff1 = vec_cmpeq(qcoeff1, vec_zeros_s16);
|
||||
qcoeff1 = vec_sign(qcoeff1, coeff1);
|
||||
vec_vsx_st(qcoeff1, off1, qcoeff_ptr);
|
||||
dqcoeff1 = vec_mladd(qcoeff1, dequant, vec_zeros_s16);
|
||||
vec_vsx_st(dqcoeff1, off1, dqcoeff_ptr);
|
||||
|
||||
qcoeff2 = vec_mulhi(vec_vaddshs(vec_abs(coeff2), round), quant);
|
||||
zero_coeff2 = vec_cmpeq(qcoeff2, vec_zeros_s16);
|
||||
qcoeff2 = vec_sign(qcoeff2, coeff2);
|
||||
vec_vsx_st(qcoeff2, off2, qcoeff_ptr);
|
||||
dqcoeff2 = vec_mladd(qcoeff2, dequant, vec_zeros_s16);
|
||||
vec_vsx_st(dqcoeff2, off2, dqcoeff_ptr);
|
||||
|
||||
eob = vec_max(eob, vec_or(scan0, zero_coeff0));
|
||||
eob2 = vec_max(vec_or(scan1, zero_coeff1), vec_or(scan2, zero_coeff2));
|
||||
eob = vec_max(eob, eob2);
|
||||
|
||||
index += 24;
|
||||
off0 += 48;
|
||||
off1 += 48;
|
||||
off2 += 48;
|
||||
} while (index < n_coeffs);
|
||||
}
|
||||
|
||||
eob = vec_max_across(eob);
|
||||
*eob_ptr = eob[0] + 1;
|
||||
}
|
||||
|
||||
// Sets the value of a 32-bit integers to 1 when the corresponding value in a is
|
||||
// negative.
|
||||
static INLINE int32x4_t vec_is_neg(int32x4_t a) {
|
||||
return vec_sr(a, vec_shift_sign_s32);
|
||||
}
|
||||
|
||||
// DeQuantization function used for 32x32 blocks. Quantized coeff of 32x32
|
||||
// blocks are twice as big as for other block sizes. As such, using
|
||||
// vec_mladd results in overflow.
|
||||
static INLINE int16x8_t dequantize_coeff_32(int16x8_t qcoeff,
|
||||
int16x8_t dequant) {
|
||||
int32x4_t dqcoeffe = vec_mule(qcoeff, dequant);
|
||||
int32x4_t dqcoeffo = vec_mulo(qcoeff, dequant);
|
||||
// Add 1 if negative to round towards zero because the C uses division.
|
||||
dqcoeffe = vec_add(dqcoeffe, vec_is_neg(dqcoeffe));
|
||||
dqcoeffo = vec_add(dqcoeffo, vec_is_neg(dqcoeffo));
|
||||
dqcoeffe = vec_sra(dqcoeffe, vec_ones_u32);
|
||||
dqcoeffo = vec_sra(dqcoeffo, vec_ones_u32);
|
||||
return (int16x8_t)vec_perm(dqcoeffe, dqcoeffo, vec_perm_odd_even_pack);
|
||||
}
|
||||
|
||||
void vp9_quantize_fp_32x32_vsx(const tran_low_t *coeff_ptr, intptr_t 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,
|
||||
const int16_t *scan, const int16_t *iscan) {
|
||||
// In stage 1, we quantize 16 coeffs (DC + 15 AC)
|
||||
// In stage 2, we loop 42 times and quantize 24 coeffs per iteration
|
||||
// (32 * 32 - 16) / 24 = 42
|
||||
int num_itr = 42;
|
||||
// Offsets are in bytes, 16 coeffs = 32 bytes
|
||||
int off0 = 32;
|
||||
int off1 = 48;
|
||||
int off2 = 64;
|
||||
|
||||
int16x8_t qcoeff0, qcoeff1, dqcoeff0, dqcoeff1, eob;
|
||||
bool16x8_t mask0, mask1, zero_coeff0, zero_coeff1;
|
||||
|
||||
int16x8_t round = vec_vsx_ld(0, round_ptr);
|
||||
int16x8_t quant = vec_vsx_ld(0, quant_ptr);
|
||||
int16x8_t dequant = vec_vsx_ld(0, dequant_ptr);
|
||||
int16x8_t coeff0 = vec_vsx_ld(0, coeff_ptr);
|
||||
int16x8_t coeff1 = vec_vsx_ld(16, coeff_ptr);
|
||||
int16x8_t scan0 = vec_vsx_ld(0, iscan);
|
||||
int16x8_t scan1 = vec_vsx_ld(16, iscan);
|
||||
int16x8_t thres = vec_sra(dequant, vec_splats((uint16_t)2));
|
||||
int16x8_t abs_coeff0 = vec_abs(coeff0);
|
||||
int16x8_t abs_coeff1 = vec_abs(coeff1);
|
||||
|
||||
(void)scan;
|
||||
(void)skip_block;
|
||||
(void)n_coeffs;
|
||||
assert(!skip_block);
|
||||
|
||||
mask0 = vec_cmpge(abs_coeff0, thres);
|
||||
round = vec_sra(vec_add(round, vec_ones_s16), vec_ones_u16);
|
||||
// First set of 8 coeff starts with DC + 7 AC
|
||||
qcoeff0 = vec_madds(vec_vaddshs(abs_coeff0, round), quant, vec_zeros_s16);
|
||||
qcoeff0 = vec_and(qcoeff0, mask0);
|
||||
zero_coeff0 = vec_cmpeq(qcoeff0, vec_zeros_s16);
|
||||
qcoeff0 = vec_sign(qcoeff0, coeff0);
|
||||
vec_vsx_st(qcoeff0, 0, qcoeff_ptr);
|
||||
|
||||
dqcoeff0 = dequantize_coeff_32(qcoeff0, dequant);
|
||||
vec_vsx_st(dqcoeff0, 0, dqcoeff_ptr);
|
||||
|
||||
// Remove DC value from thres, round, quant and dequant
|
||||
thres = vec_splat(thres, 1);
|
||||
round = vec_splat(round, 1);
|
||||
quant = vec_splat(quant, 1);
|
||||
dequant = vec_splat(dequant, 1);
|
||||
|
||||
mask1 = vec_cmpge(abs_coeff1, thres);
|
||||
|
||||
// Second set of 8 coeff starts with (all AC)
|
||||
qcoeff1 =
|
||||
vec_madds(vec_vaddshs(vec_abs(coeff1), round), quant, vec_zeros_s16);
|
||||
qcoeff1 = vec_and(qcoeff1, mask1);
|
||||
zero_coeff1 = vec_cmpeq(qcoeff1, vec_zeros_s16);
|
||||
qcoeff1 = vec_sign(qcoeff1, coeff1);
|
||||
vec_vsx_st(qcoeff1, 16, qcoeff_ptr);
|
||||
|
||||
dqcoeff1 = dequantize_coeff_32(qcoeff1, dequant);
|
||||
vec_vsx_st(dqcoeff1, 16, dqcoeff_ptr);
|
||||
|
||||
eob = vec_max(vec_or(scan0, zero_coeff0), vec_or(scan1, zero_coeff1));
|
||||
|
||||
do {
|
||||
int16x8_t coeff2, abs_coeff2, qcoeff2, dqcoeff2, eob2, scan2;
|
||||
bool16x8_t zero_coeff2, mask2;
|
||||
coeff0 = vec_vsx_ld(off0, coeff_ptr);
|
||||
coeff1 = vec_vsx_ld(off1, coeff_ptr);
|
||||
coeff2 = vec_vsx_ld(off2, coeff_ptr);
|
||||
scan0 = vec_vsx_ld(off0, iscan);
|
||||
scan1 = vec_vsx_ld(off1, iscan);
|
||||
scan2 = vec_vsx_ld(off2, iscan);
|
||||
|
||||
abs_coeff0 = vec_abs(coeff0);
|
||||
abs_coeff1 = vec_abs(coeff1);
|
||||
abs_coeff2 = vec_abs(coeff2);
|
||||
|
||||
qcoeff0 = vec_madds(vec_vaddshs(abs_coeff0, round), quant, vec_zeros_s16);
|
||||
qcoeff1 = vec_madds(vec_vaddshs(abs_coeff1, round), quant, vec_zeros_s16);
|
||||
qcoeff2 = vec_madds(vec_vaddshs(abs_coeff2, round), quant, vec_zeros_s16);
|
||||
|
||||
mask0 = vec_cmpge(abs_coeff0, thres);
|
||||
mask1 = vec_cmpge(abs_coeff1, thres);
|
||||
mask2 = vec_cmpge(abs_coeff2, thres);
|
||||
|
||||
qcoeff0 = vec_and(qcoeff0, mask0);
|
||||
qcoeff1 = vec_and(qcoeff1, mask1);
|
||||
qcoeff2 = vec_and(qcoeff2, mask2);
|
||||
|
||||
zero_coeff0 = vec_cmpeq(qcoeff0, vec_zeros_s16);
|
||||
zero_coeff1 = vec_cmpeq(qcoeff1, vec_zeros_s16);
|
||||
zero_coeff2 = vec_cmpeq(qcoeff2, vec_zeros_s16);
|
||||
|
||||
qcoeff0 = vec_sign(qcoeff0, coeff0);
|
||||
qcoeff1 = vec_sign(qcoeff1, coeff1);
|
||||
qcoeff2 = vec_sign(qcoeff2, coeff2);
|
||||
|
||||
vec_vsx_st(qcoeff0, off0, qcoeff_ptr);
|
||||
vec_vsx_st(qcoeff1, off1, qcoeff_ptr);
|
||||
vec_vsx_st(qcoeff2, off2, qcoeff_ptr);
|
||||
|
||||
dqcoeff0 = dequantize_coeff_32(qcoeff0, dequant);
|
||||
dqcoeff1 = dequantize_coeff_32(qcoeff1, dequant);
|
||||
dqcoeff2 = dequantize_coeff_32(qcoeff2, dequant);
|
||||
|
||||
vec_vsx_st(dqcoeff0, off0, dqcoeff_ptr);
|
||||
vec_vsx_st(dqcoeff1, off1, dqcoeff_ptr);
|
||||
vec_vsx_st(dqcoeff2, off2, dqcoeff_ptr);
|
||||
|
||||
eob = vec_max(eob, vec_or(scan0, zero_coeff0));
|
||||
eob2 = vec_max(vec_or(scan1, zero_coeff1), vec_or(scan2, zero_coeff2));
|
||||
eob = vec_max(eob, eob2);
|
||||
|
||||
off0 += 48;
|
||||
off1 += 48;
|
||||
off2 += 48;
|
||||
num_itr--;
|
||||
} while (num_itr != 0);
|
||||
|
||||
eob = vec_max_across(eob);
|
||||
*eob_ptr = eob[0] + 1;
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2016 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_encoder.h"
|
||||
#include "vp9/encoder/vp9_alt_ref_aq.h"
|
||||
|
||||
struct ALT_REF_AQ {
|
||||
int dummy;
|
||||
};
|
||||
|
||||
struct ALT_REF_AQ *vp9_alt_ref_aq_create(void) {
|
||||
return (struct ALT_REF_AQ *)vpx_malloc(sizeof(struct ALT_REF_AQ));
|
||||
}
|
||||
|
||||
void vp9_alt_ref_aq_destroy(struct ALT_REF_AQ *const self) { vpx_free(self); }
|
||||
|
||||
void vp9_alt_ref_aq_upload_map(struct ALT_REF_AQ *const self,
|
||||
const struct MATX_8U *segmentation_map) {
|
||||
(void)self;
|
||||
(void)segmentation_map;
|
||||
}
|
||||
|
||||
void vp9_alt_ref_aq_set_nsegments(struct ALT_REF_AQ *const self,
|
||||
int nsegments) {
|
||||
(void)self;
|
||||
(void)nsegments;
|
||||
}
|
||||
|
||||
void vp9_alt_ref_aq_setup_mode(struct ALT_REF_AQ *const self,
|
||||
struct VP9_COMP *const cpi) {
|
||||
(void)cpi;
|
||||
(void)self;
|
||||
}
|
||||
|
||||
// set basic segmentation to the altref's one
|
||||
void vp9_alt_ref_aq_setup_map(struct ALT_REF_AQ *const self,
|
||||
struct VP9_COMP *const cpi) {
|
||||
(void)cpi;
|
||||
(void)self;
|
||||
}
|
||||
|
||||
// restore cpi->aq_mode
|
||||
void vp9_alt_ref_aq_unset_all(struct ALT_REF_AQ *const self,
|
||||
struct VP9_COMP *const cpi) {
|
||||
(void)cpi;
|
||||
(void)self;
|
||||
}
|
||||
|
||||
int vp9_alt_ref_aq_disable_if(const struct ALT_REF_AQ *self,
|
||||
int segmentation_overhead, int bandwidth) {
|
||||
(void)bandwidth;
|
||||
(void)self;
|
||||
(void)segmentation_overhead;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright (c) 2016 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* \file vp9_alt_ref_aq.h
|
||||
*
|
||||
* This file contains public interface for setting up adaptive segmentation
|
||||
* for altref frames. Go to alt_ref_aq_private.h for implmentation details.
|
||||
*/
|
||||
|
||||
#ifndef VPX_VP9_ENCODER_VP9_ALT_REF_AQ_H_
|
||||
#define VPX_VP9_ENCODER_VP9_ALT_REF_AQ_H_
|
||||
|
||||
#include "vpx/vpx_integer.h"
|
||||
|
||||
// Where to disable segmentation
|
||||
#define ALT_REF_AQ_LOW_BITRATE_BOUNDARY 150
|
||||
|
||||
// Last frame always has overall quality = 0,
|
||||
// so it is questionable if I can process it
|
||||
#define ALT_REF_AQ_APPLY_TO_LAST_FRAME 1
|
||||
|
||||
// If I should try to compare gain
|
||||
// against segmentation overhead
|
||||
#define ALT_REF_AQ_PROTECT_GAIN 0
|
||||
|
||||
// Threshold to disable segmentation
|
||||
#define ALT_REF_AQ_PROTECT_GAIN_THRESH 0.5
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Simple structure for storing images
|
||||
struct MATX_8U {
|
||||
int rows;
|
||||
int cols;
|
||||
int stride;
|
||||
|
||||
uint8_t *data;
|
||||
};
|
||||
|
||||
struct VP9_COMP;
|
||||
struct ALT_REF_AQ;
|
||||
|
||||
/*!\brief Constructor
|
||||
*
|
||||
* \return Instance of the class
|
||||
*/
|
||||
struct ALT_REF_AQ *vp9_alt_ref_aq_create(void);
|
||||
|
||||
/*!\brief Upload segmentation_map to self object
|
||||
*
|
||||
* \param self Instance of the class
|
||||
* \param segmentation_map Segmentation map to upload
|
||||
*/
|
||||
void vp9_alt_ref_aq_upload_map(struct ALT_REF_AQ *const self,
|
||||
const struct MATX_8U *segmentation_map);
|
||||
|
||||
/*!\brief Return pointer to the altref segmentation map
|
||||
*
|
||||
* \param self Instance of the class
|
||||
* \param segmentation_overhead Segmentation overhead in bytes
|
||||
* \param bandwidth Current frame bandwidth in bytes
|
||||
*
|
||||
* \return Boolean value to disable segmentation
|
||||
*/
|
||||
int vp9_alt_ref_aq_disable_if(const struct ALT_REF_AQ *self,
|
||||
int segmentation_overhead, int bandwidth);
|
||||
|
||||
/*!\brief Set number of segments
|
||||
*
|
||||
* It is used for delta quantizer computations
|
||||
* and thus it can be larger than
|
||||
* maximum value of the segmentation map
|
||||
*
|
||||
* \param self Instance of the class
|
||||
* \param nsegments Maximum number of segments
|
||||
*/
|
||||
void vp9_alt_ref_aq_set_nsegments(struct ALT_REF_AQ *const self, int nsegments);
|
||||
|
||||
/*!\brief Set up LOOKAHEAD_AQ segmentation mode
|
||||
*
|
||||
* Set up segmentation mode to LOOKAHEAD_AQ
|
||||
* (expected future frames prediction
|
||||
* quality refering to the current frame).
|
||||
*
|
||||
* \param self Instance of the class
|
||||
* \param cpi Encoder context
|
||||
*/
|
||||
void vp9_alt_ref_aq_setup_mode(struct ALT_REF_AQ *const self,
|
||||
struct VP9_COMP *const cpi);
|
||||
|
||||
/*!\brief Set up LOOKAHEAD_AQ segmentation map and delta quantizers
|
||||
*
|
||||
* \param self Instance of the class
|
||||
* \param cpi Encoder context
|
||||
*/
|
||||
void vp9_alt_ref_aq_setup_map(struct ALT_REF_AQ *const self,
|
||||
struct VP9_COMP *const cpi);
|
||||
|
||||
/*!\brief Restore main segmentation map mode and reset the class variables
|
||||
*
|
||||
* \param self Instance of the class
|
||||
* \param cpi Encoder context
|
||||
*/
|
||||
void vp9_alt_ref_aq_unset_all(struct ALT_REF_AQ *const self,
|
||||
struct VP9_COMP *const cpi);
|
||||
|
||||
/*!\brief Destructor
|
||||
*
|
||||
* \param self Instance of the class
|
||||
*/
|
||||
void vp9_alt_ref_aq_destroy(struct ALT_REF_AQ *const self);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_ENCODER_VP9_ALT_REF_AQ_H_
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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 "vpx_ports/system_state.h"
|
||||
|
||||
#include "vp9/encoder/vp9_aq_360.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"
|
||||
|
||||
static const double rate_ratio[MAX_SEGMENTS] = { 1.0, 0.75, 0.6, 0.5,
|
||||
0.4, 0.3, 0.25 };
|
||||
|
||||
// Sets segment id 0 for the equatorial region, 1 for temperate region
|
||||
// and 2 for the polar regions
|
||||
unsigned int vp9_360aq_segment_id(int mi_row, int mi_rows) {
|
||||
if (mi_row < mi_rows / 8 || mi_row > mi_rows - mi_rows / 8)
|
||||
return 2;
|
||||
else if (mi_row < mi_rows / 4 || mi_row > mi_rows - mi_rows / 4)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vp9_360aq_frame_setup(VP9_COMP *cpi) {
|
||||
VP9_COMMON *cm = &cpi->common;
|
||||
struct segmentation *seg = &cm->seg;
|
||||
int i;
|
||||
|
||||
if (frame_is_intra_only(cm) || cpi->force_update_segmentation ||
|
||||
cm->error_resilient_mode) {
|
||||
vp9_enable_segmentation(seg);
|
||||
vp9_clearall_segfeatures(seg);
|
||||
|
||||
seg->abs_delta = SEGMENT_DELTADATA;
|
||||
|
||||
vpx_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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 VPX_VP9_ENCODER_VP9_AQ_360_H_
|
||||
#define VPX_VP9_ENCODER_VP9_AQ_360_H_
|
||||
|
||||
#include "vp9/encoder/vp9_encoder.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
unsigned int vp9_360aq_segment_id(int mi_row, int mi_rows);
|
||||
void vp9_360aq_frame_setup(VP9_COMP *cpi);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_ENCODER_VP9_AQ_360_H_
|
||||
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* 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 "vpx_dsp/vpx_dsp_common.h"
|
||||
#include "vpx_ports/system_state.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 }
|
||||
};
|
||||
|
||||
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.
|
||||
vpx_clear_system_state();
|
||||
|
||||
if (frame_is_intra_only(cm) || cm->error_resilient_mode ||
|
||||
cpi->refresh_alt_ref_frame || cpi->force_update_segmentation ||
|
||||
(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
|
||||
// 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 = VPXMIN(cm->mi_cols - mi_col, num_8x8_blocks_wide_lookup[bs]);
|
||||
const int ymis = VPXMIN(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);
|
||||
|
||||
vpx_clear_system_state();
|
||||
low_var_thresh = (cpi->oxcf.pass == 2) ? VPXMAX(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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 VPX_VP9_ENCODER_VP9_AQ_COMPLEXITY_H_
|
||||
#define VPX_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 // VPX_VP9_ENCODER_VP9_AQ_COMPLEXITY_H_
|
||||
@@ -0,0 +1,688 @@
|
||||
/*
|
||||
* 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 "vpx_dsp/vpx_dsp_common.h"
|
||||
#include "vpx_ports/system_state.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"
|
||||
|
||||
static const uint8_t VP9_VAR_OFFS[64] = {
|
||||
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
|
||||
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
|
||||
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
|
||||
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
|
||||
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128
|
||||
};
|
||||
|
||||
CYCLIC_REFRESH *vp9_cyclic_refresh_alloc(int mi_rows, int mi_cols) {
|
||||
size_t last_coded_q_map_size;
|
||||
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) {
|
||||
vp9_cyclic_refresh_free(cr);
|
||||
return NULL;
|
||||
}
|
||||
last_coded_q_map_size = mi_rows * mi_cols * sizeof(*cr->last_coded_q_map);
|
||||
cr->last_coded_q_map = vpx_malloc(last_coded_q_map_size);
|
||||
if (cr->last_coded_q_map == NULL) {
|
||||
vp9_cyclic_refresh_free(cr);
|
||||
return NULL;
|
||||
}
|
||||
assert(MAXQ <= 255);
|
||||
memset(cr->last_coded_q_map, MAXQ, last_coded_q_map_size);
|
||||
cr->counter_encode_maxq_scene_change = 0;
|
||||
return cr;
|
||||
}
|
||||
|
||||
void vp9_cyclic_refresh_free(CYCLIC_REFRESH *cr) {
|
||||
if (cr != NULL) {
|
||||
vpx_free(cr->map);
|
||||
vpx_free(cr->last_coded_q_map);
|
||||
vpx_free(cr);
|
||||
}
|
||||
}
|
||||
|
||||
// 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 MODE_INFO *mi,
|
||||
int64_t rate, int64_t dist, int bsize) {
|
||||
MV mv = mi->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(mi)))
|
||||
return CR_SEGMENT_ID_BASE;
|
||||
else if (bsize >= BLOCK_16X16 && rate < cr->thresh_rate_sb &&
|
||||
is_inter_block(mi) && mi->mv[0].as_int == 0 &&
|
||||
cr->rate_boost_fac > 10)
|
||||
// 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[1],
|
||||
mbs, correction_factor, cm->bit_depth) +
|
||||
weight_segment2 *
|
||||
vp9_estimate_bits_at_q(cm->frame_type,
|
||||
cm->base_qindex + cr->qindex_delta[2],
|
||||
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 deltaq = 0;
|
||||
if (cpi->oxcf.speed < 8)
|
||||
deltaq = compute_deltaq(cpi, i, cr->rate_ratio_qdelta);
|
||||
else
|
||||
deltaq = -(cr->max_qdelta_perc * i) / 200;
|
||||
// Take segment weighted average for bits per mb.
|
||||
bits_per_mb = (int)((1.0 - cr->weight_segment) *
|
||||
vp9_rc_bits_per_mb(cm->frame_type, i,
|
||||
correction_factor, cm->bit_depth) +
|
||||
cr->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, MODE_INFO *const mi,
|
||||
int mi_row, int mi_col, BLOCK_SIZE bsize,
|
||||
int64_t rate, int64_t dist, int skip,
|
||||
struct macroblock_plane *const p) {
|
||||
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 = VPXMIN(cm->mi_cols - mi_col, bw);
|
||||
const int ymis = VPXMIN(cm->mi_rows - mi_row, bh);
|
||||
const int block_index = mi_row * cm->mi_cols + mi_col;
|
||||
int refresh_this_block = candidate_refresh_aq(cr, mi, 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;
|
||||
|
||||
int is_skin = 0;
|
||||
if (refresh_this_block == 0 && bsize <= BLOCK_16X16 &&
|
||||
cpi->use_skin_detection) {
|
||||
is_skin =
|
||||
vp9_compute_skin_block(p[0].src.buf, p[1].src.buf, p[2].src.buf,
|
||||
p[0].src.stride, p[1].src.stride, bsize, 0, 0);
|
||||
if (is_skin) refresh_this_block = 1;
|
||||
}
|
||||
|
||||
if (cpi->oxcf.rc_mode == VPX_VBR && mi->ref_frame[0] == GOLDEN_FRAME)
|
||||
refresh_this_block = 0;
|
||||
|
||||
// If this block is labeled for refresh, check if we should reset the
|
||||
// segment_id.
|
||||
if (cpi->sf.use_nonrd_pick_mode &&
|
||||
cyclic_refresh_segment_id_boosted(mi->segment_id)) {
|
||||
mi->segment_id = refresh_this_block;
|
||||
// Reset segment_id if it will be skipped.
|
||||
if (skip) mi->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(mi->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++) {
|
||||
int map_offset = block_index + y * cm->mi_cols + x;
|
||||
cr->map[map_offset] = new_map_value;
|
||||
cpi->segmentation_map[map_offset] = mi->segment_id;
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_cyclic_refresh_update_sb_postencode(VP9_COMP *const cpi,
|
||||
const MODE_INFO *const mi,
|
||||
int mi_row, int mi_col,
|
||||
BLOCK_SIZE bsize) {
|
||||
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 = VPXMIN(cm->mi_cols - mi_col, bw);
|
||||
const int ymis = VPXMIN(cm->mi_rows - mi_row, bh);
|
||||
const int block_index = mi_row * cm->mi_cols + mi_col;
|
||||
int x, y;
|
||||
for (y = 0; y < ymis; y++)
|
||||
for (x = 0; x < xmis; x++) {
|
||||
int map_offset = block_index + y * cm->mi_cols + x;
|
||||
// Inter skip blocks were clearly not coded at the current qindex, so
|
||||
// don't update the map for them. For cases where motion is non-zero or
|
||||
// the reference frame isn't the previous frame, the previous value in
|
||||
// the map for this spatial location is not entirely correct.
|
||||
if ((!is_inter_block(mi) || !mi->skip) &&
|
||||
mi->segment_id <= CR_SEGMENT_ID_BOOST2) {
|
||||
cr->last_coded_q_map[map_offset] =
|
||||
clamp(cm->base_qindex + cr->qindex_delta[mi->segment_id], 0, MAXQ);
|
||||
} else if (is_inter_block(mi) && mi->skip &&
|
||||
mi->segment_id <= CR_SEGMENT_ID_BOOST2) {
|
||||
cr->last_coded_q_map[map_offset] = VPXMIN(
|
||||
clamp(cm->base_qindex + cr->qindex_delta[mi->segment_id], 0, MAXQ),
|
||||
cr->last_coded_q_map[map_offset]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// From the just encoded frame: update the actual number of blocks that were
|
||||
// applied the segment delta q, and the amount of low motion in the frame.
|
||||
// Also check conditions for forcing golden update, or preventing golden
|
||||
// update if the period is up.
|
||||
void vp9_cyclic_refresh_postencode(VP9_COMP *const cpi) {
|
||||
VP9_COMMON *const cm = &cpi->common;
|
||||
MODE_INFO **mi = cm->mi_grid_visible;
|
||||
CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
|
||||
RATE_CONTROL *const rc = &cpi->rc;
|
||||
unsigned char *const seg_map = cpi->segmentation_map;
|
||||
double fraction_low = 0.0;
|
||||
int force_gf_refresh = 0;
|
||||
int low_content_frame = 0;
|
||||
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++) {
|
||||
MV mv = mi[0]->mv[0].as_mv;
|
||||
int map_index = mi_row * cm->mi_cols + mi_col;
|
||||
if (cyclic_refresh_segment_id(seg_map[map_index]) == CR_SEGMENT_ID_BOOST1)
|
||||
cr->actual_num_seg1_blocks++;
|
||||
else if (cyclic_refresh_segment_id(seg_map[map_index]) ==
|
||||
CR_SEGMENT_ID_BOOST2)
|
||||
cr->actual_num_seg2_blocks++;
|
||||
// Accumulate low_content_frame.
|
||||
if (is_inter_block(mi[0]) && abs(mv.row) < 16 && abs(mv.col) < 16)
|
||||
low_content_frame++;
|
||||
mi++;
|
||||
}
|
||||
mi += 8;
|
||||
}
|
||||
// Check for golden frame update: only for non-SVC and non-golden boost.
|
||||
if (!cpi->use_svc && cpi->ext_refresh_frame_flags_pending == 0 &&
|
||||
!cpi->oxcf.gf_cbr_boost_pct) {
|
||||
// Force this frame as a golden update frame if this frame changes the
|
||||
// resolution (resize_pending != 0).
|
||||
if (cpi->resize_pending != 0) {
|
||||
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;
|
||||
}
|
||||
// Update average of low content/motion in the frame.
|
||||
fraction_low = (double)low_content_frame / (cm->mi_rows * cm->mi_cols);
|
||||
cr->low_content_avg = (fraction_low + 3 * cr->low_content_avg) / 4;
|
||||
if (!force_gf_refresh && cpi->refresh_golden_frame == 1 &&
|
||||
rc->frames_since_key > rc->frames_since_golden + 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.65 || cr->low_content_avg < 0.6) {
|
||||
cpi->refresh_golden_frame = 0;
|
||||
}
|
||||
// Reset for next internal.
|
||||
cr->low_content_avg = fraction_low;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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 of the refresh period,
|
||||
// with some max limit. 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 = VPXMIN(4 * (100 / cr->percent_refresh), 40);
|
||||
else
|
||||
rc->baseline_gf_interval = 40;
|
||||
if (cpi->oxcf.rc_mode == VPX_VBR) rc->baseline_gf_interval = 20;
|
||||
if (rc->avg_frame_low_motion < 50 && rc->frames_since_key > 40)
|
||||
rc->baseline_gf_interval = 10;
|
||||
}
|
||||
|
||||
static int is_superblock_flat_static(VP9_COMP *const cpi, int sb_row_index,
|
||||
int sb_col_index) {
|
||||
unsigned int source_variance;
|
||||
const uint8_t *src_y = cpi->Source->y_buffer;
|
||||
const int ystride = cpi->Source->y_stride;
|
||||
unsigned int sse;
|
||||
const BLOCK_SIZE bsize = BLOCK_64X64;
|
||||
src_y += (sb_row_index << 6) * ystride + (sb_col_index << 6);
|
||||
source_variance =
|
||||
cpi->fn_ptr[bsize].vf(src_y, ystride, VP9_VAR_OFFS, 0, &sse);
|
||||
if (source_variance == 0) {
|
||||
uint64_t block_sad;
|
||||
const uint8_t *last_src_y = cpi->Last_Source->y_buffer;
|
||||
const int last_ystride = cpi->Last_Source->y_stride;
|
||||
last_src_y += (sb_row_index << 6) * ystride + (sb_col_index << 6);
|
||||
block_sad =
|
||||
cpi->fn_ptr[bsize].sdf(src_y, ystride, last_src_y, last_ystride);
|
||||
if (block_sad == 0) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 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;
|
||||
int consec_zero_mv_thresh = 0;
|
||||
int qindex_thresh = 0;
|
||||
int count_sel = 0;
|
||||
int count_tot = 0;
|
||||
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;
|
||||
if (cpi->oxcf.content != VP9E_CONTENT_SCREEN) {
|
||||
consec_zero_mv_thresh = 100;
|
||||
}
|
||||
qindex_thresh =
|
||||
cpi->oxcf.content == VP9E_CONTENT_SCREEN
|
||||
? vp9_get_qindex(&cm->seg, CR_SEGMENT_ID_BOOST2, cm->base_qindex)
|
||||
: vp9_get_qindex(&cm->seg, CR_SEGMENT_ID_BOOST1, cm->base_qindex);
|
||||
// More aggressive settings for noisy content.
|
||||
if (cpi->noise_estimate.enabled && cpi->noise_estimate.level >= kMedium) {
|
||||
consec_zero_mv_thresh = 60;
|
||||
qindex_thresh =
|
||||
VPXMAX(vp9_get_qindex(&cm->seg, CR_SEGMENT_ID_BOOST1, cm->base_qindex),
|
||||
cm->base_qindex);
|
||||
}
|
||||
do {
|
||||
int sum_map = 0;
|
||||
int consec_zero_mv_thresh_block = consec_zero_mv_thresh;
|
||||
// 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;
|
||||
int flat_static_blocks = 0;
|
||||
int compute_content = 1;
|
||||
assert(mi_row >= 0 && mi_row < cm->mi_rows);
|
||||
assert(mi_col >= 0 && mi_col < cm->mi_cols);
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
if (cpi->common.use_highbitdepth) compute_content = 0;
|
||||
#endif
|
||||
if (cpi->Last_Source == NULL ||
|
||||
cpi->Last_Source->y_width != cpi->Source->y_width ||
|
||||
cpi->Last_Source->y_height != cpi->Source->y_height)
|
||||
compute_content = 0;
|
||||
bl_index = mi_row * cm->mi_cols + mi_col;
|
||||
// Loop through all 8x8 blocks in superblock and update map.
|
||||
xmis =
|
||||
VPXMIN(cm->mi_cols - mi_col, num_8x8_blocks_wide_lookup[BLOCK_64X64]);
|
||||
ymis =
|
||||
VPXMIN(cm->mi_rows - mi_row, num_8x8_blocks_high_lookup[BLOCK_64X64]);
|
||||
if (cpi->noise_estimate.enabled && cpi->noise_estimate.level >= kMedium &&
|
||||
(xmis <= 2 || ymis <= 2))
|
||||
consec_zero_mv_thresh_block = 4;
|
||||
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 depending on the coding mode.
|
||||
if (cr->map[bl_index2] == 0) {
|
||||
count_tot++;
|
||||
if (cr->last_coded_q_map[bl_index2] > qindex_thresh ||
|
||||
cpi->consec_zero_mv[bl_index2] < consec_zero_mv_thresh_block) {
|
||||
sum_map++;
|
||||
count_sel++;
|
||||
}
|
||||
} 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) {
|
||||
// This superblock is a candidate for refresh:
|
||||
// compute spatial variance and exclude blocks that are spatially flat
|
||||
// and stationary. Note: this is currently only done for screne content
|
||||
// mode.
|
||||
if (compute_content && cr->skip_flat_static_blocks)
|
||||
flat_static_blocks =
|
||||
is_superblock_flat_static(cpi, sb_row_index, sb_col_index);
|
||||
if (!flat_static_blocks) {
|
||||
// Label this superblock as segment 1.
|
||||
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;
|
||||
cr->reduce_refresh = 0;
|
||||
if (cpi->oxcf.content != VP9E_CONTENT_SCREEN)
|
||||
if (count_sel<(3 * count_tot)>> 2) cr->reduce_refresh = 1;
|
||||
}
|
||||
|
||||
// Set cyclic refresh parameters.
|
||||
void vp9_cyclic_refresh_update_parameters(VP9_COMP *const cpi) {
|
||||
const RATE_CONTROL *const rc = &cpi->rc;
|
||||
const VP9_COMMON *const cm = &cpi->common;
|
||||
CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
|
||||
int num8x8bl = cm->MBs << 2;
|
||||
int target_refresh = 0;
|
||||
double weight_segment_target = 0;
|
||||
double weight_segment = 0;
|
||||
int thresh_low_motion = 20;
|
||||
int qp_thresh = VPXMIN((cpi->oxcf.content == VP9E_CONTENT_SCREEN) ? 35 : 20,
|
||||
rc->best_quality << 1);
|
||||
int qp_max_thresh = 117 * MAXQ >> 7;
|
||||
cr->apply_cyclic_refresh = 1;
|
||||
if (frame_is_intra_only(cm) || cpi->svc.temporal_layer_id > 0 ||
|
||||
is_lossless_requested(&cpi->oxcf) ||
|
||||
rc->avg_frame_qindex[INTER_FRAME] < qp_thresh ||
|
||||
(cpi->use_svc &&
|
||||
cpi->svc.layer_context[cpi->svc.temporal_layer_id].is_key_frame) ||
|
||||
(!cpi->use_svc && rc->avg_frame_low_motion < thresh_low_motion &&
|
||||
rc->frames_since_key > 40) ||
|
||||
(!cpi->use_svc && rc->avg_frame_qindex[INTER_FRAME] > qp_max_thresh &&
|
||||
rc->frames_since_key > 20)) {
|
||||
cr->apply_cyclic_refresh = 0;
|
||||
return;
|
||||
}
|
||||
cr->percent_refresh = 10;
|
||||
if (cr->reduce_refresh) cr->percent_refresh = 5;
|
||||
cr->max_qdelta_perc = 60;
|
||||
cr->time_for_refresh = 0;
|
||||
cr->motion_thresh = 32;
|
||||
cr->rate_boost_fac = 15;
|
||||
// Use larger delta-qp (increase rate_ratio_qdelta) for first few (~4)
|
||||
// periods of the refresh cycle, after a key frame.
|
||||
// Account for larger interval on base layer for temporal layers.
|
||||
if (cr->percent_refresh > 0 &&
|
||||
rc->frames_since_key <
|
||||
(4 * cpi->svc.number_temporal_layers) * (100 / cr->percent_refresh)) {
|
||||
cr->rate_ratio_qdelta = 3.0;
|
||||
} else {
|
||||
cr->rate_ratio_qdelta = 2.0;
|
||||
if (cpi->noise_estimate.enabled && cpi->noise_estimate.level >= kMedium) {
|
||||
// Reduce the delta-qp if the estimated source noise is above threshold.
|
||||
cr->rate_ratio_qdelta = 1.7;
|
||||
cr->rate_boost_fac = 13;
|
||||
}
|
||||
}
|
||||
// For screen-content: keep rate_ratio_qdelta to 2.0 (segment#1 boost) and
|
||||
// percent_refresh (refresh rate) to 10. But reduce rate boost for segment#2
|
||||
// (rate_boost_fac = 10 disables segment#2).
|
||||
if (cpi->oxcf.content == VP9E_CONTENT_SCREEN) {
|
||||
// Only enable feature of skipping flat_static blocks for top layer
|
||||
// under screen content mode.
|
||||
if (cpi->svc.spatial_layer_id == cpi->svc.number_spatial_layers - 1)
|
||||
cr->skip_flat_static_blocks = 1;
|
||||
cr->percent_refresh = (cr->skip_flat_static_blocks) ? 5 : 10;
|
||||
// Increase the amount of refresh on scene change that is encoded at max Q,
|
||||
// increase for a few cycles of the refresh period (~100 / percent_refresh).
|
||||
if (cr->counter_encode_maxq_scene_change < 30)
|
||||
cr->percent_refresh = (cr->skip_flat_static_blocks) ? 10 : 15;
|
||||
cr->rate_ratio_qdelta = 2.0;
|
||||
cr->rate_boost_fac = 10;
|
||||
}
|
||||
// Adjust some parameters for low resolutions.
|
||||
if (cm->width * cm->height <= 352 * 288) {
|
||||
if (rc->avg_frame_bandwidth < 3000) {
|
||||
cr->motion_thresh = 64;
|
||||
cr->rate_boost_fac = 13;
|
||||
} else {
|
||||
cr->max_qdelta_perc = 70;
|
||||
cr->rate_ratio_qdelta = VPXMAX(cr->rate_ratio_qdelta, 2.5);
|
||||
}
|
||||
}
|
||||
if (cpi->oxcf.rc_mode == VPX_VBR) {
|
||||
// To be adjusted for VBR mode, e.g., based on gf period and boost.
|
||||
// For now use smaller qp-delta (than CBR), no second boosted seg, and
|
||||
// turn-off (no refresh) on golden refresh (since it's already boosted).
|
||||
cr->percent_refresh = 10;
|
||||
cr->rate_ratio_qdelta = 1.5;
|
||||
cr->rate_boost_fac = 10;
|
||||
if (cpi->refresh_golden_frame == 1) {
|
||||
cr->percent_refresh = 0;
|
||||
cr->rate_ratio_qdelta = 1.0;
|
||||
}
|
||||
}
|
||||
// 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.
|
||||
// Use the target if its less. To be used for setting the base qp for the
|
||||
// frame in vp9_rc_regulate_q.
|
||||
target_refresh = cr->percent_refresh * cm->mi_rows * cm->mi_cols / 100;
|
||||
weight_segment_target = (double)(target_refresh) / num8x8bl;
|
||||
weight_segment = (double)((target_refresh + cr->actual_num_seg1_blocks +
|
||||
cr->actual_num_seg2_blocks) >>
|
||||
1) /
|
||||
num8x8bl;
|
||||
if (weight_segment_target < 7 * weight_segment / 8)
|
||||
weight_segment = weight_segment_target;
|
||||
// For screen-content: don't include target for the weight segment,
|
||||
// since for all flat areas the segment is reset, so its more accurate
|
||||
// to just use the previous actual number of seg blocks for the weight.
|
||||
if (cpi->oxcf.content == VP9E_CONTENT_SCREEN)
|
||||
weight_segment =
|
||||
(double)(cr->actual_num_seg1_blocks + cr->actual_num_seg2_blocks) /
|
||||
num8x8bl;
|
||||
cr->weight_segment = weight_segment;
|
||||
}
|
||||
|
||||
// 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;
|
||||
int scene_change_detected =
|
||||
cpi->rc.high_source_sad ||
|
||||
(cpi->use_svc && cpi->svc.high_source_sad_superframe);
|
||||
if (cm->current_video_frame == 0) cr->low_content_avg = 0.0;
|
||||
// Reset if resoluton change has occurred.
|
||||
if (cpi->resize_pending != 0) vp9_cyclic_refresh_reset_resize(cpi);
|
||||
if (!cr->apply_cyclic_refresh || (cpi->force_update_segmentation) ||
|
||||
scene_change_detected) {
|
||||
// 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 || scene_change_detected) {
|
||||
memset(cr->last_coded_q_map, MAXQ,
|
||||
cm->mi_rows * cm->mi_cols * sizeof(*cr->last_coded_q_map));
|
||||
cr->sb_index = 0;
|
||||
cr->reduce_refresh = 0;
|
||||
cr->counter_encode_maxq_scene_change = 0;
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
int qindex_delta = 0;
|
||||
int qindex2;
|
||||
const double q = vp9_convert_qindex_to_q(cm->base_qindex, cm->bit_depth);
|
||||
cr->counter_encode_maxq_scene_change++;
|
||||
vpx_clear_system_state();
|
||||
// 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;
|
||||
|
||||
// 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[1] = 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,
|
||||
VPXMIN(CR_MAX_RATE_TARGET_RATIO,
|
||||
0.1 * cr->rate_boost_fac * cr->rate_ratio_qdelta));
|
||||
cr->qindex_delta[2] = 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;
|
||||
}
|
||||
|
||||
void vp9_cyclic_refresh_reset_resize(VP9_COMP *const cpi) {
|
||||
const VP9_COMMON *const cm = &cpi->common;
|
||||
CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
|
||||
memset(cr->map, 0, cm->mi_rows * cm->mi_cols);
|
||||
memset(cr->last_coded_q_map, MAXQ,
|
||||
cm->mi_rows * cm->mi_cols * sizeof(*cr->last_coded_q_map));
|
||||
cr->sb_index = 0;
|
||||
cpi->refresh_golden_frame = 1;
|
||||
cpi->refresh_alt_ref_frame = 1;
|
||||
cr->counter_encode_maxq_scene_change = 0;
|
||||
}
|
||||
|
||||
void vp9_cyclic_refresh_limit_q(const VP9_COMP *cpi, int *q) {
|
||||
CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
|
||||
// For now apply hard limit to frame-level decrease in q, if the cyclic
|
||||
// refresh is active (percent_refresh > 0).
|
||||
if (cr->percent_refresh > 0 && cpi->rc.q_1_frame - *q > 8) {
|
||||
*q = cpi->rc.q_1_frame - 8;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* 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 VPX_VP9_ENCODER_VP9_AQ_CYCLICREFRESH_H_
|
||||
#define VPX_VP9_ENCODER_VP9_AQ_CYCLICREFRESH_H_
|
||||
|
||||
#include "vpx/vpx_integer.h"
|
||||
#include "vp9/common/vp9_blockd.h"
|
||||
#include "vp9/encoder/vp9_block.h"
|
||||
#include "vp9/encoder/vp9_skin_detection.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
|
||||
|
||||
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;
|
||||
// Map of the last q a block was coded at.
|
||||
uint8_t *last_coded_q_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;
|
||||
// Boost factor for rate target ratio, for segment CR_SEGMENT_ID_BOOST2.
|
||||
int rate_boost_fac;
|
||||
double low_content_avg;
|
||||
int qindex_delta[3];
|
||||
int reduce_refresh;
|
||||
double weight_segment;
|
||||
int apply_cyclic_refresh;
|
||||
int counter_encode_maxq_scene_change;
|
||||
int skip_flat_static_blocks;
|
||||
};
|
||||
|
||||
struct VP9_COMP;
|
||||
|
||||
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,
|
||||
MODE_INFO *const mi, int mi_row,
|
||||
int mi_col, BLOCK_SIZE bsize,
|
||||
int64_t rate, int64_t dist, int skip,
|
||||
struct macroblock_plane *const p);
|
||||
|
||||
void vp9_cyclic_refresh_update_sb_postencode(struct VP9_COMP *const cpi,
|
||||
const MODE_INFO *const mi,
|
||||
int mi_row, int mi_col,
|
||||
BLOCK_SIZE bsize);
|
||||
|
||||
// From the just encoded frame: update the actual number of blocks that were
|
||||
// applied the segment delta q, and the amount of low motion in the frame.
|
||||
// Also check conditions for forcing golden update, or preventing golden
|
||||
// update if the period is up.
|
||||
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);
|
||||
|
||||
// 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);
|
||||
|
||||
void vp9_cyclic_refresh_reset_resize(struct VP9_COMP *const cpi);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void vp9_cyclic_refresh_limit_q(const struct VP9_COMP *cpi, int *q);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_ENCODER_VP9_AQ_CYCLICREFRESH_H_
|
||||
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
* 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 "vpx_ports/system_state.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_encodeframe.h"
|
||||
#include "vp9/encoder/vp9_segmentation.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 (frame_is_intra_only(cm) || cm->error_resilient_mode ||
|
||||
cpi->refresh_alt_ref_frame || cpi->force_update_segmentation ||
|
||||
(cpi->refresh_golden_frame && !cpi->rc.is_src_frame_alt_ref)) {
|
||||
vp9_enable_segmentation(seg);
|
||||
vp9_clearall_segfeatures(seg);
|
||||
|
||||
seg->abs_delta = SEGMENT_DELTADATA;
|
||||
|
||||
vpx_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, int64_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;
|
||||
}
|
||||
}
|
||||
|
||||
#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) {
|
||||
uint64_t sse64 = 0;
|
||||
int64_t sum64 = 0;
|
||||
aq_highbd_variance64(x->plane[0].src.buf, x->plane[0].src.stride,
|
||||
CONVERT_TO_BYTEPTR(vp9_highbd_64_zeros), 0, bw, bh,
|
||||
&sse64, &sum64);
|
||||
sse = (unsigned int)(sse64 >> (2 * (xd->bd - 8)));
|
||||
avg = (int)(sum64 >> (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 - (unsigned int)(((int64_t)avg * avg) / (bw * bh));
|
||||
return (unsigned int)(((uint64_t)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 (unsigned int)(((uint64_t)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);
|
||||
vpx_clear_system_state();
|
||||
return log(var + 1.0);
|
||||
}
|
||||
|
||||
// Get the range of sub block energy values;
|
||||
void vp9_get_sub_block_energy(VP9_COMP *cpi, MACROBLOCK *mb, int mi_row,
|
||||
int mi_col, BLOCK_SIZE bsize, int *min_e,
|
||||
int *max_e) {
|
||||
VP9_COMMON *const cm = &cpi->common;
|
||||
const int bw = num_8x8_blocks_wide_lookup[bsize];
|
||||
const int bh = num_8x8_blocks_high_lookup[bsize];
|
||||
const int xmis = VPXMIN(cm->mi_cols - mi_col, bw);
|
||||
const int ymis = VPXMIN(cm->mi_rows - mi_row, bh);
|
||||
int x, y;
|
||||
|
||||
if (xmis < bw || ymis < bh) {
|
||||
vp9_setup_src_planes(mb, cpi->Source, mi_row, mi_col);
|
||||
*min_e = vp9_block_energy(cpi, mb, bsize);
|
||||
*max_e = *min_e;
|
||||
} else {
|
||||
int energy;
|
||||
*min_e = ENERGY_MAX;
|
||||
*max_e = ENERGY_MIN;
|
||||
|
||||
for (y = 0; y < ymis; ++y) {
|
||||
for (x = 0; x < xmis; ++x) {
|
||||
vp9_setup_src_planes(mb, cpi->Source, mi_row + y, mi_col + x);
|
||||
energy = vp9_block_energy(cpi, mb, BLOCK_8X8);
|
||||
*min_e = VPXMIN(*min_e, energy);
|
||||
*max_e = VPXMAX(*max_e, energy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Re-instate source pointers back to what they should have been on entry.
|
||||
vp9_setup_src_planes(mb, cpi->Source, mi_row, mi_col);
|
||||
}
|
||||
|
||||
#define DEFAULT_E_MIDPOINT 10.0
|
||||
int vp9_block_energy(VP9_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bs) {
|
||||
double energy;
|
||||
double energy_midpoint;
|
||||
vpx_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);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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 VPX_VP9_ENCODER_VP9_AQ_VARIANCE_H_
|
||||
#define VPX_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);
|
||||
|
||||
void vp9_get_sub_block_energy(VP9_COMP *cpi, MACROBLOCK *mb, int mi_row,
|
||||
int mi_col, BLOCK_SIZE bsize, int *min_e,
|
||||
int *max_e);
|
||||
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 // VPX_VP9_ENCODER_VP9_AQ_VARIANCE_H_
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user