(77d1794a) Tester's build January 10th, 2020
This commit is contained in:
@@ -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
@@ -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_ENCODER_VP9_BITSTREAM_H_
|
||||
#define VPX_VP9_ENCODER_VP9_BITSTREAM_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "vp9/encoder/vp9_encoder.h"
|
||||
|
||||
typedef struct VP9BitstreamWorkerData {
|
||||
uint8_t *dest;
|
||||
int dest_size;
|
||||
vpx_writer bit_writer;
|
||||
int tile_idx;
|
||||
unsigned int max_mv_magnitude;
|
||||
// The size of interp_filter_selected in VP9_COMP is actually
|
||||
// MAX_REFERENCE_FRAMES x SWITCHABLE. But when encoding tiles, all we ever do
|
||||
// is increment the very first index (index 0) for the first dimension. Hence
|
||||
// this is sufficient.
|
||||
int interp_filter_selected[1][SWITCHABLE];
|
||||
DECLARE_ALIGNED(16, MACROBLOCKD, xd);
|
||||
} VP9BitstreamWorkerData;
|
||||
|
||||
int vp9_get_refresh_mask(VP9_COMP *cpi);
|
||||
|
||||
void vp9_bitstream_encode_tiles_buffer_dealloc(VP9_COMP *const cpi);
|
||||
|
||||
void vp9_pack_bitstream(VP9_COMP *cpi, uint8_t *dest, size_t *size);
|
||||
|
||||
static INLINE int vp9_preserve_existing_gf(VP9_COMP *cpi) {
|
||||
return cpi->refresh_golden_frame && cpi->rc.is_src_frame_alt_ref &&
|
||||
!cpi->use_svc;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_ENCODER_VP9_BITSTREAM_H_
|
||||
@@ -0,0 +1,221 @@
|
||||
/*
|
||||
* 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_ENCODER_VP9_BLOCK_H_
|
||||
#define VPX_VP9_ENCODER_VP9_BLOCK_H_
|
||||
|
||||
#include "vpx_util/vpx_thread.h"
|
||||
|
||||
#include "vp9/common/vp9_entropymv.h"
|
||||
#include "vp9/common/vp9_entropy.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
unsigned int sse;
|
||||
int sum;
|
||||
unsigned int var;
|
||||
} diff;
|
||||
|
||||
struct macroblock_plane {
|
||||
DECLARE_ALIGNED(16, int16_t, src_diff[64 * 64]);
|
||||
tran_low_t *qcoeff;
|
||||
tran_low_t *coeff;
|
||||
uint16_t *eobs;
|
||||
struct buf_2d src;
|
||||
|
||||
// Quantizer setings
|
||||
DECLARE_ALIGNED(16, int16_t, round_fp[8]);
|
||||
int16_t *quant_fp;
|
||||
int16_t *quant;
|
||||
int16_t *quant_shift;
|
||||
int16_t *zbin;
|
||||
int16_t *round;
|
||||
|
||||
int64_t quant_thred[2];
|
||||
};
|
||||
|
||||
/* The [2] dimension is for whether we skip the EOB node (i.e. if previous
|
||||
* coefficient in this block was zero) or not. */
|
||||
typedef unsigned int vp9_coeff_cost[PLANE_TYPES][REF_TYPES][COEF_BANDS][2]
|
||||
[COEFF_CONTEXTS][ENTROPY_TOKENS];
|
||||
|
||||
typedef struct {
|
||||
int_mv ref_mvs[MAX_REF_FRAMES][MAX_MV_REF_CANDIDATES];
|
||||
uint8_t mode_context[MAX_REF_FRAMES];
|
||||
} MB_MODE_INFO_EXT;
|
||||
|
||||
typedef struct {
|
||||
int col_min;
|
||||
int col_max;
|
||||
int row_min;
|
||||
int row_max;
|
||||
} MvLimits;
|
||||
|
||||
typedef struct macroblock MACROBLOCK;
|
||||
struct macroblock {
|
||||
// cf. https://bugs.chromium.org/p/webm/issues/detail?id=1054
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
int64_t bsse[MAX_MB_PLANE << 2];
|
||||
#endif
|
||||
|
||||
struct macroblock_plane plane[MAX_MB_PLANE];
|
||||
|
||||
MACROBLOCKD e_mbd;
|
||||
MB_MODE_INFO_EXT *mbmi_ext;
|
||||
MB_MODE_INFO_EXT *mbmi_ext_base;
|
||||
int skip_block;
|
||||
int select_tx_size;
|
||||
int skip_recode;
|
||||
int skip_optimize;
|
||||
int q_index;
|
||||
int block_qcoeff_opt;
|
||||
int block_tx_domain;
|
||||
|
||||
// The equivalent error at the current rdmult of one whole bit (not one
|
||||
// bitcost unit).
|
||||
int errorperbit;
|
||||
// The equivalend SAD error of one (whole) bit at the current quantizer
|
||||
// for large blocks.
|
||||
int sadperbit16;
|
||||
// The equivalend SAD error of one (whole) bit at the current quantizer
|
||||
// for sub-8x8 blocks.
|
||||
int sadperbit4;
|
||||
int rddiv;
|
||||
int rdmult;
|
||||
int cb_rdmult;
|
||||
int segment_id;
|
||||
int mb_energy;
|
||||
|
||||
// These are set to their default values at the beginning, and then adjusted
|
||||
// further in the encoding process.
|
||||
BLOCK_SIZE min_partition_size;
|
||||
BLOCK_SIZE max_partition_size;
|
||||
|
||||
int mv_best_ref_index[MAX_REF_FRAMES];
|
||||
unsigned int max_mv_context[MAX_REF_FRAMES];
|
||||
unsigned int source_variance;
|
||||
unsigned int pred_sse[MAX_REF_FRAMES];
|
||||
int pred_mv_sad[MAX_REF_FRAMES];
|
||||
|
||||
int nmvjointcost[MV_JOINTS];
|
||||
int *nmvcost[2];
|
||||
int *nmvcost_hp[2];
|
||||
int **mvcost;
|
||||
|
||||
int nmvjointsadcost[MV_JOINTS];
|
||||
int *nmvsadcost[2];
|
||||
int *nmvsadcost_hp[2];
|
||||
int **mvsadcost;
|
||||
|
||||
// sharpness is used to disable skip mode and change rd_mult
|
||||
int sharpness;
|
||||
|
||||
// aq mode is used to adjust rd based on segment.
|
||||
int adjust_rdmult_by_segment;
|
||||
|
||||
// These define limits to motion vector components to prevent them
|
||||
// from extending outside the UMV borders
|
||||
MvLimits mv_limits;
|
||||
|
||||
// Notes transform blocks where no coefficents are coded.
|
||||
// Set during mode selection. Read during block encoding.
|
||||
uint8_t zcoeff_blk[TX_SIZES][256];
|
||||
|
||||
// Accumulate the tx block eobs in a partition block.
|
||||
int32_t sum_y_eobs[TX_SIZES];
|
||||
|
||||
int skip;
|
||||
|
||||
int encode_breakout;
|
||||
|
||||
// note that token_costs is the cost when eob node is skipped
|
||||
vp9_coeff_cost token_costs[TX_SIZES];
|
||||
|
||||
int optimize;
|
||||
|
||||
// indicate if it is in the rd search loop or encoding process
|
||||
int use_lp32x32fdct;
|
||||
int skip_encode;
|
||||
|
||||
// In first pass, intra prediction is done based on source pixels
|
||||
// at tile boundaries
|
||||
int fp_src_pred;
|
||||
|
||||
// use fast quantization process
|
||||
int quant_fp;
|
||||
|
||||
// skip forward transform and quantization
|
||||
uint8_t skip_txfm[MAX_MB_PLANE << 2];
|
||||
#define SKIP_TXFM_NONE 0
|
||||
#define SKIP_TXFM_AC_DC 1
|
||||
#define SKIP_TXFM_AC_ONLY 2
|
||||
|
||||
// cf. https://bugs.chromium.org/p/webm/issues/detail?id=1054
|
||||
#if !defined(_MSC_VER) || _MSC_VER >= 1900
|
||||
int64_t bsse[MAX_MB_PLANE << 2];
|
||||
#endif
|
||||
|
||||
// Used to store sub partition's choices.
|
||||
MV pred_mv[MAX_REF_FRAMES];
|
||||
|
||||
// Strong color activity detection. Used in RTC coding mode to enhance
|
||||
// the visual quality at the boundary of moving color objects.
|
||||
uint8_t color_sensitivity[2];
|
||||
|
||||
uint8_t sb_is_skin;
|
||||
|
||||
uint8_t skip_low_source_sad;
|
||||
|
||||
uint8_t lowvar_highsumdiff;
|
||||
|
||||
uint8_t last_sb_high_content;
|
||||
|
||||
int sb_use_mv_part;
|
||||
|
||||
int sb_mvcol_part;
|
||||
|
||||
int sb_mvrow_part;
|
||||
|
||||
int sb_pickmode_part;
|
||||
|
||||
int zero_temp_sad_source;
|
||||
|
||||
// For each superblock: saves the content value (e.g., low/high sad/sumdiff)
|
||||
// based on source sad, prior to encoding the frame.
|
||||
uint8_t content_state_sb;
|
||||
|
||||
// Used to save the status of whether a block has a low variance in
|
||||
// choose_partitioning. 0 for 64x64, 1~2 for 64x32, 3~4 for 32x64, 5~8 for
|
||||
// 32x32, 9~24 for 16x16.
|
||||
uint8_t variance_low[25];
|
||||
|
||||
uint8_t arf_frame_usage;
|
||||
uint8_t lastgolden_frame_usage;
|
||||
|
||||
void (*fwd_txfm4x4)(const int16_t *input, tran_low_t *output, int stride);
|
||||
void (*inv_txfm_add)(const tran_low_t *input, uint8_t *dest, int stride,
|
||||
int eob);
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
void (*highbd_inv_txfm_add)(const tran_low_t *input, uint16_t *dest,
|
||||
int stride, int eob, int bd);
|
||||
#endif
|
||||
DECLARE_ALIGNED(16, uint8_t, est_pred[64 * 64]);
|
||||
|
||||
struct scale_factors *me_sf;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_ENCODER_VP9_BLOCK_H_
|
||||
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* 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 <stdlib.h>
|
||||
|
||||
#include "vpx/vpx_integer.h"
|
||||
#include "vpx_ports/system_state.h"
|
||||
#include "vp9/encoder/vp9_blockiness.h"
|
||||
|
||||
static int horizontal_filter(const uint8_t *s) {
|
||||
return (s[1] - s[-2]) * 2 + (s[-1] - s[0]) * 6;
|
||||
}
|
||||
|
||||
static int vertical_filter(const uint8_t *s, int p) {
|
||||
return (s[p] - s[-2 * p]) * 2 + (s[-p] - s[0]) * 6;
|
||||
}
|
||||
|
||||
static int variance(int sum, int sum_squared, int size) {
|
||||
return sum_squared / size - (sum / size) * (sum / size);
|
||||
}
|
||||
// Calculate a blockiness level for a vertical block edge.
|
||||
// This function returns a new blockiness metric that's defined as
|
||||
|
||||
// p0 p1 p2 p3
|
||||
// q0 q1 q2 q3
|
||||
// block edge ->
|
||||
// r0 r1 r2 r3
|
||||
// s0 s1 s2 s3
|
||||
|
||||
// blockiness = p0*-2+q0*6+r0*-6+s0*2 +
|
||||
// p1*-2+q1*6+r1*-6+s1*2 +
|
||||
// p2*-2+q2*6+r2*-6+s2*2 +
|
||||
// p3*-2+q3*6+r3*-6+s3*2 ;
|
||||
|
||||
// reconstructed_blockiness = abs(blockiness from reconstructed buffer -
|
||||
// blockiness from source buffer,0)
|
||||
//
|
||||
// I make the assumption that flat blocks are much more visible than high
|
||||
// contrast blocks. As such, I scale the result of the blockiness calc
|
||||
// by dividing the blockiness by the variance of the pixels on either side
|
||||
// of the edge as follows:
|
||||
// var_0 = (q0^2+q1^2+q2^2+q3^2) - ((q0 + q1 + q2 + q3) / 4 )^2
|
||||
// var_1 = (r0^2+r1^2+r2^2+r3^2) - ((r0 + r1 + r2 + r3) / 4 )^2
|
||||
// The returned blockiness is the scaled value
|
||||
// Reconstructed blockiness / ( 1 + var_0 + var_1 ) ;
|
||||
static int blockiness_vertical(const uint8_t *s, int sp, const uint8_t *r,
|
||||
int rp, int size) {
|
||||
int s_blockiness = 0;
|
||||
int r_blockiness = 0;
|
||||
int sum_0 = 0;
|
||||
int sum_sq_0 = 0;
|
||||
int sum_1 = 0;
|
||||
int sum_sq_1 = 0;
|
||||
int i;
|
||||
int var_0;
|
||||
int var_1;
|
||||
for (i = 0; i < size; ++i, s += sp, r += rp) {
|
||||
s_blockiness += horizontal_filter(s);
|
||||
r_blockiness += horizontal_filter(r);
|
||||
sum_0 += s[0];
|
||||
sum_sq_0 += s[0] * s[0];
|
||||
sum_1 += s[-1];
|
||||
sum_sq_1 += s[-1] * s[-1];
|
||||
}
|
||||
var_0 = variance(sum_0, sum_sq_0, size);
|
||||
var_1 = variance(sum_1, sum_sq_1, size);
|
||||
r_blockiness = abs(r_blockiness);
|
||||
s_blockiness = abs(s_blockiness);
|
||||
|
||||
if (r_blockiness > s_blockiness)
|
||||
return (r_blockiness - s_blockiness) / (1 + var_0 + var_1);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Calculate a blockiness level for a horizontal block edge
|
||||
// same as above.
|
||||
static int blockiness_horizontal(const uint8_t *s, int sp, const uint8_t *r,
|
||||
int rp, int size) {
|
||||
int s_blockiness = 0;
|
||||
int r_blockiness = 0;
|
||||
int sum_0 = 0;
|
||||
int sum_sq_0 = 0;
|
||||
int sum_1 = 0;
|
||||
int sum_sq_1 = 0;
|
||||
int i;
|
||||
int var_0;
|
||||
int var_1;
|
||||
for (i = 0; i < size; ++i, ++s, ++r) {
|
||||
s_blockiness += vertical_filter(s, sp);
|
||||
r_blockiness += vertical_filter(r, rp);
|
||||
sum_0 += s[0];
|
||||
sum_sq_0 += s[0] * s[0];
|
||||
sum_1 += s[-sp];
|
||||
sum_sq_1 += s[-sp] * s[-sp];
|
||||
}
|
||||
var_0 = variance(sum_0, sum_sq_0, size);
|
||||
var_1 = variance(sum_1, sum_sq_1, size);
|
||||
r_blockiness = abs(r_blockiness);
|
||||
s_blockiness = abs(s_blockiness);
|
||||
|
||||
if (r_blockiness > s_blockiness)
|
||||
return (r_blockiness - s_blockiness) / (1 + var_0 + var_1);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
// This function returns the blockiness for the entire frame currently by
|
||||
// looking at all borders in steps of 4.
|
||||
double vp9_get_blockiness(const uint8_t *img1, int img1_pitch,
|
||||
const uint8_t *img2, int img2_pitch, int width,
|
||||
int height) {
|
||||
double blockiness = 0;
|
||||
int i, j;
|
||||
vpx_clear_system_state();
|
||||
for (i = 0; i < height;
|
||||
i += 4, img1 += img1_pitch * 4, img2 += img2_pitch * 4) {
|
||||
for (j = 0; j < width; j += 4) {
|
||||
if (i > 0 && i < height && j > 0 && j < width) {
|
||||
blockiness +=
|
||||
blockiness_vertical(img1 + j, img1_pitch, img2 + j, img2_pitch, 4);
|
||||
blockiness += blockiness_horizontal(img1 + j, img1_pitch, img2 + j,
|
||||
img2_pitch, 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
blockiness /= width * height / 16;
|
||||
return blockiness;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2019 The WebM project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can 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_BLOCKINESS_H_
|
||||
#define VPX_VP9_ENCODER_VP9_BLOCKINESS_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
double vp9_get_blockiness(const uint8_t *img1, int img1_pitch,
|
||||
const uint8_t *img2, int img2_pitch, int width,
|
||||
int height);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_ENCODER_VP9_BLOCKINESS_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 "vp9/encoder/vp9_context_tree.h"
|
||||
#include "vp9/encoder/vp9_encoder.h"
|
||||
|
||||
static const BLOCK_SIZE square[] = {
|
||||
BLOCK_8X8,
|
||||
BLOCK_16X16,
|
||||
BLOCK_32X32,
|
||||
BLOCK_64X64,
|
||||
};
|
||||
|
||||
static void alloc_mode_context(VP9_COMMON *cm, int num_4x4_blk,
|
||||
PICK_MODE_CONTEXT *ctx) {
|
||||
const int num_blk = (num_4x4_blk < 4 ? 4 : num_4x4_blk);
|
||||
const int num_pix = num_blk << 4;
|
||||
int i, k;
|
||||
ctx->num_4x4_blk = num_blk;
|
||||
|
||||
CHECK_MEM_ERROR(cm, ctx->zcoeff_blk, vpx_calloc(num_blk, sizeof(uint8_t)));
|
||||
for (i = 0; i < MAX_MB_PLANE; ++i) {
|
||||
for (k = 0; k < 3; ++k) {
|
||||
CHECK_MEM_ERROR(cm, ctx->coeff[i][k],
|
||||
vpx_memalign(32, num_pix * sizeof(*ctx->coeff[i][k])));
|
||||
CHECK_MEM_ERROR(cm, ctx->qcoeff[i][k],
|
||||
vpx_memalign(32, num_pix * sizeof(*ctx->qcoeff[i][k])));
|
||||
CHECK_MEM_ERROR(cm, ctx->dqcoeff[i][k],
|
||||
vpx_memalign(32, num_pix * sizeof(*ctx->dqcoeff[i][k])));
|
||||
CHECK_MEM_ERROR(cm, ctx->eobs[i][k],
|
||||
vpx_memalign(32, num_blk * sizeof(*ctx->eobs[i][k])));
|
||||
ctx->coeff_pbuf[i][k] = ctx->coeff[i][k];
|
||||
ctx->qcoeff_pbuf[i][k] = ctx->qcoeff[i][k];
|
||||
ctx->dqcoeff_pbuf[i][k] = ctx->dqcoeff[i][k];
|
||||
ctx->eobs_pbuf[i][k] = ctx->eobs[i][k];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void free_mode_context(PICK_MODE_CONTEXT *ctx) {
|
||||
int i, k;
|
||||
vpx_free(ctx->zcoeff_blk);
|
||||
ctx->zcoeff_blk = 0;
|
||||
for (i = 0; i < MAX_MB_PLANE; ++i) {
|
||||
for (k = 0; k < 3; ++k) {
|
||||
vpx_free(ctx->coeff[i][k]);
|
||||
ctx->coeff[i][k] = 0;
|
||||
vpx_free(ctx->qcoeff[i][k]);
|
||||
ctx->qcoeff[i][k] = 0;
|
||||
vpx_free(ctx->dqcoeff[i][k]);
|
||||
ctx->dqcoeff[i][k] = 0;
|
||||
vpx_free(ctx->eobs[i][k]);
|
||||
ctx->eobs[i][k] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void alloc_tree_contexts(VP9_COMMON *cm, PC_TREE *tree,
|
||||
int num_4x4_blk) {
|
||||
alloc_mode_context(cm, num_4x4_blk, &tree->none);
|
||||
alloc_mode_context(cm, num_4x4_blk / 2, &tree->horizontal[0]);
|
||||
alloc_mode_context(cm, num_4x4_blk / 2, &tree->vertical[0]);
|
||||
|
||||
if (num_4x4_blk > 4) {
|
||||
alloc_mode_context(cm, num_4x4_blk / 2, &tree->horizontal[1]);
|
||||
alloc_mode_context(cm, num_4x4_blk / 2, &tree->vertical[1]);
|
||||
} else {
|
||||
memset(&tree->horizontal[1], 0, sizeof(tree->horizontal[1]));
|
||||
memset(&tree->vertical[1], 0, sizeof(tree->vertical[1]));
|
||||
}
|
||||
}
|
||||
|
||||
static void free_tree_contexts(PC_TREE *tree) {
|
||||
free_mode_context(&tree->none);
|
||||
free_mode_context(&tree->horizontal[0]);
|
||||
free_mode_context(&tree->horizontal[1]);
|
||||
free_mode_context(&tree->vertical[0]);
|
||||
free_mode_context(&tree->vertical[1]);
|
||||
}
|
||||
|
||||
// This function sets up a tree of contexts such that at each square
|
||||
// partition level. There are contexts for none, horizontal, vertical, and
|
||||
// split. Along with a block_size value and a selected block_size which
|
||||
// represents the state of our search.
|
||||
void vp9_setup_pc_tree(VP9_COMMON *cm, ThreadData *td) {
|
||||
int i, j;
|
||||
const int leaf_nodes = 64;
|
||||
const int tree_nodes = 64 + 16 + 4 + 1;
|
||||
int pc_tree_index = 0;
|
||||
PC_TREE *this_pc;
|
||||
PICK_MODE_CONTEXT *this_leaf;
|
||||
int square_index = 1;
|
||||
int nodes;
|
||||
|
||||
vpx_free(td->leaf_tree);
|
||||
CHECK_MEM_ERROR(cm, td->leaf_tree,
|
||||
vpx_calloc(leaf_nodes, sizeof(*td->leaf_tree)));
|
||||
vpx_free(td->pc_tree);
|
||||
CHECK_MEM_ERROR(cm, td->pc_tree,
|
||||
vpx_calloc(tree_nodes, sizeof(*td->pc_tree)));
|
||||
|
||||
this_pc = &td->pc_tree[0];
|
||||
this_leaf = &td->leaf_tree[0];
|
||||
|
||||
// 4x4 blocks smaller than 8x8 but in the same 8x8 block share the same
|
||||
// context so we only need to allocate 1 for each 8x8 block.
|
||||
for (i = 0; i < leaf_nodes; ++i) alloc_mode_context(cm, 1, &td->leaf_tree[i]);
|
||||
|
||||
// Sets up all the leaf nodes in the tree.
|
||||
for (pc_tree_index = 0; pc_tree_index < leaf_nodes; ++pc_tree_index) {
|
||||
PC_TREE *const tree = &td->pc_tree[pc_tree_index];
|
||||
tree->block_size = square[0];
|
||||
alloc_tree_contexts(cm, tree, 4);
|
||||
tree->leaf_split[0] = this_leaf++;
|
||||
for (j = 1; j < 4; j++) tree->leaf_split[j] = tree->leaf_split[0];
|
||||
}
|
||||
|
||||
// Each node has 4 leaf nodes, fill each block_size level of the tree
|
||||
// from leafs to the root.
|
||||
for (nodes = 16; nodes > 0; nodes >>= 2) {
|
||||
for (i = 0; i < nodes; ++i) {
|
||||
PC_TREE *const tree = &td->pc_tree[pc_tree_index];
|
||||
alloc_tree_contexts(cm, tree, 4 << (2 * square_index));
|
||||
tree->block_size = square[square_index];
|
||||
for (j = 0; j < 4; j++) tree->split[j] = this_pc++;
|
||||
++pc_tree_index;
|
||||
}
|
||||
++square_index;
|
||||
}
|
||||
td->pc_root = &td->pc_tree[tree_nodes - 1];
|
||||
td->pc_root[0].none.best_mode_index = 2;
|
||||
}
|
||||
|
||||
void vp9_free_pc_tree(ThreadData *td) {
|
||||
int i;
|
||||
|
||||
if (td == NULL) return;
|
||||
|
||||
if (td->leaf_tree != NULL) {
|
||||
// Set up all 4x4 mode contexts
|
||||
for (i = 0; i < 64; ++i) free_mode_context(&td->leaf_tree[i]);
|
||||
vpx_free(td->leaf_tree);
|
||||
td->leaf_tree = NULL;
|
||||
}
|
||||
|
||||
if (td->pc_tree != NULL) {
|
||||
const int tree_nodes = 64 + 16 + 4 + 1;
|
||||
// Sets up all the leaf nodes in the tree.
|
||||
for (i = 0; i < tree_nodes; ++i) free_tree_contexts(&td->pc_tree[i]);
|
||||
vpx_free(td->pc_tree);
|
||||
td->pc_tree = NULL;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* 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_CONTEXT_TREE_H_
|
||||
#define VPX_VP9_ENCODER_VP9_CONTEXT_TREE_H_
|
||||
|
||||
#include "vp9/common/vp9_blockd.h"
|
||||
#include "vp9/encoder/vp9_block.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct VP9_COMP;
|
||||
struct VP9Common;
|
||||
struct ThreadData;
|
||||
|
||||
// Structure to hold snapshot of coding context during the mode picking process
|
||||
typedef struct {
|
||||
MODE_INFO mic;
|
||||
MB_MODE_INFO_EXT mbmi_ext;
|
||||
uint8_t *zcoeff_blk;
|
||||
tran_low_t *coeff[MAX_MB_PLANE][3];
|
||||
tran_low_t *qcoeff[MAX_MB_PLANE][3];
|
||||
tran_low_t *dqcoeff[MAX_MB_PLANE][3];
|
||||
uint16_t *eobs[MAX_MB_PLANE][3];
|
||||
|
||||
// dual buffer pointers, 0: in use, 1: best in store
|
||||
tran_low_t *coeff_pbuf[MAX_MB_PLANE][3];
|
||||
tran_low_t *qcoeff_pbuf[MAX_MB_PLANE][3];
|
||||
tran_low_t *dqcoeff_pbuf[MAX_MB_PLANE][3];
|
||||
uint16_t *eobs_pbuf[MAX_MB_PLANE][3];
|
||||
|
||||
int is_coded;
|
||||
int num_4x4_blk;
|
||||
int skip;
|
||||
int pred_pixel_ready;
|
||||
// For current partition, only if all Y, U, and V transform blocks'
|
||||
// coefficients are quantized to 0, skippable is set to 0.
|
||||
int skippable;
|
||||
uint8_t skip_txfm[MAX_MB_PLANE << 2];
|
||||
int best_mode_index;
|
||||
int hybrid_pred_diff;
|
||||
int comp_pred_diff;
|
||||
int single_pred_diff;
|
||||
int64_t best_filter_diff[SWITCHABLE_FILTER_CONTEXTS];
|
||||
|
||||
// TODO(jingning) Use RD_COST struct here instead. This involves a boarder
|
||||
// scope of refactoring.
|
||||
int rate;
|
||||
int64_t dist;
|
||||
int64_t rdcost;
|
||||
|
||||
#if CONFIG_VP9_TEMPORAL_DENOISING
|
||||
unsigned int newmv_sse;
|
||||
unsigned int zeromv_sse;
|
||||
unsigned int zeromv_lastref_sse;
|
||||
PREDICTION_MODE best_sse_inter_mode;
|
||||
int_mv best_sse_mv;
|
||||
MV_REFERENCE_FRAME best_reference_frame;
|
||||
MV_REFERENCE_FRAME best_zeromv_reference_frame;
|
||||
int sb_skip_denoising;
|
||||
#endif
|
||||
|
||||
// motion vector cache for adaptive motion search control in partition
|
||||
// search loop
|
||||
MV pred_mv[MAX_REF_FRAMES];
|
||||
INTERP_FILTER pred_interp_filter;
|
||||
|
||||
// Used for the machine learning-based early termination
|
||||
int32_t sum_y_eobs;
|
||||
// Skip certain ref frames during RD search of rectangular partitions.
|
||||
uint8_t skip_ref_frame_mask;
|
||||
} PICK_MODE_CONTEXT;
|
||||
|
||||
typedef struct PC_TREE {
|
||||
int index;
|
||||
PARTITION_TYPE partitioning;
|
||||
BLOCK_SIZE block_size;
|
||||
PICK_MODE_CONTEXT none;
|
||||
PICK_MODE_CONTEXT horizontal[2];
|
||||
PICK_MODE_CONTEXT vertical[2];
|
||||
union {
|
||||
struct PC_TREE *split[4];
|
||||
PICK_MODE_CONTEXT *leaf_split[4];
|
||||
};
|
||||
// Obtained from a simple motion search. Used by the ML based partition search
|
||||
// speed feature.
|
||||
MV mv;
|
||||
} PC_TREE;
|
||||
|
||||
void vp9_setup_pc_tree(struct VP9Common *cm, struct ThreadData *td);
|
||||
void vp9_free_pc_tree(struct ThreadData *td);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_ENCODER_VP9_CONTEXT_TREE_H_
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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/encoder/vp9_cost.h"
|
||||
|
||||
/* round(-log2(i/256.) * (1 << VP9_PROB_COST_SHIFT))
|
||||
Begins with a bogus entry for simpler addressing. */
|
||||
const uint16_t vp9_prob_cost[256] = {
|
||||
4096, 4096, 3584, 3284, 3072, 2907, 2772, 2659, 2560, 2473, 2395, 2325, 2260,
|
||||
2201, 2147, 2096, 2048, 2003, 1961, 1921, 1883, 1847, 1813, 1780, 1748, 1718,
|
||||
1689, 1661, 1635, 1609, 1584, 1559, 1536, 1513, 1491, 1470, 1449, 1429, 1409,
|
||||
1390, 1371, 1353, 1335, 1318, 1301, 1284, 1268, 1252, 1236, 1221, 1206, 1192,
|
||||
1177, 1163, 1149, 1136, 1123, 1110, 1097, 1084, 1072, 1059, 1047, 1036, 1024,
|
||||
1013, 1001, 990, 979, 968, 958, 947, 937, 927, 917, 907, 897, 887,
|
||||
878, 868, 859, 850, 841, 832, 823, 814, 806, 797, 789, 780, 772,
|
||||
764, 756, 748, 740, 732, 724, 717, 709, 702, 694, 687, 680, 673,
|
||||
665, 658, 651, 644, 637, 631, 624, 617, 611, 604, 598, 591, 585,
|
||||
578, 572, 566, 560, 554, 547, 541, 535, 530, 524, 518, 512, 506,
|
||||
501, 495, 489, 484, 478, 473, 467, 462, 456, 451, 446, 441, 435,
|
||||
430, 425, 420, 415, 410, 405, 400, 395, 390, 385, 380, 375, 371,
|
||||
366, 361, 356, 352, 347, 343, 338, 333, 329, 324, 320, 316, 311,
|
||||
307, 302, 298, 294, 289, 285, 281, 277, 273, 268, 264, 260, 256,
|
||||
252, 248, 244, 240, 236, 232, 228, 224, 220, 216, 212, 209, 205,
|
||||
201, 197, 194, 190, 186, 182, 179, 175, 171, 168, 164, 161, 157,
|
||||
153, 150, 146, 143, 139, 136, 132, 129, 125, 122, 119, 115, 112,
|
||||
109, 105, 102, 99, 95, 92, 89, 86, 82, 79, 76, 73, 70,
|
||||
66, 63, 60, 57, 54, 51, 48, 45, 42, 38, 35, 32, 29,
|
||||
26, 23, 20, 18, 15, 12, 9, 6, 3
|
||||
};
|
||||
|
||||
static void cost(int *costs, vpx_tree tree, const vpx_prob *probs, int i,
|
||||
int c) {
|
||||
const vpx_prob prob = probs[i / 2];
|
||||
int b;
|
||||
|
||||
assert(prob != 0);
|
||||
for (b = 0; b <= 1; ++b) {
|
||||
const int cc = c + vp9_cost_bit(prob, b);
|
||||
const vpx_tree_index ii = tree[i + b];
|
||||
|
||||
if (ii <= 0)
|
||||
costs[-ii] = cc;
|
||||
else
|
||||
cost(costs, tree, probs, ii, cc);
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_cost_tokens(int *costs, const vpx_prob *probs, vpx_tree tree) {
|
||||
cost(costs, tree, probs, 0, 0);
|
||||
}
|
||||
|
||||
void vp9_cost_tokens_skip(int *costs, const vpx_prob *probs, vpx_tree tree) {
|
||||
assert(tree[0] <= 0 && tree[1] > 0);
|
||||
|
||||
costs[-tree[0]] = vp9_cost_bit(probs[0], 0);
|
||||
cost(costs, tree, probs, 2, 0);
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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_COST_H_
|
||||
#define VPX_VP9_ENCODER_VP9_COST_H_
|
||||
|
||||
#include "vpx_dsp/prob.h"
|
||||
#include "vpx/vpx_integer.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern const uint16_t vp9_prob_cost[256];
|
||||
|
||||
// The factor to scale from cost in bits to cost in vp9_prob_cost units.
|
||||
#define VP9_PROB_COST_SHIFT 9
|
||||
|
||||
#define vp9_cost_zero(prob) (vp9_prob_cost[prob])
|
||||
|
||||
#define vp9_cost_one(prob) vp9_cost_zero(256 - (prob))
|
||||
|
||||
#define vp9_cost_bit(prob, bit) vp9_cost_zero((bit) ? 256 - (prob) : (prob))
|
||||
|
||||
static INLINE unsigned int cost_branch256(const unsigned int ct[2],
|
||||
vpx_prob p) {
|
||||
return ct[0] * vp9_cost_zero(p) + ct[1] * vp9_cost_one(p);
|
||||
}
|
||||
|
||||
static INLINE int treed_cost(vpx_tree tree, const vpx_prob *probs, int bits,
|
||||
int len) {
|
||||
int cost = 0;
|
||||
vpx_tree_index i = 0;
|
||||
|
||||
do {
|
||||
const int bit = (bits >> --len) & 1;
|
||||
cost += vp9_cost_bit(probs[i >> 1], bit);
|
||||
i = tree[i + bit];
|
||||
} while (len);
|
||||
|
||||
return cost;
|
||||
}
|
||||
|
||||
void vp9_cost_tokens(int *costs, const vpx_prob *probs, vpx_tree tree);
|
||||
void vp9_cost_tokens_skip(int *costs, const vpx_prob *probs, vpx_tree tree);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_ENCODER_VP9_COST_H_
|
||||
@@ -0,0 +1,687 @@
|
||||
/*
|
||||
* Copyright (c) 2010 The WebM project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "./vp9_rtcd.h"
|
||||
#include "./vpx_config.h"
|
||||
#include "./vpx_dsp_rtcd.h"
|
||||
|
||||
#include "vp9/common/vp9_blockd.h"
|
||||
#include "vp9/common/vp9_idct.h"
|
||||
#include "vpx_dsp/fwd_txfm.h"
|
||||
#include "vpx_ports/mem.h"
|
||||
|
||||
static void fdct4(const tran_low_t *input, tran_low_t *output) {
|
||||
tran_high_t step[4];
|
||||
tran_high_t temp1, temp2;
|
||||
|
||||
step[0] = input[0] + input[3];
|
||||
step[1] = input[1] + input[2];
|
||||
step[2] = input[1] - input[2];
|
||||
step[3] = input[0] - input[3];
|
||||
|
||||
temp1 = (step[0] + step[1]) * cospi_16_64;
|
||||
temp2 = (step[0] - step[1]) * cospi_16_64;
|
||||
output[0] = (tran_low_t)fdct_round_shift(temp1);
|
||||
output[2] = (tran_low_t)fdct_round_shift(temp2);
|
||||
temp1 = step[2] * cospi_24_64 + step[3] * cospi_8_64;
|
||||
temp2 = -step[2] * cospi_8_64 + step[3] * cospi_24_64;
|
||||
output[1] = (tran_low_t)fdct_round_shift(temp1);
|
||||
output[3] = (tran_low_t)fdct_round_shift(temp2);
|
||||
}
|
||||
|
||||
static void fdct8(const tran_low_t *input, tran_low_t *output) {
|
||||
tran_high_t s0, s1, s2, s3, s4, s5, s6, s7; // canbe16
|
||||
tran_high_t t0, t1, t2, t3; // needs32
|
||||
tran_high_t x0, x1, x2, x3; // canbe16
|
||||
|
||||
// stage 1
|
||||
s0 = input[0] + input[7];
|
||||
s1 = input[1] + input[6];
|
||||
s2 = input[2] + input[5];
|
||||
s3 = input[3] + input[4];
|
||||
s4 = input[3] - input[4];
|
||||
s5 = input[2] - input[5];
|
||||
s6 = input[1] - input[6];
|
||||
s7 = input[0] - input[7];
|
||||
|
||||
// fdct4(step, step);
|
||||
x0 = s0 + s3;
|
||||
x1 = s1 + s2;
|
||||
x2 = s1 - s2;
|
||||
x3 = s0 - s3;
|
||||
t0 = (x0 + x1) * cospi_16_64;
|
||||
t1 = (x0 - x1) * cospi_16_64;
|
||||
t2 = x2 * cospi_24_64 + x3 * cospi_8_64;
|
||||
t3 = -x2 * cospi_8_64 + x3 * cospi_24_64;
|
||||
output[0] = (tran_low_t)fdct_round_shift(t0);
|
||||
output[2] = (tran_low_t)fdct_round_shift(t2);
|
||||
output[4] = (tran_low_t)fdct_round_shift(t1);
|
||||
output[6] = (tran_low_t)fdct_round_shift(t3);
|
||||
|
||||
// Stage 2
|
||||
t0 = (s6 - s5) * cospi_16_64;
|
||||
t1 = (s6 + s5) * cospi_16_64;
|
||||
t2 = (tran_low_t)fdct_round_shift(t0);
|
||||
t3 = (tran_low_t)fdct_round_shift(t1);
|
||||
|
||||
// Stage 3
|
||||
x0 = s4 + t2;
|
||||
x1 = s4 - t2;
|
||||
x2 = s7 - t3;
|
||||
x3 = s7 + t3;
|
||||
|
||||
// Stage 4
|
||||
t0 = x0 * cospi_28_64 + x3 * cospi_4_64;
|
||||
t1 = x1 * cospi_12_64 + x2 * cospi_20_64;
|
||||
t2 = x2 * cospi_12_64 + x1 * -cospi_20_64;
|
||||
t3 = x3 * cospi_28_64 + x0 * -cospi_4_64;
|
||||
output[1] = (tran_low_t)fdct_round_shift(t0);
|
||||
output[3] = (tran_low_t)fdct_round_shift(t2);
|
||||
output[5] = (tran_low_t)fdct_round_shift(t1);
|
||||
output[7] = (tran_low_t)fdct_round_shift(t3);
|
||||
}
|
||||
|
||||
static void fdct16(const tran_low_t in[16], tran_low_t out[16]) {
|
||||
tran_high_t step1[8]; // canbe16
|
||||
tran_high_t step2[8]; // canbe16
|
||||
tran_high_t step3[8]; // canbe16
|
||||
tran_high_t input[8]; // canbe16
|
||||
tran_high_t temp1, temp2; // needs32
|
||||
|
||||
// step 1
|
||||
input[0] = in[0] + in[15];
|
||||
input[1] = in[1] + in[14];
|
||||
input[2] = in[2] + in[13];
|
||||
input[3] = in[3] + in[12];
|
||||
input[4] = in[4] + in[11];
|
||||
input[5] = in[5] + in[10];
|
||||
input[6] = in[6] + in[9];
|
||||
input[7] = in[7] + in[8];
|
||||
|
||||
step1[0] = in[7] - in[8];
|
||||
step1[1] = in[6] - in[9];
|
||||
step1[2] = in[5] - in[10];
|
||||
step1[3] = in[4] - in[11];
|
||||
step1[4] = in[3] - in[12];
|
||||
step1[5] = in[2] - in[13];
|
||||
step1[6] = in[1] - in[14];
|
||||
step1[7] = in[0] - in[15];
|
||||
|
||||
// fdct8(step, step);
|
||||
{
|
||||
tran_high_t s0, s1, s2, s3, s4, s5, s6, s7; // canbe16
|
||||
tran_high_t t0, t1, t2, t3; // needs32
|
||||
tran_high_t x0, x1, x2, x3; // canbe16
|
||||
|
||||
// stage 1
|
||||
s0 = input[0] + input[7];
|
||||
s1 = input[1] + input[6];
|
||||
s2 = input[2] + input[5];
|
||||
s3 = input[3] + input[4];
|
||||
s4 = input[3] - input[4];
|
||||
s5 = input[2] - input[5];
|
||||
s6 = input[1] - input[6];
|
||||
s7 = input[0] - input[7];
|
||||
|
||||
// fdct4(step, step);
|
||||
x0 = s0 + s3;
|
||||
x1 = s1 + s2;
|
||||
x2 = s1 - s2;
|
||||
x3 = s0 - s3;
|
||||
t0 = (x0 + x1) * cospi_16_64;
|
||||
t1 = (x0 - x1) * cospi_16_64;
|
||||
t2 = x3 * cospi_8_64 + x2 * cospi_24_64;
|
||||
t3 = x3 * cospi_24_64 - x2 * cospi_8_64;
|
||||
out[0] = (tran_low_t)fdct_round_shift(t0);
|
||||
out[4] = (tran_low_t)fdct_round_shift(t2);
|
||||
out[8] = (tran_low_t)fdct_round_shift(t1);
|
||||
out[12] = (tran_low_t)fdct_round_shift(t3);
|
||||
|
||||
// Stage 2
|
||||
t0 = (s6 - s5) * cospi_16_64;
|
||||
t1 = (s6 + s5) * cospi_16_64;
|
||||
t2 = fdct_round_shift(t0);
|
||||
t3 = fdct_round_shift(t1);
|
||||
|
||||
// Stage 3
|
||||
x0 = s4 + t2;
|
||||
x1 = s4 - t2;
|
||||
x2 = s7 - t3;
|
||||
x3 = s7 + t3;
|
||||
|
||||
// Stage 4
|
||||
t0 = x0 * cospi_28_64 + x3 * cospi_4_64;
|
||||
t1 = x1 * cospi_12_64 + x2 * cospi_20_64;
|
||||
t2 = x2 * cospi_12_64 + x1 * -cospi_20_64;
|
||||
t3 = x3 * cospi_28_64 + x0 * -cospi_4_64;
|
||||
out[2] = (tran_low_t)fdct_round_shift(t0);
|
||||
out[6] = (tran_low_t)fdct_round_shift(t2);
|
||||
out[10] = (tran_low_t)fdct_round_shift(t1);
|
||||
out[14] = (tran_low_t)fdct_round_shift(t3);
|
||||
}
|
||||
|
||||
// step 2
|
||||
temp1 = (step1[5] - step1[2]) * cospi_16_64;
|
||||
temp2 = (step1[4] - step1[3]) * cospi_16_64;
|
||||
step2[2] = fdct_round_shift(temp1);
|
||||
step2[3] = fdct_round_shift(temp2);
|
||||
temp1 = (step1[4] + step1[3]) * cospi_16_64;
|
||||
temp2 = (step1[5] + step1[2]) * cospi_16_64;
|
||||
step2[4] = fdct_round_shift(temp1);
|
||||
step2[5] = fdct_round_shift(temp2);
|
||||
|
||||
// step 3
|
||||
step3[0] = step1[0] + step2[3];
|
||||
step3[1] = step1[1] + step2[2];
|
||||
step3[2] = step1[1] - step2[2];
|
||||
step3[3] = step1[0] - step2[3];
|
||||
step3[4] = step1[7] - step2[4];
|
||||
step3[5] = step1[6] - step2[5];
|
||||
step3[6] = step1[6] + step2[5];
|
||||
step3[7] = step1[7] + step2[4];
|
||||
|
||||
// step 4
|
||||
temp1 = step3[1] * -cospi_8_64 + step3[6] * cospi_24_64;
|
||||
temp2 = step3[2] * cospi_24_64 + step3[5] * cospi_8_64;
|
||||
step2[1] = fdct_round_shift(temp1);
|
||||
step2[2] = fdct_round_shift(temp2);
|
||||
temp1 = step3[2] * cospi_8_64 - step3[5] * cospi_24_64;
|
||||
temp2 = step3[1] * cospi_24_64 + step3[6] * cospi_8_64;
|
||||
step2[5] = fdct_round_shift(temp1);
|
||||
step2[6] = fdct_round_shift(temp2);
|
||||
|
||||
// step 5
|
||||
step1[0] = step3[0] + step2[1];
|
||||
step1[1] = step3[0] - step2[1];
|
||||
step1[2] = step3[3] + step2[2];
|
||||
step1[3] = step3[3] - step2[2];
|
||||
step1[4] = step3[4] - step2[5];
|
||||
step1[5] = step3[4] + step2[5];
|
||||
step1[6] = step3[7] - step2[6];
|
||||
step1[7] = step3[7] + step2[6];
|
||||
|
||||
// step 6
|
||||
temp1 = step1[0] * cospi_30_64 + step1[7] * cospi_2_64;
|
||||
temp2 = step1[1] * cospi_14_64 + step1[6] * cospi_18_64;
|
||||
out[1] = (tran_low_t)fdct_round_shift(temp1);
|
||||
out[9] = (tran_low_t)fdct_round_shift(temp2);
|
||||
|
||||
temp1 = step1[2] * cospi_22_64 + step1[5] * cospi_10_64;
|
||||
temp2 = step1[3] * cospi_6_64 + step1[4] * cospi_26_64;
|
||||
out[5] = (tran_low_t)fdct_round_shift(temp1);
|
||||
out[13] = (tran_low_t)fdct_round_shift(temp2);
|
||||
|
||||
temp1 = step1[3] * -cospi_26_64 + step1[4] * cospi_6_64;
|
||||
temp2 = step1[2] * -cospi_10_64 + step1[5] * cospi_22_64;
|
||||
out[3] = (tran_low_t)fdct_round_shift(temp1);
|
||||
out[11] = (tran_low_t)fdct_round_shift(temp2);
|
||||
|
||||
temp1 = step1[1] * -cospi_18_64 + step1[6] * cospi_14_64;
|
||||
temp2 = step1[0] * -cospi_2_64 + step1[7] * cospi_30_64;
|
||||
out[7] = (tran_low_t)fdct_round_shift(temp1);
|
||||
out[15] = (tran_low_t)fdct_round_shift(temp2);
|
||||
}
|
||||
|
||||
static void fadst4(const tran_low_t *input, tran_low_t *output) {
|
||||
tran_high_t x0, x1, x2, x3;
|
||||
tran_high_t s0, s1, s2, s3, s4, s5, s6, s7;
|
||||
|
||||
x0 = input[0];
|
||||
x1 = input[1];
|
||||
x2 = input[2];
|
||||
x3 = input[3];
|
||||
|
||||
if (!(x0 | x1 | x2 | x3)) {
|
||||
output[0] = output[1] = output[2] = output[3] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
s0 = sinpi_1_9 * x0;
|
||||
s1 = sinpi_4_9 * x0;
|
||||
s2 = sinpi_2_9 * x1;
|
||||
s3 = sinpi_1_9 * x1;
|
||||
s4 = sinpi_3_9 * x2;
|
||||
s5 = sinpi_4_9 * x3;
|
||||
s6 = sinpi_2_9 * x3;
|
||||
s7 = x0 + x1 - x3;
|
||||
|
||||
x0 = s0 + s2 + s5;
|
||||
x1 = sinpi_3_9 * s7;
|
||||
x2 = s1 - s3 + s6;
|
||||
x3 = s4;
|
||||
|
||||
s0 = x0 + x3;
|
||||
s1 = x1;
|
||||
s2 = x2 - x3;
|
||||
s3 = x2 - x0 + x3;
|
||||
|
||||
// 1-D transform scaling factor is sqrt(2).
|
||||
output[0] = (tran_low_t)fdct_round_shift(s0);
|
||||
output[1] = (tran_low_t)fdct_round_shift(s1);
|
||||
output[2] = (tran_low_t)fdct_round_shift(s2);
|
||||
output[3] = (tran_low_t)fdct_round_shift(s3);
|
||||
}
|
||||
|
||||
static void fadst8(const tran_low_t *input, tran_low_t *output) {
|
||||
tran_high_t s0, s1, s2, s3, s4, s5, s6, s7;
|
||||
|
||||
tran_high_t x0 = input[7];
|
||||
tran_high_t x1 = input[0];
|
||||
tran_high_t x2 = input[5];
|
||||
tran_high_t x3 = input[2];
|
||||
tran_high_t x4 = input[3];
|
||||
tran_high_t x5 = input[4];
|
||||
tran_high_t x6 = input[1];
|
||||
tran_high_t x7 = input[6];
|
||||
|
||||
// stage 1
|
||||
s0 = cospi_2_64 * x0 + cospi_30_64 * x1;
|
||||
s1 = cospi_30_64 * x0 - cospi_2_64 * x1;
|
||||
s2 = cospi_10_64 * x2 + cospi_22_64 * x3;
|
||||
s3 = cospi_22_64 * x2 - cospi_10_64 * x3;
|
||||
s4 = cospi_18_64 * x4 + cospi_14_64 * x5;
|
||||
s5 = cospi_14_64 * x4 - cospi_18_64 * x5;
|
||||
s6 = cospi_26_64 * x6 + cospi_6_64 * x7;
|
||||
s7 = cospi_6_64 * x6 - cospi_26_64 * x7;
|
||||
|
||||
x0 = fdct_round_shift(s0 + s4);
|
||||
x1 = fdct_round_shift(s1 + s5);
|
||||
x2 = fdct_round_shift(s2 + s6);
|
||||
x3 = fdct_round_shift(s3 + s7);
|
||||
x4 = fdct_round_shift(s0 - s4);
|
||||
x5 = fdct_round_shift(s1 - s5);
|
||||
x6 = fdct_round_shift(s2 - s6);
|
||||
x7 = fdct_round_shift(s3 - s7);
|
||||
|
||||
// stage 2
|
||||
s0 = x0;
|
||||
s1 = x1;
|
||||
s2 = x2;
|
||||
s3 = x3;
|
||||
s4 = cospi_8_64 * x4 + cospi_24_64 * x5;
|
||||
s5 = cospi_24_64 * x4 - cospi_8_64 * x5;
|
||||
s6 = -cospi_24_64 * x6 + cospi_8_64 * x7;
|
||||
s7 = cospi_8_64 * x6 + cospi_24_64 * x7;
|
||||
|
||||
x0 = s0 + s2;
|
||||
x1 = s1 + s3;
|
||||
x2 = s0 - s2;
|
||||
x3 = s1 - s3;
|
||||
x4 = fdct_round_shift(s4 + s6);
|
||||
x5 = fdct_round_shift(s5 + s7);
|
||||
x6 = fdct_round_shift(s4 - s6);
|
||||
x7 = fdct_round_shift(s5 - s7);
|
||||
|
||||
// stage 3
|
||||
s2 = cospi_16_64 * (x2 + x3);
|
||||
s3 = cospi_16_64 * (x2 - x3);
|
||||
s6 = cospi_16_64 * (x6 + x7);
|
||||
s7 = cospi_16_64 * (x6 - x7);
|
||||
|
||||
x2 = fdct_round_shift(s2);
|
||||
x3 = fdct_round_shift(s3);
|
||||
x6 = fdct_round_shift(s6);
|
||||
x7 = fdct_round_shift(s7);
|
||||
|
||||
output[0] = (tran_low_t)x0;
|
||||
output[1] = (tran_low_t)-x4;
|
||||
output[2] = (tran_low_t)x6;
|
||||
output[3] = (tran_low_t)-x2;
|
||||
output[4] = (tran_low_t)x3;
|
||||
output[5] = (tran_low_t)-x7;
|
||||
output[6] = (tran_low_t)x5;
|
||||
output[7] = (tran_low_t)-x1;
|
||||
}
|
||||
|
||||
static void fadst16(const tran_low_t *input, tran_low_t *output) {
|
||||
tran_high_t s0, s1, s2, s3, s4, s5, s6, s7, s8;
|
||||
tran_high_t s9, s10, s11, s12, s13, s14, s15;
|
||||
|
||||
tran_high_t x0 = input[15];
|
||||
tran_high_t x1 = input[0];
|
||||
tran_high_t x2 = input[13];
|
||||
tran_high_t x3 = input[2];
|
||||
tran_high_t x4 = input[11];
|
||||
tran_high_t x5 = input[4];
|
||||
tran_high_t x6 = input[9];
|
||||
tran_high_t x7 = input[6];
|
||||
tran_high_t x8 = input[7];
|
||||
tran_high_t x9 = input[8];
|
||||
tran_high_t x10 = input[5];
|
||||
tran_high_t x11 = input[10];
|
||||
tran_high_t x12 = input[3];
|
||||
tran_high_t x13 = input[12];
|
||||
tran_high_t x14 = input[1];
|
||||
tran_high_t x15 = input[14];
|
||||
|
||||
// stage 1
|
||||
s0 = x0 * cospi_1_64 + x1 * cospi_31_64;
|
||||
s1 = x0 * cospi_31_64 - x1 * cospi_1_64;
|
||||
s2 = x2 * cospi_5_64 + x3 * cospi_27_64;
|
||||
s3 = x2 * cospi_27_64 - x3 * cospi_5_64;
|
||||
s4 = x4 * cospi_9_64 + x5 * cospi_23_64;
|
||||
s5 = x4 * cospi_23_64 - x5 * cospi_9_64;
|
||||
s6 = x6 * cospi_13_64 + x7 * cospi_19_64;
|
||||
s7 = x6 * cospi_19_64 - x7 * cospi_13_64;
|
||||
s8 = x8 * cospi_17_64 + x9 * cospi_15_64;
|
||||
s9 = x8 * cospi_15_64 - x9 * cospi_17_64;
|
||||
s10 = x10 * cospi_21_64 + x11 * cospi_11_64;
|
||||
s11 = x10 * cospi_11_64 - x11 * cospi_21_64;
|
||||
s12 = x12 * cospi_25_64 + x13 * cospi_7_64;
|
||||
s13 = x12 * cospi_7_64 - x13 * cospi_25_64;
|
||||
s14 = x14 * cospi_29_64 + x15 * cospi_3_64;
|
||||
s15 = x14 * cospi_3_64 - x15 * cospi_29_64;
|
||||
|
||||
x0 = fdct_round_shift(s0 + s8);
|
||||
x1 = fdct_round_shift(s1 + s9);
|
||||
x2 = fdct_round_shift(s2 + s10);
|
||||
x3 = fdct_round_shift(s3 + s11);
|
||||
x4 = fdct_round_shift(s4 + s12);
|
||||
x5 = fdct_round_shift(s5 + s13);
|
||||
x6 = fdct_round_shift(s6 + s14);
|
||||
x7 = fdct_round_shift(s7 + s15);
|
||||
x8 = fdct_round_shift(s0 - s8);
|
||||
x9 = fdct_round_shift(s1 - s9);
|
||||
x10 = fdct_round_shift(s2 - s10);
|
||||
x11 = fdct_round_shift(s3 - s11);
|
||||
x12 = fdct_round_shift(s4 - s12);
|
||||
x13 = fdct_round_shift(s5 - s13);
|
||||
x14 = fdct_round_shift(s6 - s14);
|
||||
x15 = fdct_round_shift(s7 - s15);
|
||||
|
||||
// stage 2
|
||||
s0 = x0;
|
||||
s1 = x1;
|
||||
s2 = x2;
|
||||
s3 = x3;
|
||||
s4 = x4;
|
||||
s5 = x5;
|
||||
s6 = x6;
|
||||
s7 = x7;
|
||||
s8 = x8 * cospi_4_64 + x9 * cospi_28_64;
|
||||
s9 = x8 * cospi_28_64 - x9 * cospi_4_64;
|
||||
s10 = x10 * cospi_20_64 + x11 * cospi_12_64;
|
||||
s11 = x10 * cospi_12_64 - x11 * cospi_20_64;
|
||||
s12 = -x12 * cospi_28_64 + x13 * cospi_4_64;
|
||||
s13 = x12 * cospi_4_64 + x13 * cospi_28_64;
|
||||
s14 = -x14 * cospi_12_64 + x15 * cospi_20_64;
|
||||
s15 = x14 * cospi_20_64 + x15 * cospi_12_64;
|
||||
|
||||
x0 = s0 + s4;
|
||||
x1 = s1 + s5;
|
||||
x2 = s2 + s6;
|
||||
x3 = s3 + s7;
|
||||
x4 = s0 - s4;
|
||||
x5 = s1 - s5;
|
||||
x6 = s2 - s6;
|
||||
x7 = s3 - s7;
|
||||
x8 = fdct_round_shift(s8 + s12);
|
||||
x9 = fdct_round_shift(s9 + s13);
|
||||
x10 = fdct_round_shift(s10 + s14);
|
||||
x11 = fdct_round_shift(s11 + s15);
|
||||
x12 = fdct_round_shift(s8 - s12);
|
||||
x13 = fdct_round_shift(s9 - s13);
|
||||
x14 = fdct_round_shift(s10 - s14);
|
||||
x15 = fdct_round_shift(s11 - s15);
|
||||
|
||||
// stage 3
|
||||
s0 = x0;
|
||||
s1 = x1;
|
||||
s2 = x2;
|
||||
s3 = x3;
|
||||
s4 = x4 * cospi_8_64 + x5 * cospi_24_64;
|
||||
s5 = x4 * cospi_24_64 - x5 * cospi_8_64;
|
||||
s6 = -x6 * cospi_24_64 + x7 * cospi_8_64;
|
||||
s7 = x6 * cospi_8_64 + x7 * cospi_24_64;
|
||||
s8 = x8;
|
||||
s9 = x9;
|
||||
s10 = x10;
|
||||
s11 = x11;
|
||||
s12 = x12 * cospi_8_64 + x13 * cospi_24_64;
|
||||
s13 = x12 * cospi_24_64 - x13 * cospi_8_64;
|
||||
s14 = -x14 * cospi_24_64 + x15 * cospi_8_64;
|
||||
s15 = x14 * cospi_8_64 + x15 * cospi_24_64;
|
||||
|
||||
x0 = s0 + s2;
|
||||
x1 = s1 + s3;
|
||||
x2 = s0 - s2;
|
||||
x3 = s1 - s3;
|
||||
x4 = fdct_round_shift(s4 + s6);
|
||||
x5 = fdct_round_shift(s5 + s7);
|
||||
x6 = fdct_round_shift(s4 - s6);
|
||||
x7 = fdct_round_shift(s5 - s7);
|
||||
x8 = s8 + s10;
|
||||
x9 = s9 + s11;
|
||||
x10 = s8 - s10;
|
||||
x11 = s9 - s11;
|
||||
x12 = fdct_round_shift(s12 + s14);
|
||||
x13 = fdct_round_shift(s13 + s15);
|
||||
x14 = fdct_round_shift(s12 - s14);
|
||||
x15 = fdct_round_shift(s13 - s15);
|
||||
|
||||
// stage 4
|
||||
s2 = (-cospi_16_64) * (x2 + x3);
|
||||
s3 = cospi_16_64 * (x2 - x3);
|
||||
s6 = cospi_16_64 * (x6 + x7);
|
||||
s7 = cospi_16_64 * (-x6 + x7);
|
||||
s10 = cospi_16_64 * (x10 + x11);
|
||||
s11 = cospi_16_64 * (-x10 + x11);
|
||||
s14 = (-cospi_16_64) * (x14 + x15);
|
||||
s15 = cospi_16_64 * (x14 - x15);
|
||||
|
||||
x2 = fdct_round_shift(s2);
|
||||
x3 = fdct_round_shift(s3);
|
||||
x6 = fdct_round_shift(s6);
|
||||
x7 = fdct_round_shift(s7);
|
||||
x10 = fdct_round_shift(s10);
|
||||
x11 = fdct_round_shift(s11);
|
||||
x14 = fdct_round_shift(s14);
|
||||
x15 = fdct_round_shift(s15);
|
||||
|
||||
output[0] = (tran_low_t)x0;
|
||||
output[1] = (tran_low_t)-x8;
|
||||
output[2] = (tran_low_t)x12;
|
||||
output[3] = (tran_low_t)-x4;
|
||||
output[4] = (tran_low_t)x6;
|
||||
output[5] = (tran_low_t)x14;
|
||||
output[6] = (tran_low_t)x10;
|
||||
output[7] = (tran_low_t)x2;
|
||||
output[8] = (tran_low_t)x3;
|
||||
output[9] = (tran_low_t)x11;
|
||||
output[10] = (tran_low_t)x15;
|
||||
output[11] = (tran_low_t)x7;
|
||||
output[12] = (tran_low_t)x5;
|
||||
output[13] = (tran_low_t)-x13;
|
||||
output[14] = (tran_low_t)x9;
|
||||
output[15] = (tran_low_t)-x1;
|
||||
}
|
||||
|
||||
static const transform_2d FHT_4[] = {
|
||||
{ fdct4, fdct4 }, // DCT_DCT = 0
|
||||
{ fadst4, fdct4 }, // ADST_DCT = 1
|
||||
{ fdct4, fadst4 }, // DCT_ADST = 2
|
||||
{ fadst4, fadst4 } // ADST_ADST = 3
|
||||
};
|
||||
|
||||
static const transform_2d FHT_8[] = {
|
||||
{ fdct8, fdct8 }, // DCT_DCT = 0
|
||||
{ fadst8, fdct8 }, // ADST_DCT = 1
|
||||
{ fdct8, fadst8 }, // DCT_ADST = 2
|
||||
{ fadst8, fadst8 } // ADST_ADST = 3
|
||||
};
|
||||
|
||||
static const transform_2d FHT_16[] = {
|
||||
{ fdct16, fdct16 }, // DCT_DCT = 0
|
||||
{ fadst16, fdct16 }, // ADST_DCT = 1
|
||||
{ fdct16, fadst16 }, // DCT_ADST = 2
|
||||
{ fadst16, fadst16 } // ADST_ADST = 3
|
||||
};
|
||||
|
||||
void vp9_fht4x4_c(const int16_t *input, tran_low_t *output, int stride,
|
||||
int tx_type) {
|
||||
if (tx_type == DCT_DCT) {
|
||||
vpx_fdct4x4_c(input, output, stride);
|
||||
} else {
|
||||
tran_low_t out[4 * 4];
|
||||
int i, j;
|
||||
tran_low_t temp_in[4], temp_out[4];
|
||||
const transform_2d ht = FHT_4[tx_type];
|
||||
|
||||
// Columns
|
||||
for (i = 0; i < 4; ++i) {
|
||||
for (j = 0; j < 4; ++j) temp_in[j] = input[j * stride + i] * 16;
|
||||
if (i == 0 && temp_in[0]) temp_in[0] += 1;
|
||||
ht.cols(temp_in, temp_out);
|
||||
for (j = 0; j < 4; ++j) out[j * 4 + i] = temp_out[j];
|
||||
}
|
||||
|
||||
// Rows
|
||||
for (i = 0; i < 4; ++i) {
|
||||
for (j = 0; j < 4; ++j) temp_in[j] = out[j + i * 4];
|
||||
ht.rows(temp_in, temp_out);
|
||||
for (j = 0; j < 4; ++j) output[j + i * 4] = (temp_out[j] + 1) >> 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_fht8x8_c(const int16_t *input, tran_low_t *output, int stride,
|
||||
int tx_type) {
|
||||
if (tx_type == DCT_DCT) {
|
||||
vpx_fdct8x8_c(input, output, stride);
|
||||
} else {
|
||||
tran_low_t out[64];
|
||||
int i, j;
|
||||
tran_low_t temp_in[8], temp_out[8];
|
||||
const transform_2d ht = FHT_8[tx_type];
|
||||
|
||||
// Columns
|
||||
for (i = 0; i < 8; ++i) {
|
||||
for (j = 0; j < 8; ++j) temp_in[j] = input[j * stride + i] * 4;
|
||||
ht.cols(temp_in, temp_out);
|
||||
for (j = 0; j < 8; ++j) out[j * 8 + i] = temp_out[j];
|
||||
}
|
||||
|
||||
// Rows
|
||||
for (i = 0; i < 8; ++i) {
|
||||
for (j = 0; j < 8; ++j) temp_in[j] = out[j + i * 8];
|
||||
ht.rows(temp_in, temp_out);
|
||||
for (j = 0; j < 8; ++j)
|
||||
output[j + i * 8] = (temp_out[j] + (temp_out[j] < 0)) >> 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 4-point reversible, orthonormal Walsh-Hadamard in 3.5 adds, 0.5 shifts per
|
||||
pixel. */
|
||||
void vp9_fwht4x4_c(const int16_t *input, tran_low_t *output, int stride) {
|
||||
int i;
|
||||
tran_high_t a1, b1, c1, d1, e1;
|
||||
const int16_t *ip_pass0 = input;
|
||||
const tran_low_t *ip = NULL;
|
||||
tran_low_t *op = output;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
a1 = ip_pass0[0 * stride];
|
||||
b1 = ip_pass0[1 * stride];
|
||||
c1 = ip_pass0[2 * stride];
|
||||
d1 = ip_pass0[3 * stride];
|
||||
|
||||
a1 += b1;
|
||||
d1 = d1 - c1;
|
||||
e1 = (a1 - d1) >> 1;
|
||||
b1 = e1 - b1;
|
||||
c1 = e1 - c1;
|
||||
a1 -= c1;
|
||||
d1 += b1;
|
||||
op[0] = (tran_low_t)a1;
|
||||
op[4] = (tran_low_t)c1;
|
||||
op[8] = (tran_low_t)d1;
|
||||
op[12] = (tran_low_t)b1;
|
||||
|
||||
ip_pass0++;
|
||||
op++;
|
||||
}
|
||||
ip = output;
|
||||
op = output;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
a1 = ip[0];
|
||||
b1 = ip[1];
|
||||
c1 = ip[2];
|
||||
d1 = ip[3];
|
||||
|
||||
a1 += b1;
|
||||
d1 -= c1;
|
||||
e1 = (a1 - d1) >> 1;
|
||||
b1 = e1 - b1;
|
||||
c1 = e1 - c1;
|
||||
a1 -= c1;
|
||||
d1 += b1;
|
||||
op[0] = (tran_low_t)(a1 * UNIT_QUANT_FACTOR);
|
||||
op[1] = (tran_low_t)(c1 * UNIT_QUANT_FACTOR);
|
||||
op[2] = (tran_low_t)(d1 * UNIT_QUANT_FACTOR);
|
||||
op[3] = (tran_low_t)(b1 * UNIT_QUANT_FACTOR);
|
||||
|
||||
ip += 4;
|
||||
op += 4;
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_fht16x16_c(const int16_t *input, tran_low_t *output, int stride,
|
||||
int tx_type) {
|
||||
if (tx_type == DCT_DCT) {
|
||||
vpx_fdct16x16_c(input, output, stride);
|
||||
} else {
|
||||
tran_low_t out[256];
|
||||
int i, j;
|
||||
tran_low_t temp_in[16], temp_out[16];
|
||||
const transform_2d ht = FHT_16[tx_type];
|
||||
|
||||
// Columns
|
||||
for (i = 0; i < 16; ++i) {
|
||||
for (j = 0; j < 16; ++j) temp_in[j] = input[j * stride + i] * 4;
|
||||
ht.cols(temp_in, temp_out);
|
||||
for (j = 0; j < 16; ++j)
|
||||
out[j * 16 + i] = (temp_out[j] + 1 + (temp_out[j] < 0)) >> 2;
|
||||
}
|
||||
|
||||
// Rows
|
||||
for (i = 0; i < 16; ++i) {
|
||||
for (j = 0; j < 16; ++j) temp_in[j] = out[j + i * 16];
|
||||
ht.rows(temp_in, temp_out);
|
||||
for (j = 0; j < 16; ++j) output[j + i * 16] = temp_out[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
void vp9_highbd_fht4x4_c(const int16_t *input, tran_low_t *output, int stride,
|
||||
int tx_type) {
|
||||
vp9_fht4x4_c(input, output, stride, tx_type);
|
||||
}
|
||||
|
||||
void vp9_highbd_fht8x8_c(const int16_t *input, tran_low_t *output, int stride,
|
||||
int tx_type) {
|
||||
vp9_fht8x8_c(input, output, stride, tx_type);
|
||||
}
|
||||
|
||||
void vp9_highbd_fwht4x4_c(const int16_t *input, tran_low_t *output,
|
||||
int stride) {
|
||||
vp9_fwht4x4_c(input, output, stride);
|
||||
}
|
||||
|
||||
void vp9_highbd_fht16x16_c(const int16_t *input, tran_low_t *output, int stride,
|
||||
int tx_type) {
|
||||
vp9_fht16x16_c(input, output, stride, tx_type);
|
||||
}
|
||||
#endif // CONFIG_VP9_HIGHBITDEPTH
|
||||
@@ -0,0 +1,838 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebM project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "./vpx_dsp_rtcd.h"
|
||||
#include "vpx_dsp/vpx_dsp_common.h"
|
||||
#include "vpx_scale/yv12config.h"
|
||||
#include "vpx/vpx_integer.h"
|
||||
#include "vp9/common/vp9_reconinter.h"
|
||||
#include "vp9/encoder/vp9_context_tree.h"
|
||||
#include "vp9/encoder/vp9_denoiser.h"
|
||||
#include "vp9/encoder/vp9_encoder.h"
|
||||
|
||||
#ifdef OUTPUT_YUV_DENOISED
|
||||
static void make_grayscale(YV12_BUFFER_CONFIG *yuv);
|
||||
#endif
|
||||
|
||||
static int absdiff_thresh(BLOCK_SIZE bs, int increase_denoising) {
|
||||
(void)bs;
|
||||
return 3 + (increase_denoising ? 1 : 0);
|
||||
}
|
||||
|
||||
static int delta_thresh(BLOCK_SIZE bs, int increase_denoising) {
|
||||
(void)bs;
|
||||
(void)increase_denoising;
|
||||
return 4;
|
||||
}
|
||||
|
||||
static int noise_motion_thresh(BLOCK_SIZE bs, int increase_denoising) {
|
||||
(void)bs;
|
||||
(void)increase_denoising;
|
||||
return 625;
|
||||
}
|
||||
|
||||
static unsigned int sse_thresh(BLOCK_SIZE bs, int increase_denoising) {
|
||||
return (1 << num_pels_log2_lookup[bs]) * (increase_denoising ? 80 : 40);
|
||||
}
|
||||
|
||||
static int sse_diff_thresh(BLOCK_SIZE bs, int increase_denoising,
|
||||
int motion_magnitude) {
|
||||
if (motion_magnitude > noise_motion_thresh(bs, increase_denoising)) {
|
||||
if (increase_denoising)
|
||||
return (1 << num_pels_log2_lookup[bs]) << 2;
|
||||
else
|
||||
return 0;
|
||||
} else {
|
||||
return (1 << num_pels_log2_lookup[bs]) << 4;
|
||||
}
|
||||
}
|
||||
|
||||
static int total_adj_weak_thresh(BLOCK_SIZE bs, int increase_denoising) {
|
||||
return (1 << num_pels_log2_lookup[bs]) * (increase_denoising ? 3 : 2);
|
||||
}
|
||||
|
||||
// TODO(jackychen): If increase_denoising is enabled in the future,
|
||||
// we might need to update the code for calculating 'total_adj' in
|
||||
// case the C code is not bit-exact with corresponding sse2 code.
|
||||
int vp9_denoiser_filter_c(const uint8_t *sig, int sig_stride,
|
||||
const uint8_t *mc_avg, int mc_avg_stride,
|
||||
uint8_t *avg, int avg_stride, int increase_denoising,
|
||||
BLOCK_SIZE bs, int motion_magnitude) {
|
||||
int r, c;
|
||||
const uint8_t *sig_start = sig;
|
||||
const uint8_t *mc_avg_start = mc_avg;
|
||||
uint8_t *avg_start = avg;
|
||||
int diff, adj, absdiff, delta;
|
||||
int adj_val[] = { 3, 4, 6 };
|
||||
int total_adj = 0;
|
||||
int shift_inc = 1;
|
||||
|
||||
// If motion_magnitude is small, making the denoiser more aggressive by
|
||||
// increasing the adjustment for each level. Add another increment for
|
||||
// blocks that are labeled for increase denoising.
|
||||
if (motion_magnitude <= MOTION_MAGNITUDE_THRESHOLD) {
|
||||
if (increase_denoising) {
|
||||
shift_inc = 2;
|
||||
}
|
||||
adj_val[0] += shift_inc;
|
||||
adj_val[1] += shift_inc;
|
||||
adj_val[2] += shift_inc;
|
||||
}
|
||||
|
||||
// First attempt to apply a strong temporal denoising filter.
|
||||
for (r = 0; r < (4 << b_height_log2_lookup[bs]); ++r) {
|
||||
for (c = 0; c < (4 << b_width_log2_lookup[bs]); ++c) {
|
||||
diff = mc_avg[c] - sig[c];
|
||||
absdiff = abs(diff);
|
||||
|
||||
if (absdiff <= absdiff_thresh(bs, increase_denoising)) {
|
||||
avg[c] = mc_avg[c];
|
||||
total_adj += diff;
|
||||
} else {
|
||||
switch (absdiff) {
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7: adj = adj_val[0]; break;
|
||||
case 8:
|
||||
case 9:
|
||||
case 10:
|
||||
case 11:
|
||||
case 12:
|
||||
case 13:
|
||||
case 14:
|
||||
case 15: adj = adj_val[1]; break;
|
||||
default: adj = adj_val[2];
|
||||
}
|
||||
if (diff > 0) {
|
||||
avg[c] = VPXMIN(UINT8_MAX, sig[c] + adj);
|
||||
total_adj += adj;
|
||||
} else {
|
||||
avg[c] = VPXMAX(0, sig[c] - adj);
|
||||
total_adj -= adj;
|
||||
}
|
||||
}
|
||||
}
|
||||
sig += sig_stride;
|
||||
avg += avg_stride;
|
||||
mc_avg += mc_avg_stride;
|
||||
}
|
||||
|
||||
// If the strong filter did not modify the signal too much, we're all set.
|
||||
if (abs(total_adj) <= total_adj_strong_thresh(bs, increase_denoising)) {
|
||||
return FILTER_BLOCK;
|
||||
}
|
||||
|
||||
// Otherwise, we try to dampen the filter if the delta is not too high.
|
||||
delta = ((abs(total_adj) - total_adj_strong_thresh(bs, increase_denoising)) >>
|
||||
num_pels_log2_lookup[bs]) +
|
||||
1;
|
||||
|
||||
if (delta >= delta_thresh(bs, increase_denoising)) {
|
||||
return COPY_BLOCK;
|
||||
}
|
||||
|
||||
mc_avg = mc_avg_start;
|
||||
avg = avg_start;
|
||||
sig = sig_start;
|
||||
for (r = 0; r < (4 << b_height_log2_lookup[bs]); ++r) {
|
||||
for (c = 0; c < (4 << b_width_log2_lookup[bs]); ++c) {
|
||||
diff = mc_avg[c] - sig[c];
|
||||
adj = abs(diff);
|
||||
if (adj > delta) {
|
||||
adj = delta;
|
||||
}
|
||||
if (diff > 0) {
|
||||
// Diff positive means we made positive adjustment above
|
||||
// (in first try/attempt), so now make negative adjustment to bring
|
||||
// denoised signal down.
|
||||
avg[c] = VPXMAX(0, avg[c] - adj);
|
||||
total_adj -= adj;
|
||||
} else {
|
||||
// Diff negative means we made negative adjustment above
|
||||
// (in first try/attempt), so now make positive adjustment to bring
|
||||
// denoised signal up.
|
||||
avg[c] = VPXMIN(UINT8_MAX, avg[c] + adj);
|
||||
total_adj += adj;
|
||||
}
|
||||
}
|
||||
sig += sig_stride;
|
||||
avg += avg_stride;
|
||||
mc_avg += mc_avg_stride;
|
||||
}
|
||||
|
||||
// We can use the filter if it has been sufficiently dampened
|
||||
if (abs(total_adj) <= total_adj_weak_thresh(bs, increase_denoising)) {
|
||||
return FILTER_BLOCK;
|
||||
}
|
||||
return COPY_BLOCK;
|
||||
}
|
||||
|
||||
static uint8_t *block_start(uint8_t *framebuf, int stride, int mi_row,
|
||||
int mi_col) {
|
||||
return framebuf + (stride * mi_row << 3) + (mi_col << 3);
|
||||
}
|
||||
|
||||
static VP9_DENOISER_DECISION perform_motion_compensation(
|
||||
VP9_COMMON *const cm, VP9_DENOISER *denoiser, MACROBLOCK *mb, BLOCK_SIZE bs,
|
||||
int increase_denoising, int mi_row, int mi_col, PICK_MODE_CONTEXT *ctx,
|
||||
int motion_magnitude, int is_skin, int *zeromv_filter, int consec_zeromv,
|
||||
int num_spatial_layers, int width, int lst_fb_idx, int gld_fb_idx,
|
||||
int use_svc, int spatial_layer, int use_gf_temporal_ref) {
|
||||
const int sse_diff = (ctx->newmv_sse == UINT_MAX)
|
||||
? 0
|
||||
: ((int)ctx->zeromv_sse - (int)ctx->newmv_sse);
|
||||
int frame;
|
||||
int denoise_layer_idx = 0;
|
||||
MACROBLOCKD *filter_mbd = &mb->e_mbd;
|
||||
MODE_INFO *mi = filter_mbd->mi[0];
|
||||
MODE_INFO saved_mi;
|
||||
int i;
|
||||
struct buf_2d saved_dst[MAX_MB_PLANE];
|
||||
struct buf_2d saved_pre[MAX_MB_PLANE];
|
||||
const RefBuffer *saved_block_refs[2];
|
||||
MV_REFERENCE_FRAME saved_frame;
|
||||
|
||||
frame = ctx->best_reference_frame;
|
||||
|
||||
saved_mi = *mi;
|
||||
|
||||
if (is_skin && (motion_magnitude > 0 || consec_zeromv < 4)) return COPY_BLOCK;
|
||||
|
||||
// Avoid denoising small blocks. When noise > kDenLow or frame width > 480,
|
||||
// denoise 16x16 blocks.
|
||||
if (bs == BLOCK_8X8 || bs == BLOCK_8X16 || bs == BLOCK_16X8 ||
|
||||
(bs == BLOCK_16X16 && width > 480 &&
|
||||
denoiser->denoising_level <= kDenLow))
|
||||
return COPY_BLOCK;
|
||||
|
||||
// If the best reference frame uses inter-prediction and there is enough of a
|
||||
// difference in sum-squared-error, use it.
|
||||
if (frame != INTRA_FRAME && frame != ALTREF_FRAME && frame != GOLDEN_FRAME &&
|
||||
sse_diff > sse_diff_thresh(bs, increase_denoising, motion_magnitude)) {
|
||||
mi->ref_frame[0] = ctx->best_reference_frame;
|
||||
mi->mode = ctx->best_sse_inter_mode;
|
||||
mi->mv[0] = ctx->best_sse_mv;
|
||||
} else {
|
||||
// Otherwise, use the zero reference frame.
|
||||
frame = ctx->best_zeromv_reference_frame;
|
||||
ctx->newmv_sse = ctx->zeromv_sse;
|
||||
// Bias to last reference.
|
||||
if ((num_spatial_layers > 1 && !use_gf_temporal_ref) ||
|
||||
frame == ALTREF_FRAME ||
|
||||
(frame == GOLDEN_FRAME && use_gf_temporal_ref) ||
|
||||
(frame != LAST_FRAME &&
|
||||
((ctx->zeromv_lastref_sse<(5 * ctx->zeromv_sse)>> 2) ||
|
||||
denoiser->denoising_level >= kDenHigh))) {
|
||||
frame = LAST_FRAME;
|
||||
ctx->newmv_sse = ctx->zeromv_lastref_sse;
|
||||
}
|
||||
mi->ref_frame[0] = frame;
|
||||
mi->mode = ZEROMV;
|
||||
mi->mv[0].as_int = 0;
|
||||
ctx->best_sse_inter_mode = ZEROMV;
|
||||
ctx->best_sse_mv.as_int = 0;
|
||||
*zeromv_filter = 1;
|
||||
if (denoiser->denoising_level > kDenMedium) {
|
||||
motion_magnitude = 0;
|
||||
}
|
||||
}
|
||||
|
||||
saved_frame = frame;
|
||||
// When using SVC, we need to map REF_FRAME to the frame buffer index.
|
||||
if (use_svc) {
|
||||
if (frame == LAST_FRAME)
|
||||
frame = lst_fb_idx + 1;
|
||||
else if (frame == GOLDEN_FRAME)
|
||||
frame = gld_fb_idx + 1;
|
||||
// Shift for the second spatial layer.
|
||||
if (num_spatial_layers - spatial_layer == 2)
|
||||
frame = frame + denoiser->num_ref_frames;
|
||||
denoise_layer_idx = num_spatial_layers - spatial_layer - 1;
|
||||
}
|
||||
|
||||
// Force copy (no denoise, copy source in denoised buffer) if
|
||||
// running_avg_y[frame] is NULL.
|
||||
if (denoiser->running_avg_y[frame].buffer_alloc == NULL) {
|
||||
// Restore everything to its original state
|
||||
*mi = saved_mi;
|
||||
return COPY_BLOCK;
|
||||
}
|
||||
|
||||
if (ctx->newmv_sse > sse_thresh(bs, increase_denoising)) {
|
||||
// Restore everything to its original state
|
||||
*mi = saved_mi;
|
||||
return COPY_BLOCK;
|
||||
}
|
||||
if (motion_magnitude > (noise_motion_thresh(bs, increase_denoising) << 3)) {
|
||||
// Restore everything to its original state
|
||||
*mi = saved_mi;
|
||||
return COPY_BLOCK;
|
||||
}
|
||||
|
||||
// We will restore these after motion compensation.
|
||||
for (i = 0; i < MAX_MB_PLANE; ++i) {
|
||||
saved_pre[i] = filter_mbd->plane[i].pre[0];
|
||||
saved_dst[i] = filter_mbd->plane[i].dst;
|
||||
}
|
||||
saved_block_refs[0] = filter_mbd->block_refs[0];
|
||||
|
||||
// Set the pointers in the MACROBLOCKD to point to the buffers in the denoiser
|
||||
// struct.
|
||||
filter_mbd->plane[0].pre[0].buf =
|
||||
block_start(denoiser->running_avg_y[frame].y_buffer,
|
||||
denoiser->running_avg_y[frame].y_stride, mi_row, mi_col);
|
||||
filter_mbd->plane[0].pre[0].stride = denoiser->running_avg_y[frame].y_stride;
|
||||
filter_mbd->plane[1].pre[0].buf =
|
||||
block_start(denoiser->running_avg_y[frame].u_buffer,
|
||||
denoiser->running_avg_y[frame].uv_stride, mi_row, mi_col);
|
||||
filter_mbd->plane[1].pre[0].stride = denoiser->running_avg_y[frame].uv_stride;
|
||||
filter_mbd->plane[2].pre[0].buf =
|
||||
block_start(denoiser->running_avg_y[frame].v_buffer,
|
||||
denoiser->running_avg_y[frame].uv_stride, mi_row, mi_col);
|
||||
filter_mbd->plane[2].pre[0].stride = denoiser->running_avg_y[frame].uv_stride;
|
||||
|
||||
filter_mbd->plane[0].dst.buf = block_start(
|
||||
denoiser->mc_running_avg_y[denoise_layer_idx].y_buffer,
|
||||
denoiser->mc_running_avg_y[denoise_layer_idx].y_stride, mi_row, mi_col);
|
||||
filter_mbd->plane[0].dst.stride =
|
||||
denoiser->mc_running_avg_y[denoise_layer_idx].y_stride;
|
||||
filter_mbd->plane[1].dst.buf = block_start(
|
||||
denoiser->mc_running_avg_y[denoise_layer_idx].u_buffer,
|
||||
denoiser->mc_running_avg_y[denoise_layer_idx].uv_stride, mi_row, mi_col);
|
||||
filter_mbd->plane[1].dst.stride =
|
||||
denoiser->mc_running_avg_y[denoise_layer_idx].uv_stride;
|
||||
filter_mbd->plane[2].dst.buf = block_start(
|
||||
denoiser->mc_running_avg_y[denoise_layer_idx].v_buffer,
|
||||
denoiser->mc_running_avg_y[denoise_layer_idx].uv_stride, mi_row, mi_col);
|
||||
filter_mbd->plane[2].dst.stride =
|
||||
denoiser->mc_running_avg_y[denoise_layer_idx].uv_stride;
|
||||
|
||||
set_ref_ptrs(cm, filter_mbd, saved_frame, NONE);
|
||||
vp9_build_inter_predictors_sby(filter_mbd, mi_row, mi_col, bs);
|
||||
|
||||
// Restore everything to its original state
|
||||
*mi = saved_mi;
|
||||
filter_mbd->block_refs[0] = saved_block_refs[0];
|
||||
for (i = 0; i < MAX_MB_PLANE; ++i) {
|
||||
filter_mbd->plane[i].pre[0] = saved_pre[i];
|
||||
filter_mbd->plane[i].dst = saved_dst[i];
|
||||
}
|
||||
|
||||
return FILTER_BLOCK;
|
||||
}
|
||||
|
||||
void vp9_denoiser_denoise(VP9_COMP *cpi, MACROBLOCK *mb, int mi_row, int mi_col,
|
||||
BLOCK_SIZE bs, PICK_MODE_CONTEXT *ctx,
|
||||
VP9_DENOISER_DECISION *denoiser_decision,
|
||||
int use_gf_temporal_ref) {
|
||||
int mv_col, mv_row;
|
||||
int motion_magnitude = 0;
|
||||
int zeromv_filter = 0;
|
||||
VP9_DENOISER *denoiser = &cpi->denoiser;
|
||||
VP9_DENOISER_DECISION decision = COPY_BLOCK;
|
||||
|
||||
const int shift =
|
||||
cpi->svc.number_spatial_layers - cpi->svc.spatial_layer_id == 2
|
||||
? denoiser->num_ref_frames
|
||||
: 0;
|
||||
YV12_BUFFER_CONFIG avg = denoiser->running_avg_y[INTRA_FRAME + shift];
|
||||
const int denoise_layer_index =
|
||||
cpi->svc.number_spatial_layers - cpi->svc.spatial_layer_id - 1;
|
||||
YV12_BUFFER_CONFIG mc_avg = denoiser->mc_running_avg_y[denoise_layer_index];
|
||||
uint8_t *avg_start = block_start(avg.y_buffer, avg.y_stride, mi_row, mi_col);
|
||||
|
||||
uint8_t *mc_avg_start =
|
||||
block_start(mc_avg.y_buffer, mc_avg.y_stride, mi_row, mi_col);
|
||||
struct buf_2d src = mb->plane[0].src;
|
||||
int is_skin = 0;
|
||||
int increase_denoising = 0;
|
||||
int consec_zeromv = 0;
|
||||
int last_is_reference = cpi->ref_frame_flags & VP9_LAST_FLAG;
|
||||
mv_col = ctx->best_sse_mv.as_mv.col;
|
||||
mv_row = ctx->best_sse_mv.as_mv.row;
|
||||
motion_magnitude = mv_row * mv_row + mv_col * mv_col;
|
||||
|
||||
if (cpi->use_skin_detection && bs <= BLOCK_32X32 &&
|
||||
denoiser->denoising_level < kDenHigh) {
|
||||
int motion_level = (motion_magnitude < 16) ? 0 : 1;
|
||||
// If motion for current block is small/zero, compute consec_zeromv for
|
||||
// skin detection (early exit in skin detection is done for large
|
||||
// consec_zeromv when current block has small/zero motion).
|
||||
consec_zeromv = 0;
|
||||
if (motion_level == 0) {
|
||||
VP9_COMMON *const cm = &cpi->common;
|
||||
int j, i;
|
||||
// Loop through the 8x8 sub-blocks.
|
||||
const int bw = num_8x8_blocks_wide_lookup[bs];
|
||||
const int bh = num_8x8_blocks_high_lookup[bs];
|
||||
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;
|
||||
consec_zeromv = 100;
|
||||
for (i = 0; i < ymis; i++) {
|
||||
for (j = 0; j < xmis; j++) {
|
||||
int bl_index = block_index + i * cm->mi_cols + j;
|
||||
consec_zeromv = VPXMIN(cpi->consec_zero_mv[bl_index], consec_zeromv);
|
||||
// No need to keep checking 8x8 blocks if any of the sub-blocks
|
||||
// has small consec_zeromv (since threshold for no_skin based on
|
||||
// zero/small motion in skin detection is high, i.e, > 4).
|
||||
if (consec_zeromv < 4) {
|
||||
i = ymis;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO(marpan): Compute skin detection over sub-blocks.
|
||||
is_skin = vp9_compute_skin_block(
|
||||
mb->plane[0].src.buf, mb->plane[1].src.buf, mb->plane[2].src.buf,
|
||||
mb->plane[0].src.stride, mb->plane[1].src.stride, bs, consec_zeromv,
|
||||
motion_level);
|
||||
}
|
||||
if (!is_skin && denoiser->denoising_level == kDenHigh) increase_denoising = 1;
|
||||
|
||||
// Copy block if LAST_FRAME is not a reference.
|
||||
// Last doesn't always exist when SVC layers are dynamically changed, e.g. top
|
||||
// spatial layer doesn't have last reference when it's brought up for the
|
||||
// first time on the fly.
|
||||
if (last_is_reference && denoiser->denoising_level >= kDenLow &&
|
||||
!ctx->sb_skip_denoising)
|
||||
decision = perform_motion_compensation(
|
||||
&cpi->common, denoiser, mb, bs, increase_denoising, mi_row, mi_col, ctx,
|
||||
motion_magnitude, is_skin, &zeromv_filter, consec_zeromv,
|
||||
cpi->svc.number_spatial_layers, cpi->Source->y_width, cpi->lst_fb_idx,
|
||||
cpi->gld_fb_idx, cpi->use_svc, cpi->svc.spatial_layer_id,
|
||||
use_gf_temporal_ref);
|
||||
|
||||
if (decision == FILTER_BLOCK) {
|
||||
decision = vp9_denoiser_filter(src.buf, src.stride, mc_avg_start,
|
||||
mc_avg.y_stride, avg_start, avg.y_stride,
|
||||
increase_denoising, bs, motion_magnitude);
|
||||
}
|
||||
|
||||
if (decision == FILTER_BLOCK) {
|
||||
vpx_convolve_copy(avg_start, avg.y_stride, src.buf, src.stride, NULL, 0, 0,
|
||||
0, 0, num_4x4_blocks_wide_lookup[bs] << 2,
|
||||
num_4x4_blocks_high_lookup[bs] << 2);
|
||||
} else { // COPY_BLOCK
|
||||
vpx_convolve_copy(src.buf, src.stride, avg_start, avg.y_stride, NULL, 0, 0,
|
||||
0, 0, num_4x4_blocks_wide_lookup[bs] << 2,
|
||||
num_4x4_blocks_high_lookup[bs] << 2);
|
||||
}
|
||||
*denoiser_decision = decision;
|
||||
if (decision == FILTER_BLOCK && zeromv_filter == 1)
|
||||
*denoiser_decision = FILTER_ZEROMV_BLOCK;
|
||||
}
|
||||
|
||||
static void copy_frame(YV12_BUFFER_CONFIG *const dest,
|
||||
const YV12_BUFFER_CONFIG *const src) {
|
||||
int r;
|
||||
const uint8_t *srcbuf = src->y_buffer;
|
||||
uint8_t *destbuf = dest->y_buffer;
|
||||
|
||||
assert(dest->y_width == src->y_width);
|
||||
assert(dest->y_height == src->y_height);
|
||||
|
||||
for (r = 0; r < dest->y_height; ++r) {
|
||||
memcpy(destbuf, srcbuf, dest->y_width);
|
||||
destbuf += dest->y_stride;
|
||||
srcbuf += src->y_stride;
|
||||
}
|
||||
}
|
||||
|
||||
static void swap_frame_buffer(YV12_BUFFER_CONFIG *const dest,
|
||||
YV12_BUFFER_CONFIG *const src) {
|
||||
uint8_t *tmp_buf = dest->y_buffer;
|
||||
assert(dest->y_width == src->y_width);
|
||||
assert(dest->y_height == src->y_height);
|
||||
dest->y_buffer = src->y_buffer;
|
||||
src->y_buffer = tmp_buf;
|
||||
}
|
||||
|
||||
void vp9_denoiser_update_frame_info(
|
||||
VP9_DENOISER *denoiser, YV12_BUFFER_CONFIG src, struct SVC *svc,
|
||||
FRAME_TYPE frame_type, int refresh_alt_ref_frame, int refresh_golden_frame,
|
||||
int refresh_last_frame, int alt_fb_idx, int gld_fb_idx, int lst_fb_idx,
|
||||
int resized, int svc_refresh_denoiser_buffers, int second_spatial_layer) {
|
||||
const int shift = second_spatial_layer ? denoiser->num_ref_frames : 0;
|
||||
// Copy source into denoised reference buffers on KEY_FRAME or
|
||||
// if the just encoded frame was resized. For SVC, copy source if the base
|
||||
// spatial layer was key frame.
|
||||
if (frame_type == KEY_FRAME || resized != 0 || denoiser->reset ||
|
||||
svc_refresh_denoiser_buffers) {
|
||||
int i;
|
||||
// Start at 1 so as not to overwrite the INTRA_FRAME
|
||||
for (i = 1; i < denoiser->num_ref_frames; ++i) {
|
||||
if (denoiser->running_avg_y[i + shift].buffer_alloc != NULL)
|
||||
copy_frame(&denoiser->running_avg_y[i + shift], &src);
|
||||
}
|
||||
denoiser->reset = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (svc->temporal_layering_mode == VP9E_TEMPORAL_LAYERING_MODE_BYPASS &&
|
||||
svc->use_set_ref_frame_config) {
|
||||
int i;
|
||||
for (i = 0; i < REF_FRAMES; i++) {
|
||||
if (svc->update_buffer_slot[svc->spatial_layer_id] & (1 << i))
|
||||
copy_frame(&denoiser->running_avg_y[i + 1 + shift],
|
||||
&denoiser->running_avg_y[INTRA_FRAME + shift]);
|
||||
}
|
||||
} else {
|
||||
// If more than one refresh occurs, must copy frame buffer.
|
||||
if ((refresh_alt_ref_frame + refresh_golden_frame + refresh_last_frame) >
|
||||
1) {
|
||||
if (refresh_alt_ref_frame) {
|
||||
copy_frame(&denoiser->running_avg_y[alt_fb_idx + 1 + shift],
|
||||
&denoiser->running_avg_y[INTRA_FRAME + shift]);
|
||||
}
|
||||
if (refresh_golden_frame) {
|
||||
copy_frame(&denoiser->running_avg_y[gld_fb_idx + 1 + shift],
|
||||
&denoiser->running_avg_y[INTRA_FRAME + shift]);
|
||||
}
|
||||
if (refresh_last_frame) {
|
||||
copy_frame(&denoiser->running_avg_y[lst_fb_idx + 1 + shift],
|
||||
&denoiser->running_avg_y[INTRA_FRAME + shift]);
|
||||
}
|
||||
} else {
|
||||
if (refresh_alt_ref_frame) {
|
||||
swap_frame_buffer(&denoiser->running_avg_y[alt_fb_idx + 1 + shift],
|
||||
&denoiser->running_avg_y[INTRA_FRAME + shift]);
|
||||
}
|
||||
if (refresh_golden_frame) {
|
||||
swap_frame_buffer(&denoiser->running_avg_y[gld_fb_idx + 1 + shift],
|
||||
&denoiser->running_avg_y[INTRA_FRAME + shift]);
|
||||
}
|
||||
if (refresh_last_frame) {
|
||||
swap_frame_buffer(&denoiser->running_avg_y[lst_fb_idx + 1 + shift],
|
||||
&denoiser->running_avg_y[INTRA_FRAME + shift]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_denoiser_reset_frame_stats(PICK_MODE_CONTEXT *ctx) {
|
||||
ctx->zeromv_sse = UINT_MAX;
|
||||
ctx->newmv_sse = UINT_MAX;
|
||||
ctx->zeromv_lastref_sse = UINT_MAX;
|
||||
ctx->best_sse_mv.as_int = 0;
|
||||
}
|
||||
|
||||
void vp9_denoiser_update_frame_stats(MODE_INFO *mi, unsigned int sse,
|
||||
PREDICTION_MODE mode,
|
||||
PICK_MODE_CONTEXT *ctx) {
|
||||
if (mi->mv[0].as_int == 0 && sse < ctx->zeromv_sse) {
|
||||
ctx->zeromv_sse = sse;
|
||||
ctx->best_zeromv_reference_frame = mi->ref_frame[0];
|
||||
if (mi->ref_frame[0] == LAST_FRAME) ctx->zeromv_lastref_sse = sse;
|
||||
}
|
||||
|
||||
if (mi->mv[0].as_int != 0 && sse < ctx->newmv_sse) {
|
||||
ctx->newmv_sse = sse;
|
||||
ctx->best_sse_inter_mode = mode;
|
||||
ctx->best_sse_mv = mi->mv[0];
|
||||
ctx->best_reference_frame = mi->ref_frame[0];
|
||||
}
|
||||
}
|
||||
|
||||
static int vp9_denoiser_realloc_svc_helper(VP9_COMMON *cm,
|
||||
VP9_DENOISER *denoiser, int fb_idx) {
|
||||
int fail = 0;
|
||||
if (denoiser->running_avg_y[fb_idx].buffer_alloc == NULL) {
|
||||
fail =
|
||||
vpx_alloc_frame_buffer(&denoiser->running_avg_y[fb_idx], cm->width,
|
||||
cm->height, cm->subsampling_x, cm->subsampling_y,
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
cm->use_highbitdepth,
|
||||
#endif
|
||||
VP9_ENC_BORDER_IN_PIXELS, 0);
|
||||
if (fail) {
|
||||
vp9_denoiser_free(denoiser);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vp9_denoiser_realloc_svc(VP9_COMMON *cm, VP9_DENOISER *denoiser,
|
||||
struct SVC *svc, int svc_buf_shift,
|
||||
int refresh_alt, int refresh_gld, int refresh_lst,
|
||||
int alt_fb_idx, int gld_fb_idx, int lst_fb_idx) {
|
||||
int fail = 0;
|
||||
if (svc->temporal_layering_mode == VP9E_TEMPORAL_LAYERING_MODE_BYPASS &&
|
||||
svc->use_set_ref_frame_config) {
|
||||
int i;
|
||||
for (i = 0; i < REF_FRAMES; i++) {
|
||||
if (cm->frame_type == KEY_FRAME ||
|
||||
svc->update_buffer_slot[svc->spatial_layer_id] & (1 << i)) {
|
||||
fail = vp9_denoiser_realloc_svc_helper(cm, denoiser,
|
||||
i + 1 + svc_buf_shift);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (refresh_alt) {
|
||||
// Increase the frame buffer index by 1 to map it to the buffer index in
|
||||
// the denoiser.
|
||||
fail = vp9_denoiser_realloc_svc_helper(cm, denoiser,
|
||||
alt_fb_idx + 1 + svc_buf_shift);
|
||||
if (fail) return 1;
|
||||
}
|
||||
if (refresh_gld) {
|
||||
fail = vp9_denoiser_realloc_svc_helper(cm, denoiser,
|
||||
gld_fb_idx + 1 + svc_buf_shift);
|
||||
if (fail) return 1;
|
||||
}
|
||||
if (refresh_lst) {
|
||||
fail = vp9_denoiser_realloc_svc_helper(cm, denoiser,
|
||||
lst_fb_idx + 1 + svc_buf_shift);
|
||||
if (fail) return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vp9_denoiser_alloc(VP9_COMMON *cm, struct SVC *svc, VP9_DENOISER *denoiser,
|
||||
int use_svc, int noise_sen, int width, int height,
|
||||
int ssx, int ssy,
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
int use_highbitdepth,
|
||||
#endif
|
||||
int border) {
|
||||
int i, layer, fail, init_num_ref_frames;
|
||||
const int legacy_byte_alignment = 0;
|
||||
int num_layers = 1;
|
||||
int scaled_width = width;
|
||||
int scaled_height = height;
|
||||
if (use_svc) {
|
||||
LAYER_CONTEXT *lc = &svc->layer_context[svc->spatial_layer_id *
|
||||
svc->number_temporal_layers +
|
||||
svc->temporal_layer_id];
|
||||
get_layer_resolution(width, height, lc->scaling_factor_num,
|
||||
lc->scaling_factor_den, &scaled_width, &scaled_height);
|
||||
// For SVC: only denoise at most 2 spatial (highest) layers.
|
||||
if (noise_sen >= 2)
|
||||
// Denoise from one spatial layer below the top.
|
||||
svc->first_layer_denoise = VPXMAX(svc->number_spatial_layers - 2, 0);
|
||||
else
|
||||
// Only denoise the top spatial layer.
|
||||
svc->first_layer_denoise = VPXMAX(svc->number_spatial_layers - 1, 0);
|
||||
num_layers = svc->number_spatial_layers - svc->first_layer_denoise;
|
||||
}
|
||||
assert(denoiser != NULL);
|
||||
denoiser->num_ref_frames = use_svc ? SVC_REF_FRAMES : NONSVC_REF_FRAMES;
|
||||
init_num_ref_frames = use_svc ? MAX_REF_FRAMES : NONSVC_REF_FRAMES;
|
||||
denoiser->num_layers = num_layers;
|
||||
CHECK_MEM_ERROR(cm, denoiser->running_avg_y,
|
||||
vpx_calloc(denoiser->num_ref_frames * num_layers,
|
||||
sizeof(denoiser->running_avg_y[0])));
|
||||
CHECK_MEM_ERROR(
|
||||
cm, denoiser->mc_running_avg_y,
|
||||
vpx_calloc(num_layers, sizeof(denoiser->mc_running_avg_y[0])));
|
||||
|
||||
for (layer = 0; layer < num_layers; ++layer) {
|
||||
const int denoise_width = (layer == 0) ? width : scaled_width;
|
||||
const int denoise_height = (layer == 0) ? height : scaled_height;
|
||||
for (i = 0; i < init_num_ref_frames; ++i) {
|
||||
fail = vpx_alloc_frame_buffer(
|
||||
&denoiser->running_avg_y[i + denoiser->num_ref_frames * layer],
|
||||
denoise_width, denoise_height, ssx, ssy,
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
use_highbitdepth,
|
||||
#endif
|
||||
border, legacy_byte_alignment);
|
||||
if (fail) {
|
||||
vp9_denoiser_free(denoiser);
|
||||
return 1;
|
||||
}
|
||||
#ifdef OUTPUT_YUV_DENOISED
|
||||
make_grayscale(&denoiser->running_avg_y[i]);
|
||||
#endif
|
||||
}
|
||||
|
||||
fail = vpx_alloc_frame_buffer(&denoiser->mc_running_avg_y[layer],
|
||||
denoise_width, denoise_height, ssx, ssy,
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
use_highbitdepth,
|
||||
#endif
|
||||
border, legacy_byte_alignment);
|
||||
if (fail) {
|
||||
vp9_denoiser_free(denoiser);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// denoiser->last_source only used for noise_estimation, so only for top
|
||||
// layer.
|
||||
fail = vpx_alloc_frame_buffer(&denoiser->last_source, width, height, ssx, ssy,
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
use_highbitdepth,
|
||||
#endif
|
||||
border, legacy_byte_alignment);
|
||||
if (fail) {
|
||||
vp9_denoiser_free(denoiser);
|
||||
return 1;
|
||||
}
|
||||
#ifdef OUTPUT_YUV_DENOISED
|
||||
make_grayscale(&denoiser->running_avg_y[i]);
|
||||
#endif
|
||||
denoiser->frame_buffer_initialized = 1;
|
||||
denoiser->denoising_level = kDenMedium;
|
||||
denoiser->prev_denoising_level = kDenMedium;
|
||||
denoiser->reset = 0;
|
||||
denoiser->current_denoiser_frame = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vp9_denoiser_free(VP9_DENOISER *denoiser) {
|
||||
int i;
|
||||
if (denoiser == NULL) {
|
||||
return;
|
||||
}
|
||||
denoiser->frame_buffer_initialized = 0;
|
||||
for (i = 0; i < denoiser->num_ref_frames * denoiser->num_layers; ++i) {
|
||||
vpx_free_frame_buffer(&denoiser->running_avg_y[i]);
|
||||
}
|
||||
vpx_free(denoiser->running_avg_y);
|
||||
denoiser->running_avg_y = NULL;
|
||||
|
||||
for (i = 0; i < denoiser->num_layers; ++i) {
|
||||
vpx_free_frame_buffer(&denoiser->mc_running_avg_y[i]);
|
||||
}
|
||||
|
||||
vpx_free(denoiser->mc_running_avg_y);
|
||||
denoiser->mc_running_avg_y = NULL;
|
||||
vpx_free_frame_buffer(&denoiser->last_source);
|
||||
}
|
||||
|
||||
static void force_refresh_longterm_ref(VP9_COMP *const cpi) {
|
||||
SVC *const svc = &cpi->svc;
|
||||
// If long term reference is used, force refresh of that slot, so
|
||||
// denoiser buffer for long term reference stays in sync.
|
||||
if (svc->use_gf_temporal_ref_current_layer) {
|
||||
int index = svc->spatial_layer_id;
|
||||
if (svc->number_spatial_layers == 3) index = svc->spatial_layer_id - 1;
|
||||
assert(index >= 0);
|
||||
cpi->alt_fb_idx = svc->buffer_gf_temporal_ref[index].idx;
|
||||
cpi->refresh_alt_ref_frame = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_denoiser_set_noise_level(VP9_COMP *const cpi, int noise_level) {
|
||||
VP9_DENOISER *const denoiser = &cpi->denoiser;
|
||||
denoiser->denoising_level = noise_level;
|
||||
if (denoiser->denoising_level > kDenLowLow &&
|
||||
denoiser->prev_denoising_level == kDenLowLow) {
|
||||
denoiser->reset = 1;
|
||||
force_refresh_longterm_ref(cpi);
|
||||
} else {
|
||||
denoiser->reset = 0;
|
||||
}
|
||||
denoiser->prev_denoising_level = denoiser->denoising_level;
|
||||
}
|
||||
|
||||
// Scale/increase the partition threshold
|
||||
// for denoiser speed-up.
|
||||
int64_t vp9_scale_part_thresh(int64_t threshold, VP9_DENOISER_LEVEL noise_level,
|
||||
int content_state, int temporal_layer_id) {
|
||||
if ((content_state == kLowSadLowSumdiff) ||
|
||||
(content_state == kHighSadLowSumdiff) ||
|
||||
(content_state == kLowVarHighSumdiff) || (noise_level == kDenHigh) ||
|
||||
(temporal_layer_id != 0)) {
|
||||
int64_t scaled_thr =
|
||||
(temporal_layer_id < 2) ? (3 * threshold) >> 1 : (7 * threshold) >> 2;
|
||||
return scaled_thr;
|
||||
} else {
|
||||
return (5 * threshold) >> 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Scale/increase the ac skip threshold for
|
||||
// denoiser speed-up.
|
||||
int64_t vp9_scale_acskip_thresh(int64_t threshold,
|
||||
VP9_DENOISER_LEVEL noise_level, int abs_sumdiff,
|
||||
int temporal_layer_id) {
|
||||
if (noise_level >= kDenLow && abs_sumdiff < 5)
|
||||
return threshold *=
|
||||
(noise_level == kDenLow) ? 2 : (temporal_layer_id == 2) ? 10 : 6;
|
||||
else
|
||||
return threshold;
|
||||
}
|
||||
|
||||
void vp9_denoiser_reset_on_first_frame(VP9_COMP *const cpi) {
|
||||
if (vp9_denoise_svc_non_key(cpi) &&
|
||||
cpi->denoiser.current_denoiser_frame == 0) {
|
||||
cpi->denoiser.reset = 1;
|
||||
force_refresh_longterm_ref(cpi);
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_denoiser_update_ref_frame(VP9_COMP *const cpi) {
|
||||
VP9_COMMON *const cm = &cpi->common;
|
||||
SVC *const svc = &cpi->svc;
|
||||
|
||||
if (cpi->oxcf.noise_sensitivity > 0 && denoise_svc(cpi) &&
|
||||
cpi->denoiser.denoising_level > kDenLowLow) {
|
||||
int svc_refresh_denoiser_buffers = 0;
|
||||
int denoise_svc_second_layer = 0;
|
||||
FRAME_TYPE frame_type = cm->intra_only ? KEY_FRAME : cm->frame_type;
|
||||
cpi->denoiser.current_denoiser_frame++;
|
||||
if (cpi->use_svc) {
|
||||
const int svc_buf_shift =
|
||||
svc->number_spatial_layers - svc->spatial_layer_id == 2
|
||||
? cpi->denoiser.num_ref_frames
|
||||
: 0;
|
||||
int layer =
|
||||
LAYER_IDS_TO_IDX(svc->spatial_layer_id, svc->temporal_layer_id,
|
||||
svc->number_temporal_layers);
|
||||
LAYER_CONTEXT *const lc = &svc->layer_context[layer];
|
||||
svc_refresh_denoiser_buffers =
|
||||
lc->is_key_frame || svc->spatial_layer_sync[svc->spatial_layer_id];
|
||||
denoise_svc_second_layer =
|
||||
svc->number_spatial_layers - svc->spatial_layer_id == 2 ? 1 : 0;
|
||||
// Check if we need to allocate extra buffers in the denoiser
|
||||
// for refreshed frames.
|
||||
if (vp9_denoiser_realloc_svc(cm, &cpi->denoiser, svc, svc_buf_shift,
|
||||
cpi->refresh_alt_ref_frame,
|
||||
cpi->refresh_golden_frame,
|
||||
cpi->refresh_last_frame, cpi->alt_fb_idx,
|
||||
cpi->gld_fb_idx, cpi->lst_fb_idx))
|
||||
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
|
||||
"Failed to re-allocate denoiser for SVC");
|
||||
}
|
||||
vp9_denoiser_update_frame_info(
|
||||
&cpi->denoiser, *cpi->Source, svc, frame_type,
|
||||
cpi->refresh_alt_ref_frame, cpi->refresh_golden_frame,
|
||||
cpi->refresh_last_frame, cpi->alt_fb_idx, cpi->gld_fb_idx,
|
||||
cpi->lst_fb_idx, cpi->resize_pending, svc_refresh_denoiser_buffers,
|
||||
denoise_svc_second_layer);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef OUTPUT_YUV_DENOISED
|
||||
static void make_grayscale(YV12_BUFFER_CONFIG *yuv) {
|
||||
int r, c;
|
||||
uint8_t *u = yuv->u_buffer;
|
||||
uint8_t *v = yuv->v_buffer;
|
||||
|
||||
for (r = 0; r < yuv->uv_height; ++r) {
|
||||
for (c = 0; c < yuv->uv_width; ++c) {
|
||||
u[c] = UINT8_MAX / 2;
|
||||
v[c] = UINT8_MAX / 2;
|
||||
}
|
||||
u += yuv->uv_stride;
|
||||
v += yuv->uv_stride;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* 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_ENCODER_VP9_DENOISER_H_
|
||||
#define VPX_VP9_ENCODER_VP9_DENOISER_H_
|
||||
|
||||
#include "vp9/encoder/vp9_block.h"
|
||||
#include "vp9/encoder/vp9_skin_detection.h"
|
||||
#include "vpx_scale/yv12config.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define MOTION_MAGNITUDE_THRESHOLD (8 * 3)
|
||||
|
||||
// Denoiser is used in non svc real-time mode which does not use alt-ref, so no
|
||||
// need to allocate for it, and hence we need MAX_REF_FRAME - 1
|
||||
#define NONSVC_REF_FRAMES MAX_REF_FRAMES - 1
|
||||
|
||||
// Number of frame buffers when SVC is used. [0] for current denoised buffer and
|
||||
// [1..8] for REF_FRAMES
|
||||
#define SVC_REF_FRAMES 9
|
||||
|
||||
typedef enum vp9_denoiser_decision {
|
||||
COPY_BLOCK,
|
||||
FILTER_BLOCK,
|
||||
FILTER_ZEROMV_BLOCK
|
||||
} VP9_DENOISER_DECISION;
|
||||
|
||||
typedef enum vp9_denoiser_level {
|
||||
kDenLowLow,
|
||||
kDenLow,
|
||||
kDenMedium,
|
||||
kDenHigh
|
||||
} VP9_DENOISER_LEVEL;
|
||||
|
||||
typedef struct vp9_denoiser {
|
||||
YV12_BUFFER_CONFIG *running_avg_y;
|
||||
YV12_BUFFER_CONFIG *mc_running_avg_y;
|
||||
YV12_BUFFER_CONFIG last_source;
|
||||
int frame_buffer_initialized;
|
||||
int reset;
|
||||
int num_ref_frames;
|
||||
int num_layers;
|
||||
unsigned int current_denoiser_frame;
|
||||
VP9_DENOISER_LEVEL denoising_level;
|
||||
VP9_DENOISER_LEVEL prev_denoising_level;
|
||||
} VP9_DENOISER;
|
||||
|
||||
typedef struct {
|
||||
int64_t zero_last_cost_orig;
|
||||
int *ref_frame_cost;
|
||||
int_mv (*frame_mv)[MAX_REF_FRAMES];
|
||||
int reuse_inter_pred;
|
||||
TX_SIZE best_tx_size;
|
||||
PREDICTION_MODE best_mode;
|
||||
MV_REFERENCE_FRAME best_ref_frame;
|
||||
INTERP_FILTER best_pred_filter;
|
||||
uint8_t best_mode_skip_txfm;
|
||||
} VP9_PICKMODE_CTX_DEN;
|
||||
|
||||
struct VP9_COMP;
|
||||
struct SVC;
|
||||
|
||||
void vp9_denoiser_update_frame_info(
|
||||
VP9_DENOISER *denoiser, YV12_BUFFER_CONFIG src, struct SVC *svc,
|
||||
FRAME_TYPE frame_type, int refresh_alt_ref_frame, int refresh_golden_frame,
|
||||
int refresh_last_frame, int alt_fb_idx, int gld_fb_idx, int lst_fb_idx,
|
||||
int resized, int svc_refresh_denoiser_buffers, int second_spatial_layer);
|
||||
|
||||
void vp9_denoiser_denoise(struct VP9_COMP *cpi, MACROBLOCK *mb, int mi_row,
|
||||
int mi_col, BLOCK_SIZE bs, PICK_MODE_CONTEXT *ctx,
|
||||
VP9_DENOISER_DECISION *denoiser_decision,
|
||||
int use_gf_temporal_ref);
|
||||
|
||||
void vp9_denoiser_reset_frame_stats(PICK_MODE_CONTEXT *ctx);
|
||||
|
||||
void vp9_denoiser_update_frame_stats(MODE_INFO *mi, unsigned int sse,
|
||||
PREDICTION_MODE mode,
|
||||
PICK_MODE_CONTEXT *ctx);
|
||||
|
||||
int vp9_denoiser_realloc_svc(VP9_COMMON *cm, VP9_DENOISER *denoiser,
|
||||
struct SVC *svc, int svc_buf_shift,
|
||||
int refresh_alt, int refresh_gld, int refresh_lst,
|
||||
int alt_fb_idx, int gld_fb_idx, int lst_fb_idx);
|
||||
|
||||
int vp9_denoiser_alloc(VP9_COMMON *cm, struct SVC *svc, VP9_DENOISER *denoiser,
|
||||
int use_svc, int noise_sen, int width, int height,
|
||||
int ssx, int ssy,
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
int use_highbitdepth,
|
||||
#endif
|
||||
int border);
|
||||
|
||||
#if CONFIG_VP9_TEMPORAL_DENOISING
|
||||
// This function is used by both c and sse2 denoiser implementations.
|
||||
// Define it as a static function within the scope where vp9_denoiser.h
|
||||
// is referenced.
|
||||
static INLINE int total_adj_strong_thresh(BLOCK_SIZE bs,
|
||||
int increase_denoising) {
|
||||
return (1 << num_pels_log2_lookup[bs]) * (increase_denoising ? 3 : 2);
|
||||
}
|
||||
#endif
|
||||
|
||||
void vp9_denoiser_free(VP9_DENOISER *denoiser);
|
||||
|
||||
void vp9_denoiser_set_noise_level(struct VP9_COMP *const cpi, int noise_level);
|
||||
|
||||
void vp9_denoiser_reset_on_first_frame(struct VP9_COMP *const cpi);
|
||||
|
||||
int64_t vp9_scale_part_thresh(int64_t threshold, VP9_DENOISER_LEVEL noise_level,
|
||||
int content_state, int temporal_layer_id);
|
||||
|
||||
int64_t vp9_scale_acskip_thresh(int64_t threshold,
|
||||
VP9_DENOISER_LEVEL noise_level, int abs_sumdiff,
|
||||
int temporal_layer_id);
|
||||
|
||||
void vp9_denoiser_update_ref_frame(struct VP9_COMP *const cpi);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_ENCODER_VP9_DENOISER_H_
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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_ENCODER_VP9_ENCODEFRAME_H_
|
||||
#define VPX_VP9_ENCODER_VP9_ENCODEFRAME_H_
|
||||
|
||||
#include "vpx/vpx_integer.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct macroblock;
|
||||
struct yv12_buffer_config;
|
||||
struct VP9_COMP;
|
||||
struct ThreadData;
|
||||
|
||||
// Constants used in SOURCE_VAR_BASED_PARTITION
|
||||
#define VAR_HIST_MAX_BG_VAR 1000
|
||||
#define VAR_HIST_FACTOR 10
|
||||
#define VAR_HIST_BINS (VAR_HIST_MAX_BG_VAR / VAR_HIST_FACTOR + 1)
|
||||
#define VAR_HIST_LARGE_CUT_OFF 75
|
||||
#define VAR_HIST_SMALL_CUT_OFF 45
|
||||
|
||||
void vp9_setup_src_planes(struct macroblock *x,
|
||||
const struct yv12_buffer_config *src, int mi_row,
|
||||
int mi_col);
|
||||
|
||||
void vp9_encode_frame(struct VP9_COMP *cpi);
|
||||
|
||||
void vp9_init_tile_data(struct VP9_COMP *cpi);
|
||||
void vp9_encode_tile(struct VP9_COMP *cpi, struct ThreadData *td, int tile_row,
|
||||
int tile_col);
|
||||
|
||||
void vp9_encode_sb_row(struct VP9_COMP *cpi, struct ThreadData *td,
|
||||
int tile_row, int tile_col, int mi_row);
|
||||
|
||||
void vp9_set_variance_partition_thresholds(struct VP9_COMP *cpi, int q,
|
||||
int content_state);
|
||||
|
||||
struct KMEANS_DATA;
|
||||
void vp9_kmeans(double *ctr_ls, double *boundary_ls, int *count_ls, int k,
|
||||
struct KMEANS_DATA *arr, int size);
|
||||
int vp9_get_group_idx(double value, double *boundary_ls, int k);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_ENCODER_VP9_ENCODEFRAME_H_
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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_ENCODER_VP9_ENCODEMB_H_
|
||||
#define VPX_VP9_ENCODER_VP9_ENCODEMB_H_
|
||||
|
||||
#include "./vpx_config.h"
|
||||
#include "vp9/encoder/vp9_block.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct encode_b_args {
|
||||
MACROBLOCK *x;
|
||||
int enable_coeff_opt;
|
||||
ENTROPY_CONTEXT *ta;
|
||||
ENTROPY_CONTEXT *tl;
|
||||
int8_t *skip;
|
||||
#if CONFIG_MISMATCH_DEBUG
|
||||
int mi_row;
|
||||
int mi_col;
|
||||
int output_enabled;
|
||||
#endif
|
||||
};
|
||||
int vp9_optimize_b(MACROBLOCK *mb, int plane, int block, TX_SIZE tx_size,
|
||||
int ctx);
|
||||
void vp9_encode_sb(MACROBLOCK *x, BLOCK_SIZE bsize, int mi_row, int mi_col,
|
||||
int output_enabled);
|
||||
void vp9_encode_sby_pass1(MACROBLOCK *x, BLOCK_SIZE bsize);
|
||||
void vp9_xform_quant_fp(MACROBLOCK *x, int plane, int block, int row, int col,
|
||||
BLOCK_SIZE plane_bsize, TX_SIZE tx_size);
|
||||
void vp9_xform_quant_dc(MACROBLOCK *x, int plane, int block, int row, int col,
|
||||
BLOCK_SIZE plane_bsize, TX_SIZE tx_size);
|
||||
void vp9_xform_quant(MACROBLOCK *x, int plane, int block, int row, int col,
|
||||
BLOCK_SIZE plane_bsize, TX_SIZE tx_size);
|
||||
|
||||
void vp9_subtract_plane(MACROBLOCK *x, BLOCK_SIZE bsize, int plane);
|
||||
|
||||
void vp9_encode_block_intra(int plane, int block, int row, int col,
|
||||
BLOCK_SIZE plane_bsize, TX_SIZE tx_size, void *arg);
|
||||
|
||||
void vp9_encode_intra_block_plane(MACROBLOCK *x, BLOCK_SIZE bsize, int plane,
|
||||
int enable_optimize_b);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_ENCODER_VP9_ENCODEMB_H_
|
||||
@@ -0,0 +1,271 @@
|
||||
/*
|
||||
* Copyright (c) 2010 The WebM project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "vp9/common/vp9_common.h"
|
||||
#include "vp9/common/vp9_entropymode.h"
|
||||
|
||||
#include "vp9/encoder/vp9_cost.h"
|
||||
#include "vp9/encoder/vp9_encodemv.h"
|
||||
|
||||
#include "vpx_dsp/vpx_dsp_common.h"
|
||||
|
||||
static struct vp9_token mv_joint_encodings[MV_JOINTS];
|
||||
static struct vp9_token mv_class_encodings[MV_CLASSES];
|
||||
static struct vp9_token mv_fp_encodings[MV_FP_SIZE];
|
||||
|
||||
void vp9_entropy_mv_init(void) {
|
||||
vp9_tokens_from_tree(mv_joint_encodings, vp9_mv_joint_tree);
|
||||
vp9_tokens_from_tree(mv_class_encodings, vp9_mv_class_tree);
|
||||
vp9_tokens_from_tree(mv_fp_encodings, vp9_mv_fp_tree);
|
||||
}
|
||||
|
||||
static void encode_mv_component(vpx_writer *w, int comp,
|
||||
const nmv_component *mvcomp, int usehp) {
|
||||
int offset;
|
||||
const int sign = comp < 0;
|
||||
const int mag = sign ? -comp : comp;
|
||||
const int mv_class = vp9_get_mv_class(mag - 1, &offset);
|
||||
const int d = offset >> 3; // int mv data
|
||||
const int fr = (offset >> 1) & 3; // fractional mv data
|
||||
const int hp = offset & 1; // high precision mv data
|
||||
|
||||
assert(comp != 0);
|
||||
|
||||
// Sign
|
||||
vpx_write(w, sign, mvcomp->sign);
|
||||
|
||||
// Class
|
||||
vp9_write_token(w, vp9_mv_class_tree, mvcomp->classes,
|
||||
&mv_class_encodings[mv_class]);
|
||||
|
||||
// Integer bits
|
||||
if (mv_class == MV_CLASS_0) {
|
||||
vpx_write(w, d, mvcomp->class0[0]);
|
||||
} else {
|
||||
int i;
|
||||
const int n = mv_class + CLASS0_BITS - 1; // number of bits
|
||||
for (i = 0; i < n; ++i) vpx_write(w, (d >> i) & 1, mvcomp->bits[i]);
|
||||
}
|
||||
|
||||
// Fractional bits
|
||||
vp9_write_token(w, vp9_mv_fp_tree,
|
||||
mv_class == MV_CLASS_0 ? mvcomp->class0_fp[d] : mvcomp->fp,
|
||||
&mv_fp_encodings[fr]);
|
||||
|
||||
// High precision bit
|
||||
if (usehp)
|
||||
vpx_write(w, hp, mv_class == MV_CLASS_0 ? mvcomp->class0_hp : mvcomp->hp);
|
||||
}
|
||||
|
||||
static void build_nmv_component_cost_table(int *mvcost,
|
||||
const nmv_component *const mvcomp,
|
||||
int usehp) {
|
||||
int sign_cost[2], class_cost[MV_CLASSES], class0_cost[CLASS0_SIZE];
|
||||
int bits_cost[MV_OFFSET_BITS][2];
|
||||
int class0_fp_cost[CLASS0_SIZE][MV_FP_SIZE], fp_cost[MV_FP_SIZE];
|
||||
int class0_hp_cost[2], hp_cost[2];
|
||||
int i;
|
||||
int c, o;
|
||||
|
||||
sign_cost[0] = vp9_cost_zero(mvcomp->sign);
|
||||
sign_cost[1] = vp9_cost_one(mvcomp->sign);
|
||||
vp9_cost_tokens(class_cost, mvcomp->classes, vp9_mv_class_tree);
|
||||
vp9_cost_tokens(class0_cost, mvcomp->class0, vp9_mv_class0_tree);
|
||||
for (i = 0; i < MV_OFFSET_BITS; ++i) {
|
||||
bits_cost[i][0] = vp9_cost_zero(mvcomp->bits[i]);
|
||||
bits_cost[i][1] = vp9_cost_one(mvcomp->bits[i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < CLASS0_SIZE; ++i)
|
||||
vp9_cost_tokens(class0_fp_cost[i], mvcomp->class0_fp[i], vp9_mv_fp_tree);
|
||||
vp9_cost_tokens(fp_cost, mvcomp->fp, vp9_mv_fp_tree);
|
||||
|
||||
// Always build the hp costs to avoid an uninitialized warning from gcc
|
||||
class0_hp_cost[0] = vp9_cost_zero(mvcomp->class0_hp);
|
||||
class0_hp_cost[1] = vp9_cost_one(mvcomp->class0_hp);
|
||||
hp_cost[0] = vp9_cost_zero(mvcomp->hp);
|
||||
hp_cost[1] = vp9_cost_one(mvcomp->hp);
|
||||
|
||||
mvcost[0] = 0;
|
||||
// MV_CLASS_0
|
||||
for (o = 0; o < (CLASS0_SIZE << 3); ++o) {
|
||||
int d, e, f;
|
||||
int cost = class_cost[MV_CLASS_0];
|
||||
int v = o + 1;
|
||||
d = (o >> 3); /* int mv data */
|
||||
f = (o >> 1) & 3; /* fractional pel mv data */
|
||||
cost += class0_cost[d];
|
||||
cost += class0_fp_cost[d][f];
|
||||
if (usehp) {
|
||||
e = (o & 1); /* high precision mv data */
|
||||
cost += class0_hp_cost[e];
|
||||
}
|
||||
mvcost[v] = cost + sign_cost[0];
|
||||
mvcost[-v] = cost + sign_cost[1];
|
||||
}
|
||||
for (c = MV_CLASS_1; c < MV_CLASSES; ++c) {
|
||||
int d;
|
||||
for (d = 0; d < (1 << c); ++d) {
|
||||
int f;
|
||||
int whole_cost = class_cost[c];
|
||||
int b = c + CLASS0_BITS - 1; /* number of bits */
|
||||
for (i = 0; i < b; ++i) whole_cost += bits_cost[i][((d >> i) & 1)];
|
||||
for (f = 0; f < 4; ++f) {
|
||||
int cost = whole_cost + fp_cost[f];
|
||||
int v = (CLASS0_SIZE << (c + 2)) + d * 8 + f * 2 /* + e */ + 1;
|
||||
if (usehp) {
|
||||
mvcost[v] = cost + hp_cost[0] + sign_cost[0];
|
||||
mvcost[-v] = cost + hp_cost[0] + sign_cost[1];
|
||||
if (v + 1 > MV_MAX) break;
|
||||
mvcost[v + 1] = cost + hp_cost[1] + sign_cost[0];
|
||||
mvcost[-v - 1] = cost + hp_cost[1] + sign_cost[1];
|
||||
} else {
|
||||
mvcost[v] = cost + sign_cost[0];
|
||||
mvcost[-v] = cost + sign_cost[1];
|
||||
if (v + 1 > MV_MAX) break;
|
||||
mvcost[v + 1] = cost + sign_cost[0];
|
||||
mvcost[-v - 1] = cost + sign_cost[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int update_mv(vpx_writer *w, const unsigned int ct[2], vpx_prob *cur_p,
|
||||
vpx_prob upd_p) {
|
||||
const vpx_prob new_p = get_binary_prob(ct[0], ct[1]) | 1;
|
||||
const int update = cost_branch256(ct, *cur_p) + vp9_cost_zero(upd_p) >
|
||||
cost_branch256(ct, new_p) + vp9_cost_one(upd_p) +
|
||||
(7 << VP9_PROB_COST_SHIFT);
|
||||
vpx_write(w, update, upd_p);
|
||||
if (update) {
|
||||
*cur_p = new_p;
|
||||
vpx_write_literal(w, new_p >> 1, 7);
|
||||
}
|
||||
return update;
|
||||
}
|
||||
|
||||
static void write_mv_update(const vpx_tree_index *tree,
|
||||
vpx_prob probs[/*n - 1*/],
|
||||
const unsigned int counts[/*n - 1*/], int n,
|
||||
vpx_writer *w) {
|
||||
int i;
|
||||
unsigned int branch_ct[32][2];
|
||||
|
||||
// Assuming max number of probabilities <= 32
|
||||
assert(n <= 32);
|
||||
|
||||
vp9_tree_probs_from_distribution(tree, branch_ct, counts);
|
||||
for (i = 0; i < n - 1; ++i)
|
||||
update_mv(w, branch_ct[i], &probs[i], MV_UPDATE_PROB);
|
||||
}
|
||||
|
||||
void vp9_write_nmv_probs(VP9_COMMON *cm, int usehp, vpx_writer *w,
|
||||
nmv_context_counts *const counts) {
|
||||
int i, j;
|
||||
nmv_context *const mvc = &cm->fc->nmvc;
|
||||
|
||||
write_mv_update(vp9_mv_joint_tree, mvc->joints, counts->joints, MV_JOINTS, w);
|
||||
|
||||
for (i = 0; i < 2; ++i) {
|
||||
nmv_component *comp = &mvc->comps[i];
|
||||
nmv_component_counts *comp_counts = &counts->comps[i];
|
||||
|
||||
update_mv(w, comp_counts->sign, &comp->sign, MV_UPDATE_PROB);
|
||||
write_mv_update(vp9_mv_class_tree, comp->classes, comp_counts->classes,
|
||||
MV_CLASSES, w);
|
||||
write_mv_update(vp9_mv_class0_tree, comp->class0, comp_counts->class0,
|
||||
CLASS0_SIZE, w);
|
||||
for (j = 0; j < MV_OFFSET_BITS; ++j)
|
||||
update_mv(w, comp_counts->bits[j], &comp->bits[j], MV_UPDATE_PROB);
|
||||
}
|
||||
|
||||
for (i = 0; i < 2; ++i) {
|
||||
for (j = 0; j < CLASS0_SIZE; ++j)
|
||||
write_mv_update(vp9_mv_fp_tree, mvc->comps[i].class0_fp[j],
|
||||
counts->comps[i].class0_fp[j], MV_FP_SIZE, w);
|
||||
|
||||
write_mv_update(vp9_mv_fp_tree, mvc->comps[i].fp, counts->comps[i].fp,
|
||||
MV_FP_SIZE, w);
|
||||
}
|
||||
|
||||
if (usehp) {
|
||||
for (i = 0; i < 2; ++i) {
|
||||
update_mv(w, counts->comps[i].class0_hp, &mvc->comps[i].class0_hp,
|
||||
MV_UPDATE_PROB);
|
||||
update_mv(w, counts->comps[i].hp, &mvc->comps[i].hp, MV_UPDATE_PROB);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_encode_mv(VP9_COMP *cpi, vpx_writer *w, const MV *mv, const MV *ref,
|
||||
const nmv_context *mvctx, int usehp,
|
||||
unsigned int *const max_mv_magnitude) {
|
||||
const MV diff = { mv->row - ref->row, mv->col - ref->col };
|
||||
const MV_JOINT_TYPE j = vp9_get_mv_joint(&diff);
|
||||
usehp = usehp && use_mv_hp(ref);
|
||||
|
||||
vp9_write_token(w, vp9_mv_joint_tree, mvctx->joints, &mv_joint_encodings[j]);
|
||||
if (mv_joint_vertical(j))
|
||||
encode_mv_component(w, diff.row, &mvctx->comps[0], usehp);
|
||||
|
||||
if (mv_joint_horizontal(j))
|
||||
encode_mv_component(w, diff.col, &mvctx->comps[1], usehp);
|
||||
|
||||
// If auto_mv_step_size is enabled then keep track of the largest
|
||||
// motion vector component used.
|
||||
if (cpi->sf.mv.auto_mv_step_size) {
|
||||
const unsigned int maxv = VPXMAX(abs(mv->row), abs(mv->col)) >> 3;
|
||||
*max_mv_magnitude = VPXMAX(maxv, *max_mv_magnitude);
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_build_nmv_cost_table(int *mvjoint, int *mvcost[2],
|
||||
const nmv_context *ctx, int usehp) {
|
||||
vp9_cost_tokens(mvjoint, ctx->joints, vp9_mv_joint_tree);
|
||||
build_nmv_component_cost_table(mvcost[0], &ctx->comps[0], usehp);
|
||||
build_nmv_component_cost_table(mvcost[1], &ctx->comps[1], usehp);
|
||||
}
|
||||
|
||||
static void inc_mvs(const MODE_INFO *mi, const MB_MODE_INFO_EXT *mbmi_ext,
|
||||
const int_mv mvs[2], nmv_context_counts *counts) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 1 + has_second_ref(mi); ++i) {
|
||||
const MV *ref = &mbmi_ext->ref_mvs[mi->ref_frame[i]][0].as_mv;
|
||||
const MV diff = { mvs[i].as_mv.row - ref->row,
|
||||
mvs[i].as_mv.col - ref->col };
|
||||
vp9_inc_mv(&diff, counts);
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_update_mv_count(ThreadData *td) {
|
||||
const MACROBLOCKD *xd = &td->mb.e_mbd;
|
||||
const MODE_INFO *mi = xd->mi[0];
|
||||
const MB_MODE_INFO_EXT *mbmi_ext = td->mb.mbmi_ext;
|
||||
|
||||
if (mi->sb_type < BLOCK_8X8) {
|
||||
const int num_4x4_w = num_4x4_blocks_wide_lookup[mi->sb_type];
|
||||
const int num_4x4_h = num_4x4_blocks_high_lookup[mi->sb_type];
|
||||
int idx, idy;
|
||||
|
||||
for (idy = 0; idy < 2; idy += num_4x4_h) {
|
||||
for (idx = 0; idx < 2; idx += num_4x4_w) {
|
||||
const int i = idy * 2 + idx;
|
||||
if (mi->bmi[i].as_mode == NEWMV)
|
||||
inc_mvs(mi, mbmi_ext, mi->bmi[i].as_mv, &td->counts->mv);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (mi->mode == NEWMV) inc_mvs(mi, mbmi_ext, mi->mv, &td->counts->mv);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2010 The WebM project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef VPX_VP9_ENCODER_VP9_ENCODEMV_H_
|
||||
#define VPX_VP9_ENCODER_VP9_ENCODEMV_H_
|
||||
|
||||
#include "vp9/encoder/vp9_encoder.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void vp9_entropy_mv_init(void);
|
||||
|
||||
void vp9_write_nmv_probs(VP9_COMMON *cm, int usehp, vpx_writer *w,
|
||||
nmv_context_counts *const counts);
|
||||
|
||||
void vp9_encode_mv(VP9_COMP *cpi, vpx_writer *w, const MV *mv, const MV *ref,
|
||||
const nmv_context *mvctx, int usehp,
|
||||
unsigned int *const max_mv_magnitude);
|
||||
|
||||
void vp9_build_nmv_cost_table(int *mvjoint, int *mvcost[2],
|
||||
const nmv_context *ctx, int usehp);
|
||||
|
||||
void vp9_update_mv_count(ThreadData *td);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_ENCODER_VP9_ENCODEMV_H_
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,667 @@
|
||||
/*
|
||||
* Copyright (c) 2014 The WebM project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "vp9/encoder/vp9_encodeframe.h"
|
||||
#include "vp9/encoder/vp9_encoder.h"
|
||||
#include "vp9/encoder/vp9_ethread.h"
|
||||
#include "vp9/encoder/vp9_firstpass.h"
|
||||
#include "vp9/encoder/vp9_multi_thread.h"
|
||||
#include "vp9/encoder/vp9_temporal_filter.h"
|
||||
#include "vpx_dsp/vpx_dsp_common.h"
|
||||
|
||||
static void accumulate_rd_opt(ThreadData *td, ThreadData *td_t) {
|
||||
int i, j, k, l, m, n;
|
||||
|
||||
for (i = 0; i < REFERENCE_MODES; i++)
|
||||
td->rd_counts.comp_pred_diff[i] += td_t->rd_counts.comp_pred_diff[i];
|
||||
|
||||
for (i = 0; i < SWITCHABLE_FILTER_CONTEXTS; i++)
|
||||
td->rd_counts.filter_diff[i] += td_t->rd_counts.filter_diff[i];
|
||||
|
||||
for (i = 0; i < TX_SIZES; i++)
|
||||
for (j = 0; j < PLANE_TYPES; j++)
|
||||
for (k = 0; k < REF_TYPES; k++)
|
||||
for (l = 0; l < COEF_BANDS; l++)
|
||||
for (m = 0; m < COEFF_CONTEXTS; m++)
|
||||
for (n = 0; n < ENTROPY_TOKENS; n++)
|
||||
td->rd_counts.coef_counts[i][j][k][l][m][n] +=
|
||||
td_t->rd_counts.coef_counts[i][j][k][l][m][n];
|
||||
}
|
||||
|
||||
static int enc_worker_hook(void *arg1, void *unused) {
|
||||
EncWorkerData *const thread_data = (EncWorkerData *)arg1;
|
||||
VP9_COMP *const cpi = thread_data->cpi;
|
||||
const VP9_COMMON *const cm = &cpi->common;
|
||||
const int tile_cols = 1 << cm->log2_tile_cols;
|
||||
const int tile_rows = 1 << cm->log2_tile_rows;
|
||||
int t;
|
||||
|
||||
(void)unused;
|
||||
|
||||
for (t = thread_data->start; t < tile_rows * tile_cols;
|
||||
t += cpi->num_workers) {
|
||||
int tile_row = t / tile_cols;
|
||||
int tile_col = t % tile_cols;
|
||||
|
||||
vp9_encode_tile(cpi, thread_data->td, tile_row, tile_col);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_max_tile_cols(VP9_COMP *cpi) {
|
||||
const int aligned_width = ALIGN_POWER_OF_TWO(cpi->oxcf.width, MI_SIZE_LOG2);
|
||||
int mi_cols = aligned_width >> MI_SIZE_LOG2;
|
||||
int min_log2_tile_cols, max_log2_tile_cols;
|
||||
int log2_tile_cols;
|
||||
|
||||
vp9_get_tile_n_bits(mi_cols, &min_log2_tile_cols, &max_log2_tile_cols);
|
||||
log2_tile_cols =
|
||||
clamp(cpi->oxcf.tile_columns, min_log2_tile_cols, max_log2_tile_cols);
|
||||
if (cpi->oxcf.target_level == LEVEL_AUTO) {
|
||||
const int level_tile_cols =
|
||||
log_tile_cols_from_picsize_level(cpi->common.width, cpi->common.height);
|
||||
if (log2_tile_cols > level_tile_cols) {
|
||||
log2_tile_cols = VPXMAX(level_tile_cols, min_log2_tile_cols);
|
||||
}
|
||||
}
|
||||
return (1 << log2_tile_cols);
|
||||
}
|
||||
|
||||
static void create_enc_workers(VP9_COMP *cpi, int num_workers) {
|
||||
VP9_COMMON *const cm = &cpi->common;
|
||||
const VPxWorkerInterface *const winterface = vpx_get_worker_interface();
|
||||
int i;
|
||||
|
||||
// Only run once to create threads and allocate thread data.
|
||||
if (cpi->num_workers == 0) {
|
||||
int allocated_workers = num_workers;
|
||||
|
||||
// While using SVC, we need to allocate threads according to the highest
|
||||
// resolution. When row based multithreading is enabled, it is OK to
|
||||
// allocate more threads than the number of max tile columns.
|
||||
if (cpi->use_svc && !cpi->row_mt) {
|
||||
int max_tile_cols = get_max_tile_cols(cpi);
|
||||
allocated_workers = VPXMIN(cpi->oxcf.max_threads, max_tile_cols);
|
||||
}
|
||||
|
||||
CHECK_MEM_ERROR(cm, cpi->workers,
|
||||
vpx_malloc(allocated_workers * sizeof(*cpi->workers)));
|
||||
|
||||
CHECK_MEM_ERROR(cm, cpi->tile_thr_data,
|
||||
vpx_calloc(allocated_workers, sizeof(*cpi->tile_thr_data)));
|
||||
|
||||
for (i = 0; i < allocated_workers; i++) {
|
||||
VPxWorker *const worker = &cpi->workers[i];
|
||||
EncWorkerData *thread_data = &cpi->tile_thr_data[i];
|
||||
|
||||
++cpi->num_workers;
|
||||
winterface->init(worker);
|
||||
|
||||
if (i < allocated_workers - 1) {
|
||||
thread_data->cpi = cpi;
|
||||
|
||||
// Allocate thread data.
|
||||
CHECK_MEM_ERROR(cm, thread_data->td,
|
||||
vpx_memalign(32, sizeof(*thread_data->td)));
|
||||
vp9_zero(*thread_data->td);
|
||||
|
||||
// Set up pc_tree.
|
||||
thread_data->td->leaf_tree = NULL;
|
||||
thread_data->td->pc_tree = NULL;
|
||||
vp9_setup_pc_tree(cm, thread_data->td);
|
||||
|
||||
// Allocate frame counters in thread data.
|
||||
CHECK_MEM_ERROR(cm, thread_data->td->counts,
|
||||
vpx_calloc(1, sizeof(*thread_data->td->counts)));
|
||||
|
||||
// Create threads
|
||||
if (!winterface->reset(worker))
|
||||
vpx_internal_error(&cm->error, VPX_CODEC_ERROR,
|
||||
"Tile encoder thread creation failed");
|
||||
} else {
|
||||
// Main thread acts as a worker and uses the thread data in cpi.
|
||||
thread_data->cpi = cpi;
|
||||
thread_data->td = &cpi->td;
|
||||
}
|
||||
winterface->sync(worker);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void launch_enc_workers(VP9_COMP *cpi, VPxWorkerHook hook, void *data2,
|
||||
int num_workers) {
|
||||
const VPxWorkerInterface *const winterface = vpx_get_worker_interface();
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_workers; i++) {
|
||||
VPxWorker *const worker = &cpi->workers[i];
|
||||
worker->hook = hook;
|
||||
worker->data1 = &cpi->tile_thr_data[i];
|
||||
worker->data2 = data2;
|
||||
}
|
||||
|
||||
// Encode a frame
|
||||
for (i = 0; i < num_workers; i++) {
|
||||
VPxWorker *const worker = &cpi->workers[i];
|
||||
EncWorkerData *const thread_data = (EncWorkerData *)worker->data1;
|
||||
|
||||
// Set the starting tile for each thread.
|
||||
thread_data->start = i;
|
||||
|
||||
if (i == cpi->num_workers - 1)
|
||||
winterface->execute(worker);
|
||||
else
|
||||
winterface->launch(worker);
|
||||
}
|
||||
|
||||
// Encoding ends.
|
||||
for (i = 0; i < num_workers; i++) {
|
||||
VPxWorker *const worker = &cpi->workers[i];
|
||||
winterface->sync(worker);
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_encode_tiles_mt(VP9_COMP *cpi) {
|
||||
VP9_COMMON *const cm = &cpi->common;
|
||||
const int tile_cols = 1 << cm->log2_tile_cols;
|
||||
const int num_workers = VPXMIN(cpi->oxcf.max_threads, tile_cols);
|
||||
int i;
|
||||
|
||||
vp9_init_tile_data(cpi);
|
||||
|
||||
create_enc_workers(cpi, num_workers);
|
||||
|
||||
for (i = 0; i < num_workers; i++) {
|
||||
EncWorkerData *thread_data;
|
||||
thread_data = &cpi->tile_thr_data[i];
|
||||
|
||||
// Before encoding a frame, copy the thread data from cpi.
|
||||
if (thread_data->td != &cpi->td) {
|
||||
thread_data->td->mb = cpi->td.mb;
|
||||
thread_data->td->rd_counts = cpi->td.rd_counts;
|
||||
}
|
||||
if (thread_data->td->counts != &cpi->common.counts) {
|
||||
memcpy(thread_data->td->counts, &cpi->common.counts,
|
||||
sizeof(cpi->common.counts));
|
||||
}
|
||||
|
||||
// Handle use_nonrd_pick_mode case.
|
||||
if (cpi->sf.use_nonrd_pick_mode) {
|
||||
MACROBLOCK *const x = &thread_data->td->mb;
|
||||
MACROBLOCKD *const xd = &x->e_mbd;
|
||||
struct macroblock_plane *const p = x->plane;
|
||||
struct macroblockd_plane *const pd = xd->plane;
|
||||
PICK_MODE_CONTEXT *ctx = &thread_data->td->pc_root->none;
|
||||
int j;
|
||||
|
||||
for (j = 0; j < MAX_MB_PLANE; ++j) {
|
||||
p[j].coeff = ctx->coeff_pbuf[j][0];
|
||||
p[j].qcoeff = ctx->qcoeff_pbuf[j][0];
|
||||
pd[j].dqcoeff = ctx->dqcoeff_pbuf[j][0];
|
||||
p[j].eobs = ctx->eobs_pbuf[j][0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
launch_enc_workers(cpi, enc_worker_hook, NULL, num_workers);
|
||||
|
||||
for (i = 0; i < num_workers; i++) {
|
||||
VPxWorker *const worker = &cpi->workers[i];
|
||||
EncWorkerData *const thread_data = (EncWorkerData *)worker->data1;
|
||||
|
||||
// Accumulate counters.
|
||||
if (i < cpi->num_workers - 1) {
|
||||
vp9_accumulate_frame_counts(&cm->counts, thread_data->td->counts, 0);
|
||||
accumulate_rd_opt(&cpi->td, thread_data->td);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if !CONFIG_REALTIME_ONLY
|
||||
static void accumulate_fp_tile_stat(TileDataEnc *tile_data,
|
||||
TileDataEnc *tile_data_t) {
|
||||
tile_data->fp_data.intra_factor += tile_data_t->fp_data.intra_factor;
|
||||
tile_data->fp_data.brightness_factor +=
|
||||
tile_data_t->fp_data.brightness_factor;
|
||||
tile_data->fp_data.coded_error += tile_data_t->fp_data.coded_error;
|
||||
tile_data->fp_data.sr_coded_error += tile_data_t->fp_data.sr_coded_error;
|
||||
tile_data->fp_data.frame_noise_energy +=
|
||||
tile_data_t->fp_data.frame_noise_energy;
|
||||
tile_data->fp_data.intra_error += tile_data_t->fp_data.intra_error;
|
||||
tile_data->fp_data.intercount += tile_data_t->fp_data.intercount;
|
||||
tile_data->fp_data.second_ref_count += tile_data_t->fp_data.second_ref_count;
|
||||
tile_data->fp_data.neutral_count += tile_data_t->fp_data.neutral_count;
|
||||
tile_data->fp_data.intra_count_low += tile_data_t->fp_data.intra_count_low;
|
||||
tile_data->fp_data.intra_count_high += tile_data_t->fp_data.intra_count_high;
|
||||
tile_data->fp_data.intra_skip_count += tile_data_t->fp_data.intra_skip_count;
|
||||
tile_data->fp_data.mvcount += tile_data_t->fp_data.mvcount;
|
||||
tile_data->fp_data.sum_mvr += tile_data_t->fp_data.sum_mvr;
|
||||
tile_data->fp_data.sum_mvr_abs += tile_data_t->fp_data.sum_mvr_abs;
|
||||
tile_data->fp_data.sum_mvc += tile_data_t->fp_data.sum_mvc;
|
||||
tile_data->fp_data.sum_mvc_abs += tile_data_t->fp_data.sum_mvc_abs;
|
||||
tile_data->fp_data.sum_mvrs += tile_data_t->fp_data.sum_mvrs;
|
||||
tile_data->fp_data.sum_mvcs += tile_data_t->fp_data.sum_mvcs;
|
||||
tile_data->fp_data.sum_in_vectors += tile_data_t->fp_data.sum_in_vectors;
|
||||
tile_data->fp_data.intra_smooth_count +=
|
||||
tile_data_t->fp_data.intra_smooth_count;
|
||||
tile_data->fp_data.image_data_start_row =
|
||||
VPXMIN(tile_data->fp_data.image_data_start_row,
|
||||
tile_data_t->fp_data.image_data_start_row) == INVALID_ROW
|
||||
? VPXMAX(tile_data->fp_data.image_data_start_row,
|
||||
tile_data_t->fp_data.image_data_start_row)
|
||||
: VPXMIN(tile_data->fp_data.image_data_start_row,
|
||||
tile_data_t->fp_data.image_data_start_row);
|
||||
}
|
||||
#endif // !CONFIG_REALTIME_ONLY
|
||||
|
||||
// Allocate memory for row synchronization
|
||||
void vp9_row_mt_sync_mem_alloc(VP9RowMTSync *row_mt_sync, VP9_COMMON *cm,
|
||||
int rows) {
|
||||
row_mt_sync->rows = rows;
|
||||
#if CONFIG_MULTITHREAD
|
||||
{
|
||||
int i;
|
||||
|
||||
CHECK_MEM_ERROR(cm, row_mt_sync->mutex,
|
||||
vpx_malloc(sizeof(*row_mt_sync->mutex) * rows));
|
||||
if (row_mt_sync->mutex) {
|
||||
for (i = 0; i < rows; ++i) {
|
||||
pthread_mutex_init(&row_mt_sync->mutex[i], NULL);
|
||||
}
|
||||
}
|
||||
|
||||
CHECK_MEM_ERROR(cm, row_mt_sync->cond,
|
||||
vpx_malloc(sizeof(*row_mt_sync->cond) * rows));
|
||||
if (row_mt_sync->cond) {
|
||||
for (i = 0; i < rows; ++i) {
|
||||
pthread_cond_init(&row_mt_sync->cond[i], NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // CONFIG_MULTITHREAD
|
||||
|
||||
CHECK_MEM_ERROR(cm, row_mt_sync->cur_col,
|
||||
vpx_malloc(sizeof(*row_mt_sync->cur_col) * rows));
|
||||
|
||||
// Set up nsync.
|
||||
row_mt_sync->sync_range = 1;
|
||||
}
|
||||
|
||||
// Deallocate row based multi-threading synchronization related mutex and data
|
||||
void vp9_row_mt_sync_mem_dealloc(VP9RowMTSync *row_mt_sync) {
|
||||
if (row_mt_sync != NULL) {
|
||||
#if CONFIG_MULTITHREAD
|
||||
int i;
|
||||
|
||||
if (row_mt_sync->mutex != NULL) {
|
||||
for (i = 0; i < row_mt_sync->rows; ++i) {
|
||||
pthread_mutex_destroy(&row_mt_sync->mutex[i]);
|
||||
}
|
||||
vpx_free(row_mt_sync->mutex);
|
||||
}
|
||||
if (row_mt_sync->cond != NULL) {
|
||||
for (i = 0; i < row_mt_sync->rows; ++i) {
|
||||
pthread_cond_destroy(&row_mt_sync->cond[i]);
|
||||
}
|
||||
vpx_free(row_mt_sync->cond);
|
||||
}
|
||||
#endif // CONFIG_MULTITHREAD
|
||||
vpx_free(row_mt_sync->cur_col);
|
||||
// clear the structure as the source of this call may be dynamic change
|
||||
// in tiles in which case this call will be followed by an _alloc()
|
||||
// which may fail.
|
||||
vp9_zero(*row_mt_sync);
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_row_mt_sync_read(VP9RowMTSync *const row_mt_sync, int r, int c) {
|
||||
#if CONFIG_MULTITHREAD
|
||||
const int nsync = row_mt_sync->sync_range;
|
||||
|
||||
if (r && !(c & (nsync - 1))) {
|
||||
pthread_mutex_t *const mutex = &row_mt_sync->mutex[r - 1];
|
||||
pthread_mutex_lock(mutex);
|
||||
|
||||
while (c > row_mt_sync->cur_col[r - 1] - nsync + 1) {
|
||||
pthread_cond_wait(&row_mt_sync->cond[r - 1], mutex);
|
||||
}
|
||||
pthread_mutex_unlock(mutex);
|
||||
}
|
||||
#else
|
||||
(void)row_mt_sync;
|
||||
(void)r;
|
||||
(void)c;
|
||||
#endif // CONFIG_MULTITHREAD
|
||||
}
|
||||
|
||||
void vp9_row_mt_sync_read_dummy(VP9RowMTSync *const row_mt_sync, int r, int c) {
|
||||
(void)row_mt_sync;
|
||||
(void)r;
|
||||
(void)c;
|
||||
return;
|
||||
}
|
||||
|
||||
void vp9_row_mt_sync_write(VP9RowMTSync *const row_mt_sync, int r, int c,
|
||||
const int cols) {
|
||||
#if CONFIG_MULTITHREAD
|
||||
const int nsync = row_mt_sync->sync_range;
|
||||
int cur;
|
||||
// Only signal when there are enough encoded blocks for next row to run.
|
||||
int sig = 1;
|
||||
|
||||
if (c < cols - 1) {
|
||||
cur = c;
|
||||
if (c % nsync != nsync - 1) sig = 0;
|
||||
} else {
|
||||
cur = cols + nsync;
|
||||
}
|
||||
|
||||
if (sig) {
|
||||
pthread_mutex_lock(&row_mt_sync->mutex[r]);
|
||||
|
||||
row_mt_sync->cur_col[r] = cur;
|
||||
|
||||
pthread_cond_signal(&row_mt_sync->cond[r]);
|
||||
pthread_mutex_unlock(&row_mt_sync->mutex[r]);
|
||||
}
|
||||
#else
|
||||
(void)row_mt_sync;
|
||||
(void)r;
|
||||
(void)c;
|
||||
(void)cols;
|
||||
#endif // CONFIG_MULTITHREAD
|
||||
}
|
||||
|
||||
void vp9_row_mt_sync_write_dummy(VP9RowMTSync *const row_mt_sync, int r, int c,
|
||||
const int cols) {
|
||||
(void)row_mt_sync;
|
||||
(void)r;
|
||||
(void)c;
|
||||
(void)cols;
|
||||
return;
|
||||
}
|
||||
|
||||
#if !CONFIG_REALTIME_ONLY
|
||||
static int first_pass_worker_hook(void *arg1, void *arg2) {
|
||||
EncWorkerData *const thread_data = (EncWorkerData *)arg1;
|
||||
MultiThreadHandle *multi_thread_ctxt = (MultiThreadHandle *)arg2;
|
||||
VP9_COMP *const cpi = thread_data->cpi;
|
||||
const VP9_COMMON *const cm = &cpi->common;
|
||||
const int tile_cols = 1 << cm->log2_tile_cols;
|
||||
int tile_row, tile_col;
|
||||
TileDataEnc *this_tile;
|
||||
int end_of_frame;
|
||||
int thread_id = thread_data->thread_id;
|
||||
int cur_tile_id = multi_thread_ctxt->thread_id_to_tile_id[thread_id];
|
||||
JobNode *proc_job = NULL;
|
||||
FIRSTPASS_DATA fp_acc_data;
|
||||
MV zero_mv = { 0, 0 };
|
||||
MV best_ref_mv;
|
||||
int mb_row;
|
||||
|
||||
end_of_frame = 0;
|
||||
while (0 == end_of_frame) {
|
||||
// Get the next job in the queue
|
||||
proc_job =
|
||||
(JobNode *)vp9_enc_grp_get_next_job(multi_thread_ctxt, cur_tile_id);
|
||||
if (NULL == proc_job) {
|
||||
// Query for the status of other tiles
|
||||
end_of_frame = vp9_get_tiles_proc_status(
|
||||
multi_thread_ctxt, thread_data->tile_completion_status, &cur_tile_id,
|
||||
tile_cols);
|
||||
} else {
|
||||
tile_col = proc_job->tile_col_id;
|
||||
tile_row = proc_job->tile_row_id;
|
||||
|
||||
this_tile = &cpi->tile_data[tile_row * tile_cols + tile_col];
|
||||
mb_row = proc_job->vert_unit_row_num;
|
||||
|
||||
best_ref_mv = zero_mv;
|
||||
vp9_zero(fp_acc_data);
|
||||
fp_acc_data.image_data_start_row = INVALID_ROW;
|
||||
vp9_first_pass_encode_tile_mb_row(cpi, thread_data->td, &fp_acc_data,
|
||||
this_tile, &best_ref_mv, mb_row);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vp9_encode_fp_row_mt(VP9_COMP *cpi) {
|
||||
VP9_COMMON *const cm = &cpi->common;
|
||||
const int tile_cols = 1 << cm->log2_tile_cols;
|
||||
const int tile_rows = 1 << cm->log2_tile_rows;
|
||||
MultiThreadHandle *multi_thread_ctxt = &cpi->multi_thread_ctxt;
|
||||
TileDataEnc *first_tile_col;
|
||||
int num_workers = VPXMAX(cpi->oxcf.max_threads, 1);
|
||||
int i;
|
||||
|
||||
if (multi_thread_ctxt->allocated_tile_cols < tile_cols ||
|
||||
multi_thread_ctxt->allocated_tile_rows < tile_rows ||
|
||||
multi_thread_ctxt->allocated_vert_unit_rows < cm->mb_rows) {
|
||||
vp9_row_mt_mem_dealloc(cpi);
|
||||
vp9_init_tile_data(cpi);
|
||||
vp9_row_mt_mem_alloc(cpi);
|
||||
} else {
|
||||
vp9_init_tile_data(cpi);
|
||||
}
|
||||
|
||||
create_enc_workers(cpi, num_workers);
|
||||
|
||||
vp9_assign_tile_to_thread(multi_thread_ctxt, tile_cols, cpi->num_workers);
|
||||
|
||||
vp9_prepare_job_queue(cpi, FIRST_PASS_JOB);
|
||||
|
||||
vp9_multi_thread_tile_init(cpi);
|
||||
|
||||
for (i = 0; i < num_workers; i++) {
|
||||
EncWorkerData *thread_data;
|
||||
thread_data = &cpi->tile_thr_data[i];
|
||||
|
||||
// Before encoding a frame, copy the thread data from cpi.
|
||||
if (thread_data->td != &cpi->td) {
|
||||
thread_data->td->mb = cpi->td.mb;
|
||||
}
|
||||
}
|
||||
|
||||
launch_enc_workers(cpi, first_pass_worker_hook, multi_thread_ctxt,
|
||||
num_workers);
|
||||
|
||||
first_tile_col = &cpi->tile_data[0];
|
||||
for (i = 1; i < tile_cols; i++) {
|
||||
TileDataEnc *this_tile = &cpi->tile_data[i];
|
||||
accumulate_fp_tile_stat(first_tile_col, this_tile);
|
||||
}
|
||||
}
|
||||
|
||||
static int temporal_filter_worker_hook(void *arg1, void *arg2) {
|
||||
EncWorkerData *const thread_data = (EncWorkerData *)arg1;
|
||||
MultiThreadHandle *multi_thread_ctxt = (MultiThreadHandle *)arg2;
|
||||
VP9_COMP *const cpi = thread_data->cpi;
|
||||
const VP9_COMMON *const cm = &cpi->common;
|
||||
const int tile_cols = 1 << cm->log2_tile_cols;
|
||||
int tile_row, tile_col;
|
||||
int mb_col_start, mb_col_end;
|
||||
TileDataEnc *this_tile;
|
||||
int end_of_frame;
|
||||
int thread_id = thread_data->thread_id;
|
||||
int cur_tile_id = multi_thread_ctxt->thread_id_to_tile_id[thread_id];
|
||||
JobNode *proc_job = NULL;
|
||||
int mb_row;
|
||||
|
||||
end_of_frame = 0;
|
||||
while (0 == end_of_frame) {
|
||||
// Get the next job in the queue
|
||||
proc_job =
|
||||
(JobNode *)vp9_enc_grp_get_next_job(multi_thread_ctxt, cur_tile_id);
|
||||
if (NULL == proc_job) {
|
||||
// Query for the status of other tiles
|
||||
end_of_frame = vp9_get_tiles_proc_status(
|
||||
multi_thread_ctxt, thread_data->tile_completion_status, &cur_tile_id,
|
||||
tile_cols);
|
||||
} else {
|
||||
tile_col = proc_job->tile_col_id;
|
||||
tile_row = proc_job->tile_row_id;
|
||||
this_tile = &cpi->tile_data[tile_row * tile_cols + tile_col];
|
||||
mb_col_start = (this_tile->tile_info.mi_col_start) >> TF_SHIFT;
|
||||
mb_col_end = (this_tile->tile_info.mi_col_end + TF_ROUND) >> TF_SHIFT;
|
||||
mb_row = proc_job->vert_unit_row_num;
|
||||
|
||||
vp9_temporal_filter_iterate_row_c(cpi, thread_data->td, mb_row,
|
||||
mb_col_start, mb_col_end);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vp9_temporal_filter_row_mt(VP9_COMP *cpi) {
|
||||
VP9_COMMON *const cm = &cpi->common;
|
||||
const int tile_cols = 1 << cm->log2_tile_cols;
|
||||
const int tile_rows = 1 << cm->log2_tile_rows;
|
||||
MultiThreadHandle *multi_thread_ctxt = &cpi->multi_thread_ctxt;
|
||||
int num_workers = cpi->num_workers ? cpi->num_workers : 1;
|
||||
int i;
|
||||
|
||||
if (multi_thread_ctxt->allocated_tile_cols < tile_cols ||
|
||||
multi_thread_ctxt->allocated_tile_rows < tile_rows ||
|
||||
multi_thread_ctxt->allocated_vert_unit_rows < cm->mb_rows) {
|
||||
vp9_row_mt_mem_dealloc(cpi);
|
||||
vp9_init_tile_data(cpi);
|
||||
vp9_row_mt_mem_alloc(cpi);
|
||||
} else {
|
||||
vp9_init_tile_data(cpi);
|
||||
}
|
||||
|
||||
create_enc_workers(cpi, num_workers);
|
||||
|
||||
vp9_assign_tile_to_thread(multi_thread_ctxt, tile_cols, cpi->num_workers);
|
||||
|
||||
vp9_prepare_job_queue(cpi, ARNR_JOB);
|
||||
|
||||
for (i = 0; i < num_workers; i++) {
|
||||
EncWorkerData *thread_data;
|
||||
thread_data = &cpi->tile_thr_data[i];
|
||||
|
||||
// Before encoding a frame, copy the thread data from cpi.
|
||||
if (thread_data->td != &cpi->td) {
|
||||
thread_data->td->mb = cpi->td.mb;
|
||||
}
|
||||
}
|
||||
|
||||
launch_enc_workers(cpi, temporal_filter_worker_hook, multi_thread_ctxt,
|
||||
num_workers);
|
||||
}
|
||||
#endif // !CONFIG_REALTIME_ONLY
|
||||
|
||||
static int enc_row_mt_worker_hook(void *arg1, void *arg2) {
|
||||
EncWorkerData *const thread_data = (EncWorkerData *)arg1;
|
||||
MultiThreadHandle *multi_thread_ctxt = (MultiThreadHandle *)arg2;
|
||||
VP9_COMP *const cpi = thread_data->cpi;
|
||||
const VP9_COMMON *const cm = &cpi->common;
|
||||
const int tile_cols = 1 << cm->log2_tile_cols;
|
||||
int tile_row, tile_col;
|
||||
int end_of_frame;
|
||||
int thread_id = thread_data->thread_id;
|
||||
int cur_tile_id = multi_thread_ctxt->thread_id_to_tile_id[thread_id];
|
||||
JobNode *proc_job = NULL;
|
||||
int mi_row;
|
||||
|
||||
end_of_frame = 0;
|
||||
while (0 == end_of_frame) {
|
||||
// Get the next job in the queue
|
||||
proc_job =
|
||||
(JobNode *)vp9_enc_grp_get_next_job(multi_thread_ctxt, cur_tile_id);
|
||||
if (NULL == proc_job) {
|
||||
// Query for the status of other tiles
|
||||
end_of_frame = vp9_get_tiles_proc_status(
|
||||
multi_thread_ctxt, thread_data->tile_completion_status, &cur_tile_id,
|
||||
tile_cols);
|
||||
} else {
|
||||
tile_col = proc_job->tile_col_id;
|
||||
tile_row = proc_job->tile_row_id;
|
||||
mi_row = proc_job->vert_unit_row_num * MI_BLOCK_SIZE;
|
||||
|
||||
vp9_encode_sb_row(cpi, thread_data->td, tile_row, tile_col, mi_row);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vp9_encode_tiles_row_mt(VP9_COMP *cpi) {
|
||||
VP9_COMMON *const cm = &cpi->common;
|
||||
const int tile_cols = 1 << cm->log2_tile_cols;
|
||||
const int tile_rows = 1 << cm->log2_tile_rows;
|
||||
MultiThreadHandle *multi_thread_ctxt = &cpi->multi_thread_ctxt;
|
||||
int num_workers = VPXMAX(cpi->oxcf.max_threads, 1);
|
||||
int i;
|
||||
|
||||
if (multi_thread_ctxt->allocated_tile_cols < tile_cols ||
|
||||
multi_thread_ctxt->allocated_tile_rows < tile_rows ||
|
||||
multi_thread_ctxt->allocated_vert_unit_rows < cm->mb_rows) {
|
||||
vp9_row_mt_mem_dealloc(cpi);
|
||||
vp9_init_tile_data(cpi);
|
||||
vp9_row_mt_mem_alloc(cpi);
|
||||
} else {
|
||||
vp9_init_tile_data(cpi);
|
||||
}
|
||||
|
||||
create_enc_workers(cpi, num_workers);
|
||||
|
||||
vp9_assign_tile_to_thread(multi_thread_ctxt, tile_cols, cpi->num_workers);
|
||||
|
||||
vp9_prepare_job_queue(cpi, ENCODE_JOB);
|
||||
|
||||
vp9_multi_thread_tile_init(cpi);
|
||||
|
||||
for (i = 0; i < num_workers; i++) {
|
||||
EncWorkerData *thread_data;
|
||||
thread_data = &cpi->tile_thr_data[i];
|
||||
// Before encoding a frame, copy the thread data from cpi.
|
||||
if (thread_data->td != &cpi->td) {
|
||||
thread_data->td->mb = cpi->td.mb;
|
||||
thread_data->td->rd_counts = cpi->td.rd_counts;
|
||||
}
|
||||
if (thread_data->td->counts != &cpi->common.counts) {
|
||||
memcpy(thread_data->td->counts, &cpi->common.counts,
|
||||
sizeof(cpi->common.counts));
|
||||
}
|
||||
|
||||
// Handle use_nonrd_pick_mode case.
|
||||
if (cpi->sf.use_nonrd_pick_mode) {
|
||||
MACROBLOCK *const x = &thread_data->td->mb;
|
||||
MACROBLOCKD *const xd = &x->e_mbd;
|
||||
struct macroblock_plane *const p = x->plane;
|
||||
struct macroblockd_plane *const pd = xd->plane;
|
||||
PICK_MODE_CONTEXT *ctx = &thread_data->td->pc_root->none;
|
||||
int j;
|
||||
|
||||
for (j = 0; j < MAX_MB_PLANE; ++j) {
|
||||
p[j].coeff = ctx->coeff_pbuf[j][0];
|
||||
p[j].qcoeff = ctx->qcoeff_pbuf[j][0];
|
||||
pd[j].dqcoeff = ctx->dqcoeff_pbuf[j][0];
|
||||
p[j].eobs = ctx->eobs_pbuf[j][0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
launch_enc_workers(cpi, enc_row_mt_worker_hook, multi_thread_ctxt,
|
||||
num_workers);
|
||||
|
||||
for (i = 0; i < num_workers; i++) {
|
||||
VPxWorker *const worker = &cpi->workers[i];
|
||||
EncWorkerData *const thread_data = (EncWorkerData *)worker->data1;
|
||||
|
||||
// Accumulate counters.
|
||||
if (i < cpi->num_workers - 1) {
|
||||
vp9_accumulate_frame_counts(&cm->counts, thread_data->td->counts, 0);
|
||||
accumulate_rd_opt(&cpi->td, thread_data->td);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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_ETHREAD_H_
|
||||
#define VPX_VP9_ENCODER_VP9_ETHREAD_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define MAX_NUM_TILE_COLS (1 << 6)
|
||||
#define MAX_NUM_TILE_ROWS 4
|
||||
#define MAX_NUM_THREADS 80
|
||||
|
||||
struct VP9_COMP;
|
||||
struct ThreadData;
|
||||
|
||||
typedef struct EncWorkerData {
|
||||
struct VP9_COMP *cpi;
|
||||
struct ThreadData *td;
|
||||
int start;
|
||||
int thread_id;
|
||||
int tile_completion_status[MAX_NUM_TILE_COLS];
|
||||
} EncWorkerData;
|
||||
|
||||
// Encoder row synchronization
|
||||
typedef struct VP9RowMTSyncData {
|
||||
#if CONFIG_MULTITHREAD
|
||||
pthread_mutex_t *mutex;
|
||||
pthread_cond_t *cond;
|
||||
#endif
|
||||
// Allocate memory to store the sb/mb block index in each row.
|
||||
int *cur_col;
|
||||
int sync_range;
|
||||
int rows;
|
||||
} VP9RowMTSync;
|
||||
|
||||
void vp9_encode_tiles_mt(struct VP9_COMP *cpi);
|
||||
|
||||
void vp9_encode_tiles_row_mt(struct VP9_COMP *cpi);
|
||||
|
||||
void vp9_encode_fp_row_mt(struct VP9_COMP *cpi);
|
||||
|
||||
void vp9_row_mt_sync_read(VP9RowMTSync *const row_mt_sync, int r, int c);
|
||||
void vp9_row_mt_sync_write(VP9RowMTSync *const row_mt_sync, int r, int c,
|
||||
const int cols);
|
||||
|
||||
void vp9_row_mt_sync_read_dummy(VP9RowMTSync *const row_mt_sync, int r, int c);
|
||||
void vp9_row_mt_sync_write_dummy(VP9RowMTSync *const row_mt_sync, int r, int c,
|
||||
const int cols);
|
||||
|
||||
// Allocate memory for row based multi-threading synchronization.
|
||||
void vp9_row_mt_sync_mem_alloc(VP9RowMTSync *row_mt_sync, struct VP9Common *cm,
|
||||
int rows);
|
||||
|
||||
// Deallocate row based multi-threading synchronization related mutex and data.
|
||||
void vp9_row_mt_sync_mem_dealloc(VP9RowMTSync *row_mt_sync);
|
||||
|
||||
void vp9_temporal_filter_row_mt(struct VP9_COMP *cpi);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_ENCODER_VP9_ETHREAD_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 "vpx_dsp/vpx_dsp_common.h"
|
||||
#include "vpx_mem/vpx_mem.h"
|
||||
#include "vpx_ports/mem.h"
|
||||
|
||||
#include "vp9/common/vp9_common.h"
|
||||
#include "vp9/encoder/vp9_extend.h"
|
||||
|
||||
static void copy_and_extend_plane(const uint8_t *src, int src_pitch,
|
||||
uint8_t *dst, int dst_pitch, int w, int h,
|
||||
int extend_top, int extend_left,
|
||||
int extend_bottom, int extend_right) {
|
||||
int i, linesize;
|
||||
|
||||
// copy the left and right most columns out
|
||||
const uint8_t *src_ptr1 = src;
|
||||
const uint8_t *src_ptr2 = src + w - 1;
|
||||
uint8_t *dst_ptr1 = dst - extend_left;
|
||||
uint8_t *dst_ptr2 = dst + w;
|
||||
|
||||
for (i = 0; i < h; i++) {
|
||||
memset(dst_ptr1, src_ptr1[0], extend_left);
|
||||
memcpy(dst_ptr1 + extend_left, src_ptr1, w);
|
||||
memset(dst_ptr2, src_ptr2[0], extend_right);
|
||||
src_ptr1 += src_pitch;
|
||||
src_ptr2 += src_pitch;
|
||||
dst_ptr1 += dst_pitch;
|
||||
dst_ptr2 += dst_pitch;
|
||||
}
|
||||
|
||||
// Now copy the top and bottom lines into each line of the respective
|
||||
// borders
|
||||
src_ptr1 = dst - extend_left;
|
||||
src_ptr2 = dst + dst_pitch * (h - 1) - extend_left;
|
||||
dst_ptr1 = dst + dst_pitch * (-extend_top) - extend_left;
|
||||
dst_ptr2 = dst + dst_pitch * (h)-extend_left;
|
||||
linesize = extend_left + extend_right + w;
|
||||
|
||||
for (i = 0; i < extend_top; i++) {
|
||||
memcpy(dst_ptr1, src_ptr1, linesize);
|
||||
dst_ptr1 += dst_pitch;
|
||||
}
|
||||
|
||||
for (i = 0; i < extend_bottom; i++) {
|
||||
memcpy(dst_ptr2, src_ptr2, linesize);
|
||||
dst_ptr2 += dst_pitch;
|
||||
}
|
||||
}
|
||||
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
static void highbd_copy_and_extend_plane(const uint8_t *src8, int src_pitch,
|
||||
uint8_t *dst8, int dst_pitch, int w,
|
||||
int h, int extend_top, int extend_left,
|
||||
int extend_bottom, int extend_right) {
|
||||
int i, linesize;
|
||||
uint16_t *src = CONVERT_TO_SHORTPTR(src8);
|
||||
uint16_t *dst = CONVERT_TO_SHORTPTR(dst8);
|
||||
|
||||
// copy the left and right most columns out
|
||||
const uint16_t *src_ptr1 = src;
|
||||
const uint16_t *src_ptr2 = src + w - 1;
|
||||
uint16_t *dst_ptr1 = dst - extend_left;
|
||||
uint16_t *dst_ptr2 = dst + w;
|
||||
|
||||
for (i = 0; i < h; i++) {
|
||||
vpx_memset16(dst_ptr1, src_ptr1[0], extend_left);
|
||||
memcpy(dst_ptr1 + extend_left, src_ptr1, w * sizeof(src_ptr1[0]));
|
||||
vpx_memset16(dst_ptr2, src_ptr2[0], extend_right);
|
||||
src_ptr1 += src_pitch;
|
||||
src_ptr2 += src_pitch;
|
||||
dst_ptr1 += dst_pitch;
|
||||
dst_ptr2 += dst_pitch;
|
||||
}
|
||||
|
||||
// Now copy the top and bottom lines into each line of the respective
|
||||
// borders
|
||||
src_ptr1 = dst - extend_left;
|
||||
src_ptr2 = dst + dst_pitch * (h - 1) - extend_left;
|
||||
dst_ptr1 = dst + dst_pitch * (-extend_top) - extend_left;
|
||||
dst_ptr2 = dst + dst_pitch * (h)-extend_left;
|
||||
linesize = extend_left + extend_right + w;
|
||||
|
||||
for (i = 0; i < extend_top; i++) {
|
||||
memcpy(dst_ptr1, src_ptr1, linesize * sizeof(src_ptr1[0]));
|
||||
dst_ptr1 += dst_pitch;
|
||||
}
|
||||
|
||||
for (i = 0; i < extend_bottom; i++) {
|
||||
memcpy(dst_ptr2, src_ptr2, linesize * sizeof(src_ptr2[0]));
|
||||
dst_ptr2 += dst_pitch;
|
||||
}
|
||||
}
|
||||
#endif // CONFIG_VP9_HIGHBITDEPTH
|
||||
|
||||
void vp9_copy_and_extend_frame(const YV12_BUFFER_CONFIG *src,
|
||||
YV12_BUFFER_CONFIG *dst) {
|
||||
// Extend src frame in buffer
|
||||
// Altref filtering assumes 16 pixel extension
|
||||
const int et_y = 16;
|
||||
const int el_y = 16;
|
||||
// Motion estimation may use src block variance with the block size up
|
||||
// to 64x64, so the right and bottom need to be extended to 64 multiple
|
||||
// or up to 16, whichever is greater.
|
||||
const int er_y =
|
||||
VPXMAX(src->y_width + 16, ALIGN_POWER_OF_TWO(src->y_width, 6)) -
|
||||
src->y_crop_width;
|
||||
const int eb_y =
|
||||
VPXMAX(src->y_height + 16, ALIGN_POWER_OF_TWO(src->y_height, 6)) -
|
||||
src->y_crop_height;
|
||||
const int uv_width_subsampling = (src->uv_width != src->y_width);
|
||||
const int uv_height_subsampling = (src->uv_height != src->y_height);
|
||||
const int et_uv = et_y >> uv_height_subsampling;
|
||||
const int el_uv = el_y >> uv_width_subsampling;
|
||||
const int eb_uv = eb_y >> uv_height_subsampling;
|
||||
const int er_uv = er_y >> uv_width_subsampling;
|
||||
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
if (src->flags & YV12_FLAG_HIGHBITDEPTH) {
|
||||
highbd_copy_and_extend_plane(src->y_buffer, src->y_stride, dst->y_buffer,
|
||||
dst->y_stride, src->y_crop_width,
|
||||
src->y_crop_height, et_y, el_y, eb_y, er_y);
|
||||
|
||||
highbd_copy_and_extend_plane(
|
||||
src->u_buffer, src->uv_stride, dst->u_buffer, dst->uv_stride,
|
||||
src->uv_crop_width, src->uv_crop_height, et_uv, el_uv, eb_uv, er_uv);
|
||||
|
||||
highbd_copy_and_extend_plane(
|
||||
src->v_buffer, src->uv_stride, dst->v_buffer, dst->uv_stride,
|
||||
src->uv_crop_width, src->uv_crop_height, et_uv, el_uv, eb_uv, er_uv);
|
||||
return;
|
||||
}
|
||||
#endif // CONFIG_VP9_HIGHBITDEPTH
|
||||
|
||||
copy_and_extend_plane(src->y_buffer, src->y_stride, dst->y_buffer,
|
||||
dst->y_stride, src->y_crop_width, src->y_crop_height,
|
||||
et_y, el_y, eb_y, er_y);
|
||||
|
||||
copy_and_extend_plane(src->u_buffer, src->uv_stride, dst->u_buffer,
|
||||
dst->uv_stride, src->uv_crop_width, src->uv_crop_height,
|
||||
et_uv, el_uv, eb_uv, er_uv);
|
||||
|
||||
copy_and_extend_plane(src->v_buffer, src->uv_stride, dst->v_buffer,
|
||||
dst->uv_stride, src->uv_crop_width, src->uv_crop_height,
|
||||
et_uv, el_uv, eb_uv, er_uv);
|
||||
}
|
||||
|
||||
void vp9_copy_and_extend_frame_with_rect(const YV12_BUFFER_CONFIG *src,
|
||||
YV12_BUFFER_CONFIG *dst, int srcy,
|
||||
int srcx, int srch, int srcw) {
|
||||
// If the side is not touching the bounder then don't extend.
|
||||
const int et_y = srcy ? 0 : dst->border;
|
||||
const int el_y = srcx ? 0 : dst->border;
|
||||
const int eb_y = srcy + srch != src->y_height
|
||||
? 0
|
||||
: dst->border + dst->y_height - src->y_height;
|
||||
const int er_y = srcx + srcw != src->y_width
|
||||
? 0
|
||||
: dst->border + dst->y_width - src->y_width;
|
||||
const int src_y_offset = srcy * src->y_stride + srcx;
|
||||
const int dst_y_offset = srcy * dst->y_stride + srcx;
|
||||
|
||||
const int et_uv = ROUND_POWER_OF_TWO(et_y, 1);
|
||||
const int el_uv = ROUND_POWER_OF_TWO(el_y, 1);
|
||||
const int eb_uv = ROUND_POWER_OF_TWO(eb_y, 1);
|
||||
const int er_uv = ROUND_POWER_OF_TWO(er_y, 1);
|
||||
const int src_uv_offset = ((srcy * src->uv_stride) >> 1) + (srcx >> 1);
|
||||
const int dst_uv_offset = ((srcy * dst->uv_stride) >> 1) + (srcx >> 1);
|
||||
const int srch_uv = ROUND_POWER_OF_TWO(srch, 1);
|
||||
const int srcw_uv = ROUND_POWER_OF_TWO(srcw, 1);
|
||||
|
||||
copy_and_extend_plane(src->y_buffer + src_y_offset, src->y_stride,
|
||||
dst->y_buffer + dst_y_offset, dst->y_stride, srcw, srch,
|
||||
et_y, el_y, eb_y, er_y);
|
||||
|
||||
copy_and_extend_plane(src->u_buffer + src_uv_offset, src->uv_stride,
|
||||
dst->u_buffer + dst_uv_offset, dst->uv_stride, srcw_uv,
|
||||
srch_uv, et_uv, el_uv, eb_uv, er_uv);
|
||||
|
||||
copy_and_extend_plane(src->v_buffer + src_uv_offset, src->uv_stride,
|
||||
dst->v_buffer + dst_uv_offset, dst->uv_stride, srcw_uv,
|
||||
srch_uv, et_uv, el_uv, eb_uv, er_uv);
|
||||
}
|
||||
@@ -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_ENCODER_VP9_EXTEND_H_
|
||||
#define VPX_VP9_ENCODER_VP9_EXTEND_H_
|
||||
|
||||
#include "vpx_scale/yv12config.h"
|
||||
#include "vpx/vpx_integer.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void vp9_copy_and_extend_frame(const YV12_BUFFER_CONFIG *src,
|
||||
YV12_BUFFER_CONFIG *dst);
|
||||
|
||||
void vp9_copy_and_extend_frame_with_rect(const YV12_BUFFER_CONFIG *src,
|
||||
YV12_BUFFER_CONFIG *dst, int srcy,
|
||||
int srcx, int srch, int srcw);
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_ENCODER_VP9_EXTEND_H_
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,300 @@
|
||||
/*
|
||||
* 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_ENCODER_VP9_FIRSTPASS_H_
|
||||
#define VPX_VP9_ENCODER_VP9_FIRSTPASS_H_
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "vp9/common/vp9_onyxc_int.h"
|
||||
#include "vp9/encoder/vp9_lookahead.h"
|
||||
#include "vp9/encoder/vp9_ratectrl.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if CONFIG_FP_MB_STATS
|
||||
|
||||
#define FPMB_DCINTRA_MASK 0x01
|
||||
|
||||
#define FPMB_MOTION_ZERO_MASK 0x02
|
||||
#define FPMB_MOTION_LEFT_MASK 0x04
|
||||
#define FPMB_MOTION_RIGHT_MASK 0x08
|
||||
#define FPMB_MOTION_UP_MASK 0x10
|
||||
#define FPMB_MOTION_DOWN_MASK 0x20
|
||||
|
||||
#define FPMB_ERROR_SMALL_MASK 0x40
|
||||
#define FPMB_ERROR_LARGE_MASK 0x80
|
||||
#define FPMB_ERROR_SMALL_TH 2000
|
||||
#define FPMB_ERROR_LARGE_TH 48000
|
||||
|
||||
typedef struct {
|
||||
uint8_t *mb_stats_start;
|
||||
uint8_t *mb_stats_end;
|
||||
} FIRSTPASS_MB_STATS;
|
||||
#endif
|
||||
|
||||
#define INVALID_ROW (-1)
|
||||
|
||||
#define MAX_ARF_LAYERS 6
|
||||
#define SECTION_NOISE_DEF 250.0
|
||||
|
||||
typedef struct {
|
||||
double frame_mb_intra_factor;
|
||||
double frame_mb_brightness_factor;
|
||||
double frame_mb_neutral_count;
|
||||
} FP_MB_FLOAT_STATS;
|
||||
|
||||
typedef struct {
|
||||
double intra_factor;
|
||||
double brightness_factor;
|
||||
int64_t coded_error;
|
||||
int64_t sr_coded_error;
|
||||
int64_t frame_noise_energy;
|
||||
int64_t intra_error;
|
||||
int intercount;
|
||||
int second_ref_count;
|
||||
double neutral_count;
|
||||
double intra_count_low; // Coded intra but low variance
|
||||
double intra_count_high; // Coded intra high variance
|
||||
int intra_skip_count;
|
||||
int image_data_start_row;
|
||||
int mvcount;
|
||||
int sum_mvr;
|
||||
int sum_mvr_abs;
|
||||
int sum_mvc;
|
||||
int sum_mvc_abs;
|
||||
int64_t sum_mvrs;
|
||||
int64_t sum_mvcs;
|
||||
int sum_in_vectors;
|
||||
int intra_smooth_count;
|
||||
} FIRSTPASS_DATA;
|
||||
|
||||
typedef struct {
|
||||
double frame;
|
||||
double weight;
|
||||
double intra_error;
|
||||
double coded_error;
|
||||
double sr_coded_error;
|
||||
double frame_noise_energy;
|
||||
double pcnt_inter;
|
||||
double pcnt_motion;
|
||||
double pcnt_second_ref;
|
||||
double pcnt_neutral;
|
||||
double pcnt_intra_low; // Coded intra but low variance
|
||||
double pcnt_intra_high; // Coded intra high variance
|
||||
double intra_skip_pct;
|
||||
double intra_smooth_pct; // % of blocks that are smooth
|
||||
double inactive_zone_rows; // Image mask rows top and bottom.
|
||||
double inactive_zone_cols; // Image mask columns at left and right edges.
|
||||
double MVr;
|
||||
double mvr_abs;
|
||||
double MVc;
|
||||
double mvc_abs;
|
||||
double MVrv;
|
||||
double MVcv;
|
||||
double mv_in_out_count;
|
||||
double duration;
|
||||
double count;
|
||||
int64_t spatial_layer_id;
|
||||
} FIRSTPASS_STATS;
|
||||
|
||||
typedef enum {
|
||||
KF_UPDATE = 0,
|
||||
LF_UPDATE = 1,
|
||||
GF_UPDATE = 2,
|
||||
ARF_UPDATE = 3,
|
||||
OVERLAY_UPDATE = 4,
|
||||
MID_OVERLAY_UPDATE = 5,
|
||||
USE_BUF_FRAME = 6, // Use show existing frame, no ref buffer update
|
||||
FRAME_UPDATE_TYPES = 7
|
||||
} FRAME_UPDATE_TYPE;
|
||||
|
||||
#define FC_ANIMATION_THRESH 0.15
|
||||
typedef enum {
|
||||
FC_NORMAL = 0,
|
||||
FC_GRAPHICS_ANIMATION = 1,
|
||||
FRAME_CONTENT_TYPES = 2
|
||||
} FRAME_CONTENT_TYPE;
|
||||
|
||||
typedef struct {
|
||||
unsigned char index;
|
||||
RATE_FACTOR_LEVEL rf_level[MAX_STATIC_GF_GROUP_LENGTH + 2];
|
||||
FRAME_UPDATE_TYPE update_type[MAX_STATIC_GF_GROUP_LENGTH + 2];
|
||||
unsigned char arf_src_offset[MAX_STATIC_GF_GROUP_LENGTH + 2];
|
||||
unsigned char layer_depth[MAX_STATIC_GF_GROUP_LENGTH + 2];
|
||||
unsigned char frame_gop_index[MAX_STATIC_GF_GROUP_LENGTH + 2];
|
||||
int bit_allocation[MAX_STATIC_GF_GROUP_LENGTH + 2];
|
||||
int gfu_boost[MAX_STATIC_GF_GROUP_LENGTH + 2];
|
||||
|
||||
int frame_start;
|
||||
int frame_end;
|
||||
// TODO(jingning): The array size of arf_stack could be reduced.
|
||||
int arf_index_stack[MAX_LAG_BUFFERS * 2];
|
||||
int top_arf_idx;
|
||||
int stack_size;
|
||||
int gf_group_size;
|
||||
int max_layer_depth;
|
||||
int allowed_max_layer_depth;
|
||||
int group_noise_energy;
|
||||
} GF_GROUP;
|
||||
|
||||
typedef struct {
|
||||
const FIRSTPASS_STATS *stats;
|
||||
int num_frames;
|
||||
} FIRST_PASS_INFO;
|
||||
|
||||
static INLINE void fps_init_first_pass_info(FIRST_PASS_INFO *first_pass_info,
|
||||
const FIRSTPASS_STATS *stats,
|
||||
int num_frames) {
|
||||
first_pass_info->stats = stats;
|
||||
first_pass_info->num_frames = num_frames;
|
||||
}
|
||||
|
||||
static INLINE int fps_get_num_frames(const FIRST_PASS_INFO *first_pass_info) {
|
||||
return first_pass_info->num_frames;
|
||||
}
|
||||
|
||||
static INLINE const FIRSTPASS_STATS *fps_get_frame_stats(
|
||||
const FIRST_PASS_INFO *first_pass_info, int show_idx) {
|
||||
if (show_idx < 0 || show_idx >= first_pass_info->num_frames) {
|
||||
return NULL;
|
||||
}
|
||||
return &first_pass_info->stats[show_idx];
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
unsigned int section_intra_rating;
|
||||
unsigned int key_frame_section_intra_rating;
|
||||
FIRSTPASS_STATS total_stats;
|
||||
FIRSTPASS_STATS this_frame_stats;
|
||||
const FIRSTPASS_STATS *stats_in;
|
||||
const FIRSTPASS_STATS *stats_in_start;
|
||||
const FIRSTPASS_STATS *stats_in_end;
|
||||
FIRST_PASS_INFO first_pass_info;
|
||||
FIRSTPASS_STATS total_left_stats;
|
||||
int first_pass_done;
|
||||
int64_t bits_left;
|
||||
double mean_mod_score;
|
||||
double normalized_score_left;
|
||||
double mb_av_energy;
|
||||
double mb_smooth_pct;
|
||||
|
||||
#if CONFIG_FP_MB_STATS
|
||||
uint8_t *frame_mb_stats_buf;
|
||||
uint8_t *this_frame_mb_stats;
|
||||
FIRSTPASS_MB_STATS firstpass_mb_stats;
|
||||
#endif
|
||||
|
||||
FP_MB_FLOAT_STATS *fp_mb_float_stats;
|
||||
|
||||
// An indication of the content type of the current frame
|
||||
FRAME_CONTENT_TYPE fr_content_type;
|
||||
|
||||
// Projected total bits available for a key frame group of frames
|
||||
int64_t kf_group_bits;
|
||||
|
||||
// Error score of frames still to be coded in kf group
|
||||
double kf_group_error_left;
|
||||
|
||||
double bpm_factor;
|
||||
int rolling_arf_group_target_bits;
|
||||
int rolling_arf_group_actual_bits;
|
||||
|
||||
int sr_update_lag;
|
||||
int kf_zeromotion_pct;
|
||||
int last_kfgroup_zeromotion_pct;
|
||||
int active_worst_quality;
|
||||
int baseline_active_worst_quality;
|
||||
int extend_minq;
|
||||
int extend_maxq;
|
||||
int extend_minq_fast;
|
||||
int arnr_strength_adjustment;
|
||||
int last_qindex_of_arf_layer[MAX_ARF_LAYERS];
|
||||
|
||||
GF_GROUP gf_group;
|
||||
} TWO_PASS;
|
||||
|
||||
struct VP9_COMP;
|
||||
struct ThreadData;
|
||||
struct TileDataEnc;
|
||||
|
||||
void vp9_init_first_pass(struct VP9_COMP *cpi);
|
||||
void vp9_first_pass(struct VP9_COMP *cpi, const struct lookahead_entry *source);
|
||||
void vp9_end_first_pass(struct VP9_COMP *cpi);
|
||||
|
||||
void vp9_first_pass_encode_tile_mb_row(struct VP9_COMP *cpi,
|
||||
struct ThreadData *td,
|
||||
FIRSTPASS_DATA *fp_acc_data,
|
||||
struct TileDataEnc *tile_data,
|
||||
MV *best_ref_mv, int mb_row);
|
||||
|
||||
void vp9_init_second_pass(struct VP9_COMP *cpi);
|
||||
void vp9_rc_get_second_pass_params(struct VP9_COMP *cpi);
|
||||
|
||||
// Post encode update of the rate control parameters for 2-pass
|
||||
void vp9_twopass_postencode_update(struct VP9_COMP *cpi);
|
||||
|
||||
void calculate_coded_size(struct VP9_COMP *cpi, int *scaled_frame_width,
|
||||
int *scaled_frame_height);
|
||||
|
||||
struct VP9EncoderConfig;
|
||||
int vp9_get_frames_to_next_key(const struct VP9EncoderConfig *oxcf,
|
||||
const FRAME_INFO *frame_info,
|
||||
const FIRST_PASS_INFO *first_pass_info,
|
||||
int kf_show_idx, int min_gf_interval);
|
||||
#if CONFIG_RATE_CTRL
|
||||
|
||||
/* Call this function to get info about the next group of pictures.
|
||||
* This function should be called after vp9_create_compressor() when encoding
|
||||
* starts or after vp9_get_compressed_data() when the encoding process of
|
||||
* the last group of pictures is just finished.
|
||||
*/
|
||||
void vp9_get_next_group_of_picture(int *first_is_key_frame, int *use_alt_ref,
|
||||
int *coding_frame_count, int *first_show_idx,
|
||||
const struct VP9_COMP *cpi);
|
||||
|
||||
/*!\brief Call this function before coding a new group of pictures to get
|
||||
* information about it.
|
||||
* \param[in] oxcf Encoder config
|
||||
* \param[in] frame_info Frame info
|
||||
* \param[in] first_pass_info First pass stats
|
||||
* \param[in] rc Rate control state
|
||||
* \param[in] show_idx Show index of the first frame in the group
|
||||
* \param[in] multi_layer_arf Is multi-layer alternate reference used
|
||||
* \param[in] allow_alt_ref Is alternate reference allowed
|
||||
* \param[in] first_is_key_frame Is the first frame in the group a key frame
|
||||
* \param[in] last_gop_use_alt_ref Does the last group use alternate reference
|
||||
*
|
||||
* \param[out] use_alt_ref Does this group use alternate reference
|
||||
*
|
||||
* \return Returns coding frame count
|
||||
*/
|
||||
int vp9_get_gop_coding_frame_count(
|
||||
int *use_alt_ref, const struct VP9EncoderConfig *oxcf,
|
||||
const FRAME_INFO *frame_info, const FIRST_PASS_INFO *first_pass_info,
|
||||
const RATE_CONTROL *rc, int show_idx, int multi_layer_arf,
|
||||
int allow_alt_ref, int first_is_key_frame, int last_gop_use_alt_ref);
|
||||
|
||||
int vp9_get_coding_frame_num(const struct VP9EncoderConfig *oxcf,
|
||||
const FRAME_INFO *frame_info,
|
||||
const FIRST_PASS_INFO *first_pass_info,
|
||||
int multi_layer_arf, int allow_alt_ref);
|
||||
#endif
|
||||
|
||||
FIRSTPASS_STATS vp9_get_frame_stats(const TWO_PASS *twopass);
|
||||
FIRSTPASS_STATS vp9_get_total_stats(const TWO_PASS *twopass);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_ENCODER_VP9_FIRSTPASS_H_
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* 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 "./vp9_rtcd.h"
|
||||
#include "./vpx_dsp_rtcd.h"
|
||||
#include "./vpx_scale_rtcd.h"
|
||||
#include "vp9/common/vp9_blockd.h"
|
||||
#include "vpx_dsp/vpx_filter.h"
|
||||
#include "vpx_scale/yv12config.h"
|
||||
|
||||
void vp9_scale_and_extend_frame_c(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 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 };
|
||||
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 };
|
||||
const InterpKernel *const kernel = vp9_filter_kernels[filter_type];
|
||||
int x, y, i;
|
||||
|
||||
#if HAVE_SSSE3 || HAVE_NEON
|
||||
// TODO(linfengz): The 4:3 specialized C code is disabled by default since
|
||||
// it's much slower than the general version which calls vpx_scaled_2d() even
|
||||
// if vpx_scaled_2d() is not optimized. It will only be enabled as a reference
|
||||
// for the platforms which have faster optimization.
|
||||
if (4 * dst->y_crop_width == 3 * src_w &&
|
||||
4 * dst->y_crop_height == 3 * src_h) {
|
||||
// Specialize 4 to 3 scaling.
|
||||
// Example pixel locations.
|
||||
// (O: Original pixel. S: Scaled pixel. X: Overlapped pixel.)
|
||||
// phase_scaler = 0 | phase_scaler = 8
|
||||
// |
|
||||
// X O S O S O X | O O O O O
|
||||
// |
|
||||
// |
|
||||
// | S S S
|
||||
// |
|
||||
// |
|
||||
// O O O O O | O O O O O
|
||||
// |
|
||||
// S S S S |
|
||||
// |
|
||||
// |
|
||||
// | S S S
|
||||
// O O O O O | O O O O O
|
||||
// |
|
||||
// |
|
||||
// |
|
||||
// S S S S |
|
||||
// |
|
||||
// O O O O O | O O O O O
|
||||
// | S S S
|
||||
// |
|
||||
// |
|
||||
// |
|
||||
// |
|
||||
// X O S O S O X | O O O O O
|
||||
|
||||
const int dst_ws[3] = { dst->y_crop_width, dst->uv_crop_width,
|
||||
dst->uv_crop_width };
|
||||
const int dst_hs[3] = { dst->y_crop_height, dst->uv_crop_height,
|
||||
dst->uv_crop_height };
|
||||
for (i = 0; i < MAX_MB_PLANE; ++i) {
|
||||
const int dst_w = dst_ws[i];
|
||||
const int dst_h = dst_hs[i];
|
||||
const int src_stride = src_strides[i];
|
||||
const int dst_stride = dst_strides[i];
|
||||
for (y = 0; y < dst_h; y += 3) {
|
||||
for (x = 0; x < dst_w; x += 3) {
|
||||
const uint8_t *src_ptr = srcs[i] + 4 * y / 3 * src_stride + 4 * x / 3;
|
||||
uint8_t *dst_ptr = dsts[i] + y * dst_stride + x;
|
||||
|
||||
// Must call c function because its optimization doesn't support 3x3.
|
||||
vpx_scaled_2d_c(src_ptr, src_stride, dst_ptr, dst_stride, kernel,
|
||||
phase_scaler, 64 / 3, phase_scaler, 64 / 3, 3, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
const int dst_w = dst->y_crop_width;
|
||||
const int dst_h = dst->y_crop_height;
|
||||
for (i = 0; i < MAX_MB_PLANE; ++i) {
|
||||
const int factor = (i == 0 || i == 3 ? 1 : 2);
|
||||
const int src_stride = src_strides[i];
|
||||
const int dst_stride = dst_strides[i];
|
||||
for (y = 0; y < dst_h; y += 16) {
|
||||
const int y_q4 = y * (16 / factor) * src_h / dst_h + phase_scaler;
|
||||
for (x = 0; x < dst_w; x += 16) {
|
||||
const int x_q4 = x * (16 / factor) * src_w / dst_w + phase_scaler;
|
||||
const uint8_t *src_ptr = srcs[i] +
|
||||
(y / factor) * src_h / dst_h * src_stride +
|
||||
(x / factor) * src_w / dst_w;
|
||||
uint8_t *dst_ptr = dsts[i] + (y / factor) * dst_stride + (x / factor);
|
||||
|
||||
vpx_scaled_2d(src_ptr, src_stride, dst_ptr, dst_stride, kernel,
|
||||
x_q4 & 0xf, 16 * src_w / dst_w, y_q4 & 0xf,
|
||||
16 * src_h / dst_h, 16 / factor, 16 / factor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vpx_extend_frame_borders(dst);
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef VPX_VP9_ENCODER_VP9_JOB_QUEUE_H_
|
||||
#define VPX_VP9_ENCODER_VP9_JOB_QUEUE_H_
|
||||
|
||||
typedef enum {
|
||||
FIRST_PASS_JOB,
|
||||
ENCODE_JOB,
|
||||
ARNR_JOB,
|
||||
NUM_JOB_TYPES,
|
||||
} JOB_TYPE;
|
||||
|
||||
// Encode job parameters
|
||||
typedef struct {
|
||||
int vert_unit_row_num; // Index of the vertical unit row
|
||||
int tile_col_id; // tile col id within a tile
|
||||
int tile_row_id; // tile col id within a tile
|
||||
} JobNode;
|
||||
|
||||
// Job queue element parameters
|
||||
typedef struct {
|
||||
// Pointer to the next link in the job queue
|
||||
void *next;
|
||||
|
||||
// Job information context of the module
|
||||
JobNode job_info;
|
||||
} JobQueue;
|
||||
|
||||
// Job queue handle
|
||||
typedef struct {
|
||||
// Pointer to the next link in the job queue
|
||||
void *next;
|
||||
|
||||
// Counter to store the number of jobs picked up for processing
|
||||
int num_jobs_acquired;
|
||||
} JobQueueHandle;
|
||||
|
||||
#endif // VPX_VP9_ENCODER_VP9_JOB_QUEUE_H_
|
||||
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebM project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "./vpx_config.h"
|
||||
|
||||
#include "vp9/common/vp9_common.h"
|
||||
|
||||
#include "vp9/encoder/vp9_encoder.h"
|
||||
#include "vp9/encoder/vp9_extend.h"
|
||||
#include "vp9/encoder/vp9_lookahead.h"
|
||||
|
||||
/* Return the buffer at the given absolute index and increment the index */
|
||||
static struct lookahead_entry *pop(struct lookahead_ctx *ctx, int *idx) {
|
||||
int index = *idx;
|
||||
struct lookahead_entry *buf = ctx->buf + index;
|
||||
|
||||
assert(index < ctx->max_sz);
|
||||
if (++index >= ctx->max_sz) index -= ctx->max_sz;
|
||||
*idx = index;
|
||||
return buf;
|
||||
}
|
||||
|
||||
void vp9_lookahead_destroy(struct lookahead_ctx *ctx) {
|
||||
if (ctx) {
|
||||
if (ctx->buf) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ctx->max_sz; i++) vpx_free_frame_buffer(&ctx->buf[i].img);
|
||||
free(ctx->buf);
|
||||
}
|
||||
free(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
struct lookahead_ctx *vp9_lookahead_init(unsigned int width,
|
||||
unsigned int height,
|
||||
unsigned int subsampling_x,
|
||||
unsigned int subsampling_y,
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
int use_highbitdepth,
|
||||
#endif
|
||||
unsigned int depth) {
|
||||
struct lookahead_ctx *ctx = NULL;
|
||||
|
||||
// Clamp the lookahead queue depth
|
||||
depth = clamp(depth, 1, MAX_LAG_BUFFERS);
|
||||
|
||||
// Allocate memory to keep previous source frames available.
|
||||
depth += MAX_PRE_FRAMES;
|
||||
|
||||
// Allocate the lookahead structures
|
||||
ctx = calloc(1, sizeof(*ctx));
|
||||
if (ctx) {
|
||||
const int legacy_byte_alignment = 0;
|
||||
unsigned int i;
|
||||
ctx->max_sz = depth;
|
||||
ctx->buf = calloc(depth, sizeof(*ctx->buf));
|
||||
ctx->next_show_idx = 0;
|
||||
if (!ctx->buf) goto bail;
|
||||
for (i = 0; i < depth; i++)
|
||||
if (vpx_alloc_frame_buffer(
|
||||
&ctx->buf[i].img, width, height, subsampling_x, subsampling_y,
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
use_highbitdepth,
|
||||
#endif
|
||||
VP9_ENC_BORDER_IN_PIXELS, legacy_byte_alignment))
|
||||
goto bail;
|
||||
}
|
||||
return ctx;
|
||||
bail:
|
||||
vp9_lookahead_destroy(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define USE_PARTIAL_COPY 0
|
||||
int vp9_lookahead_full(const struct lookahead_ctx *ctx) {
|
||||
return ctx->sz + 1 + MAX_PRE_FRAMES > ctx->max_sz;
|
||||
}
|
||||
|
||||
int vp9_lookahead_next_show_idx(const struct lookahead_ctx *ctx) {
|
||||
return ctx->next_show_idx;
|
||||
}
|
||||
|
||||
int vp9_lookahead_push(struct lookahead_ctx *ctx, YV12_BUFFER_CONFIG *src,
|
||||
int64_t ts_start, int64_t ts_end, int use_highbitdepth,
|
||||
vpx_enc_frame_flags_t flags) {
|
||||
struct lookahead_entry *buf;
|
||||
#if USE_PARTIAL_COPY
|
||||
int row, col, active_end;
|
||||
int mb_rows = (src->y_height + 15) >> 4;
|
||||
int mb_cols = (src->y_width + 15) >> 4;
|
||||
#endif
|
||||
int width = src->y_crop_width;
|
||||
int height = src->y_crop_height;
|
||||
int uv_width = src->uv_crop_width;
|
||||
int uv_height = src->uv_crop_height;
|
||||
int subsampling_x = src->subsampling_x;
|
||||
int subsampling_y = src->subsampling_y;
|
||||
int larger_dimensions, new_dimensions;
|
||||
#if !CONFIG_VP9_HIGHBITDEPTH
|
||||
(void)use_highbitdepth;
|
||||
assert(use_highbitdepth == 0);
|
||||
#endif
|
||||
|
||||
if (vp9_lookahead_full(ctx)) return 1;
|
||||
ctx->sz++;
|
||||
buf = pop(ctx, &ctx->write_idx);
|
||||
|
||||
new_dimensions = width != buf->img.y_crop_width ||
|
||||
height != buf->img.y_crop_height ||
|
||||
uv_width != buf->img.uv_crop_width ||
|
||||
uv_height != buf->img.uv_crop_height;
|
||||
larger_dimensions = width > buf->img.y_width || height > buf->img.y_height ||
|
||||
uv_width > buf->img.uv_width ||
|
||||
uv_height > buf->img.uv_height;
|
||||
assert(!larger_dimensions || new_dimensions);
|
||||
|
||||
#if USE_PARTIAL_COPY
|
||||
// TODO(jkoleszar): This is disabled for now, as
|
||||
// vp9_copy_and_extend_frame_with_rect is not subsampling/alpha aware.
|
||||
|
||||
// Only do this partial copy if the following conditions are all met:
|
||||
// 1. Lookahead queue has has size of 1.
|
||||
// 2. Active map is provided.
|
||||
// 3. This is not a key frame, golden nor altref frame.
|
||||
if (!new_dimensions && ctx->max_sz == 1 && active_map && !flags) {
|
||||
for (row = 0; row < mb_rows; ++row) {
|
||||
col = 0;
|
||||
|
||||
while (1) {
|
||||
// Find the first active macroblock in this row.
|
||||
for (; col < mb_cols; ++col) {
|
||||
if (active_map[col]) break;
|
||||
}
|
||||
|
||||
// No more active macroblock in this row.
|
||||
if (col == mb_cols) break;
|
||||
|
||||
// Find the end of active region in this row.
|
||||
active_end = col;
|
||||
|
||||
for (; active_end < mb_cols; ++active_end) {
|
||||
if (!active_map[active_end]) break;
|
||||
}
|
||||
|
||||
// Only copy this active region.
|
||||
vp9_copy_and_extend_frame_with_rect(src, &buf->img, row << 4, col << 4,
|
||||
16, (active_end - col) << 4);
|
||||
|
||||
// Start again from the end of this active region.
|
||||
col = active_end;
|
||||
}
|
||||
|
||||
active_map += mb_cols;
|
||||
}
|
||||
} else {
|
||||
#endif
|
||||
if (larger_dimensions) {
|
||||
YV12_BUFFER_CONFIG new_img;
|
||||
memset(&new_img, 0, sizeof(new_img));
|
||||
if (vpx_alloc_frame_buffer(&new_img, width, height, subsampling_x,
|
||||
subsampling_y,
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
use_highbitdepth,
|
||||
#endif
|
||||
VP9_ENC_BORDER_IN_PIXELS, 0))
|
||||
return 1;
|
||||
vpx_free_frame_buffer(&buf->img);
|
||||
buf->img = new_img;
|
||||
} else if (new_dimensions) {
|
||||
buf->img.y_crop_width = src->y_crop_width;
|
||||
buf->img.y_crop_height = src->y_crop_height;
|
||||
buf->img.uv_crop_width = src->uv_crop_width;
|
||||
buf->img.uv_crop_height = src->uv_crop_height;
|
||||
buf->img.subsampling_x = src->subsampling_x;
|
||||
buf->img.subsampling_y = src->subsampling_y;
|
||||
}
|
||||
// Partial copy not implemented yet
|
||||
vp9_copy_and_extend_frame(src, &buf->img);
|
||||
#if USE_PARTIAL_COPY
|
||||
}
|
||||
#endif
|
||||
|
||||
buf->ts_start = ts_start;
|
||||
buf->ts_end = ts_end;
|
||||
buf->flags = flags;
|
||||
buf->show_idx = ctx->next_show_idx;
|
||||
++ctx->next_show_idx;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct lookahead_entry *vp9_lookahead_pop(struct lookahead_ctx *ctx,
|
||||
int drain) {
|
||||
struct lookahead_entry *buf = NULL;
|
||||
|
||||
if (ctx && ctx->sz && (drain || ctx->sz == ctx->max_sz - MAX_PRE_FRAMES)) {
|
||||
buf = pop(ctx, &ctx->read_idx);
|
||||
ctx->sz--;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
struct lookahead_entry *vp9_lookahead_peek(struct lookahead_ctx *ctx,
|
||||
int index) {
|
||||
struct lookahead_entry *buf = NULL;
|
||||
|
||||
if (index >= 0) {
|
||||
// Forward peek
|
||||
if (index < ctx->sz) {
|
||||
index += ctx->read_idx;
|
||||
if (index >= ctx->max_sz) index -= ctx->max_sz;
|
||||
buf = ctx->buf + index;
|
||||
}
|
||||
} else if (index < 0) {
|
||||
// Backward peek
|
||||
if (-index <= MAX_PRE_FRAMES) {
|
||||
index += ctx->read_idx;
|
||||
if (index < 0) index += ctx->max_sz;
|
||||
buf = ctx->buf + index;
|
||||
}
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
unsigned int vp9_lookahead_depth(struct lookahead_ctx *ctx) { return ctx->sz; }
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* 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_ENCODER_VP9_LOOKAHEAD_H_
|
||||
#define VPX_VP9_ENCODER_VP9_LOOKAHEAD_H_
|
||||
|
||||
#include "vpx_scale/yv12config.h"
|
||||
#include "vpx/vpx_encoder.h"
|
||||
#include "vpx/vpx_integer.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define MAX_LAG_BUFFERS 25
|
||||
|
||||
struct lookahead_entry {
|
||||
YV12_BUFFER_CONFIG img;
|
||||
int64_t ts_start;
|
||||
int64_t ts_end;
|
||||
int show_idx; /*The show_idx of this frame*/
|
||||
vpx_enc_frame_flags_t flags;
|
||||
};
|
||||
|
||||
// The max of past frames we want to keep in the queue.
|
||||
#define MAX_PRE_FRAMES 1
|
||||
|
||||
struct lookahead_ctx {
|
||||
int max_sz; /* Absolute size of the queue */
|
||||
int sz; /* Number of buffers currently in the queue */
|
||||
int read_idx; /* Read index */
|
||||
int write_idx; /* Write index */
|
||||
int next_show_idx; /* The show_idx that will be assigned to the next frame
|
||||
being pushed in the queue*/
|
||||
struct lookahead_entry *buf; /* Buffer list */
|
||||
};
|
||||
|
||||
/**\brief Initializes the lookahead stage
|
||||
*
|
||||
* The lookahead stage is a queue of frame buffers on which some analysis
|
||||
* may be done when buffers are enqueued.
|
||||
*/
|
||||
struct lookahead_ctx *vp9_lookahead_init(unsigned int width,
|
||||
unsigned int height,
|
||||
unsigned int subsampling_x,
|
||||
unsigned int subsampling_y,
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
int use_highbitdepth,
|
||||
#endif
|
||||
unsigned int depth);
|
||||
|
||||
/**\brief Destroys the lookahead stage
|
||||
*/
|
||||
void vp9_lookahead_destroy(struct lookahead_ctx *ctx);
|
||||
|
||||
/**\brief Check if lookahead is full
|
||||
*
|
||||
* \param[in] ctx Pointer to the lookahead context
|
||||
*
|
||||
* Return 1 if lookahead is full, otherwise return 0.
|
||||
*/
|
||||
int vp9_lookahead_full(const struct lookahead_ctx *ctx);
|
||||
|
||||
/**\brief Return the next_show_idx
|
||||
*
|
||||
* \param[in] ctx Pointer to the lookahead context
|
||||
*
|
||||
* Return the show_idx that will be assigned to the next
|
||||
* frame pushed by vp9_lookahead_push()
|
||||
*/
|
||||
int vp9_lookahead_next_show_idx(const struct lookahead_ctx *ctx);
|
||||
|
||||
/**\brief Enqueue a source buffer
|
||||
*
|
||||
* This function will copy the source image into a new framebuffer with
|
||||
* the expected stride/border.
|
||||
*
|
||||
* If active_map is non-NULL and there is only one frame in the queue, then copy
|
||||
* only active macroblocks.
|
||||
*
|
||||
* \param[in] ctx Pointer to the lookahead context
|
||||
* \param[in] src Pointer to the image to enqueue
|
||||
* \param[in] ts_start Timestamp for the start of this frame
|
||||
* \param[in] ts_end Timestamp for the end of this frame
|
||||
* \param[in] flags Flags set on this frame
|
||||
* \param[in] active_map Map that specifies which macroblock is active
|
||||
*/
|
||||
int vp9_lookahead_push(struct lookahead_ctx *ctx, YV12_BUFFER_CONFIG *src,
|
||||
int64_t ts_start, int64_t ts_end, int use_highbitdepth,
|
||||
vpx_enc_frame_flags_t flags);
|
||||
|
||||
/**\brief Get the next source buffer to encode
|
||||
*
|
||||
*
|
||||
* \param[in] ctx Pointer to the lookahead context
|
||||
* \param[in] drain Flag indicating the buffer should be drained
|
||||
* (return a buffer regardless of the current queue depth)
|
||||
*
|
||||
* \retval NULL, if drain set and queue is empty
|
||||
* \retval NULL, if drain not set and queue not of the configured depth
|
||||
*/
|
||||
struct lookahead_entry *vp9_lookahead_pop(struct lookahead_ctx *ctx, int drain);
|
||||
|
||||
/**\brief Get a future source buffer to encode
|
||||
*
|
||||
* \param[in] ctx Pointer to the lookahead context
|
||||
* \param[in] index Index of the frame to be returned, 0 == next frame
|
||||
*
|
||||
* \retval NULL, if no buffer exists at the specified index
|
||||
*/
|
||||
struct lookahead_entry *vp9_lookahead_peek(struct lookahead_ctx *ctx,
|
||||
int index);
|
||||
|
||||
/**\brief Get the number of frames currently in the lookahead queue
|
||||
*
|
||||
* \param[in] ctx Pointer to the lookahead context
|
||||
*/
|
||||
unsigned int vp9_lookahead_depth(struct lookahead_ctx *ctx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_ENCODER_VP9_LOOKAHEAD_H_
|
||||
@@ -0,0 +1,402 @@
|
||||
/*
|
||||
* Copyright (c) 2010 The WebM project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include "./vp9_rtcd.h"
|
||||
#include "./vpx_dsp_rtcd.h"
|
||||
|
||||
#include "vpx_dsp/vpx_dsp_common.h"
|
||||
#include "vpx_mem/vpx_mem.h"
|
||||
#include "vpx_ports/system_state.h"
|
||||
#include "vp9/encoder/vp9_segmentation.h"
|
||||
#include "vp9/encoder/vp9_mcomp.h"
|
||||
#include "vp9/common/vp9_blockd.h"
|
||||
#include "vp9/common/vp9_reconinter.h"
|
||||
#include "vp9/common/vp9_reconintra.h"
|
||||
|
||||
static unsigned int do_16x16_motion_iteration(VP9_COMP *cpi, const MV *ref_mv,
|
||||
MV *dst_mv, int mb_row,
|
||||
int mb_col) {
|
||||
MACROBLOCK *const x = &cpi->td.mb;
|
||||
MACROBLOCKD *const xd = &x->e_mbd;
|
||||
MV_SPEED_FEATURES *const mv_sf = &cpi->sf.mv;
|
||||
const SEARCH_METHODS old_search_method = mv_sf->search_method;
|
||||
const vp9_variance_fn_ptr_t v_fn_ptr = cpi->fn_ptr[BLOCK_16X16];
|
||||
const MvLimits tmp_mv_limits = x->mv_limits;
|
||||
MV ref_full;
|
||||
int cost_list[5];
|
||||
|
||||
// Further step/diamond searches as necessary
|
||||
int step_param = mv_sf->reduce_first_step_size;
|
||||
step_param = VPXMIN(step_param, MAX_MVSEARCH_STEPS - 2);
|
||||
|
||||
vp9_set_mv_search_range(&x->mv_limits, ref_mv);
|
||||
|
||||
ref_full.col = ref_mv->col >> 3;
|
||||
ref_full.row = ref_mv->row >> 3;
|
||||
|
||||
mv_sf->search_method = HEX;
|
||||
vp9_full_pixel_search(cpi, x, BLOCK_16X16, &ref_full, step_param,
|
||||
cpi->sf.mv.search_method, x->errorperbit,
|
||||
cond_cost_list(cpi, cost_list), ref_mv, dst_mv, 0, 0);
|
||||
mv_sf->search_method = old_search_method;
|
||||
|
||||
/* restore UMV window */
|
||||
x->mv_limits = tmp_mv_limits;
|
||||
|
||||
// Try sub-pixel MC
|
||||
// if (bestsme > error_thresh && bestsme < INT_MAX)
|
||||
{
|
||||
uint32_t distortion;
|
||||
uint32_t sse;
|
||||
// TODO(yunqing): may use higher tap interp filter than 2 taps if needed.
|
||||
cpi->find_fractional_mv_step(
|
||||
x, dst_mv, ref_mv, cpi->common.allow_high_precision_mv, x->errorperbit,
|
||||
&v_fn_ptr, 0, mv_sf->subpel_search_level,
|
||||
cond_cost_list(cpi, cost_list), NULL, NULL, &distortion, &sse, NULL, 0,
|
||||
0, USE_2_TAPS);
|
||||
}
|
||||
|
||||
xd->mi[0]->mode = NEWMV;
|
||||
xd->mi[0]->mv[0].as_mv = *dst_mv;
|
||||
|
||||
vp9_build_inter_predictors_sby(xd, mb_row, mb_col, BLOCK_16X16);
|
||||
|
||||
return vpx_sad16x16(x->plane[0].src.buf, x->plane[0].src.stride,
|
||||
xd->plane[0].dst.buf, xd->plane[0].dst.stride);
|
||||
}
|
||||
|
||||
static int do_16x16_motion_search(VP9_COMP *cpi, const MV *ref_mv,
|
||||
int_mv *dst_mv, int mb_row, int mb_col) {
|
||||
MACROBLOCK *const x = &cpi->td.mb;
|
||||
MACROBLOCKD *const xd = &x->e_mbd;
|
||||
unsigned int err, tmp_err;
|
||||
MV tmp_mv;
|
||||
|
||||
// Try zero MV first
|
||||
// FIXME should really use something like near/nearest MV and/or MV prediction
|
||||
err = vpx_sad16x16(x->plane[0].src.buf, x->plane[0].src.stride,
|
||||
xd->plane[0].pre[0].buf, xd->plane[0].pre[0].stride);
|
||||
dst_mv->as_int = 0;
|
||||
|
||||
// Test last reference frame using the previous best mv as the
|
||||
// starting point (best reference) for the search
|
||||
tmp_err = do_16x16_motion_iteration(cpi, ref_mv, &tmp_mv, mb_row, mb_col);
|
||||
if (tmp_err < err) {
|
||||
err = tmp_err;
|
||||
dst_mv->as_mv = tmp_mv;
|
||||
}
|
||||
|
||||
// If the current best reference mv is not centered on 0,0 then do a 0,0
|
||||
// based search as well.
|
||||
if (ref_mv->row != 0 || ref_mv->col != 0) {
|
||||
unsigned int tmp_err;
|
||||
MV zero_ref_mv = { 0, 0 }, tmp_mv;
|
||||
|
||||
tmp_err =
|
||||
do_16x16_motion_iteration(cpi, &zero_ref_mv, &tmp_mv, mb_row, mb_col);
|
||||
if (tmp_err < err) {
|
||||
dst_mv->as_mv = tmp_mv;
|
||||
err = tmp_err;
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int do_16x16_zerozero_search(VP9_COMP *cpi, int_mv *dst_mv) {
|
||||
MACROBLOCK *const x = &cpi->td.mb;
|
||||
MACROBLOCKD *const xd = &x->e_mbd;
|
||||
unsigned int err;
|
||||
|
||||
// Try zero MV first
|
||||
// FIXME should really use something like near/nearest MV and/or MV prediction
|
||||
err = vpx_sad16x16(x->plane[0].src.buf, x->plane[0].src.stride,
|
||||
xd->plane[0].pre[0].buf, xd->plane[0].pre[0].stride);
|
||||
|
||||
dst_mv->as_int = 0;
|
||||
|
||||
return err;
|
||||
}
|
||||
static int find_best_16x16_intra(VP9_COMP *cpi, PREDICTION_MODE *pbest_mode) {
|
||||
MACROBLOCK *const x = &cpi->td.mb;
|
||||
MACROBLOCKD *const xd = &x->e_mbd;
|
||||
PREDICTION_MODE best_mode = -1, mode;
|
||||
unsigned int best_err = INT_MAX;
|
||||
|
||||
// calculate SATD for each intra prediction mode;
|
||||
// we're intentionally not doing 4x4, we just want a rough estimate
|
||||
for (mode = DC_PRED; mode <= TM_PRED; mode++) {
|
||||
unsigned int err;
|
||||
|
||||
xd->mi[0]->mode = mode;
|
||||
vp9_predict_intra_block(xd, 2, TX_16X16, mode, x->plane[0].src.buf,
|
||||
x->plane[0].src.stride, xd->plane[0].dst.buf,
|
||||
xd->plane[0].dst.stride, 0, 0, 0);
|
||||
err = vpx_sad16x16(x->plane[0].src.buf, x->plane[0].src.stride,
|
||||
xd->plane[0].dst.buf, xd->plane[0].dst.stride);
|
||||
|
||||
// find best
|
||||
if (err < best_err) {
|
||||
best_err = err;
|
||||
best_mode = mode;
|
||||
}
|
||||
}
|
||||
|
||||
if (pbest_mode) *pbest_mode = best_mode;
|
||||
|
||||
return best_err;
|
||||
}
|
||||
|
||||
static void update_mbgraph_mb_stats(VP9_COMP *cpi, MBGRAPH_MB_STATS *stats,
|
||||
YV12_BUFFER_CONFIG *buf, int mb_y_offset,
|
||||
YV12_BUFFER_CONFIG *golden_ref,
|
||||
const MV *prev_golden_ref_mv,
|
||||
YV12_BUFFER_CONFIG *alt_ref, int mb_row,
|
||||
int mb_col) {
|
||||
MACROBLOCK *const x = &cpi->td.mb;
|
||||
MACROBLOCKD *const xd = &x->e_mbd;
|
||||
int intra_error;
|
||||
VP9_COMMON *cm = &cpi->common;
|
||||
|
||||
// FIXME in practice we're completely ignoring chroma here
|
||||
x->plane[0].src.buf = buf->y_buffer + mb_y_offset;
|
||||
x->plane[0].src.stride = buf->y_stride;
|
||||
|
||||
xd->plane[0].dst.buf = get_frame_new_buffer(cm)->y_buffer + mb_y_offset;
|
||||
xd->plane[0].dst.stride = get_frame_new_buffer(cm)->y_stride;
|
||||
|
||||
// do intra 16x16 prediction
|
||||
intra_error = find_best_16x16_intra(cpi, &stats->ref[INTRA_FRAME].m.mode);
|
||||
if (intra_error <= 0) intra_error = 1;
|
||||
stats->ref[INTRA_FRAME].err = intra_error;
|
||||
|
||||
// Golden frame MV search, if it exists and is different than last frame
|
||||
if (golden_ref) {
|
||||
int g_motion_error;
|
||||
xd->plane[0].pre[0].buf = golden_ref->y_buffer + mb_y_offset;
|
||||
xd->plane[0].pre[0].stride = golden_ref->y_stride;
|
||||
g_motion_error =
|
||||
do_16x16_motion_search(cpi, prev_golden_ref_mv,
|
||||
&stats->ref[GOLDEN_FRAME].m.mv, mb_row, mb_col);
|
||||
stats->ref[GOLDEN_FRAME].err = g_motion_error;
|
||||
} else {
|
||||
stats->ref[GOLDEN_FRAME].err = INT_MAX;
|
||||
stats->ref[GOLDEN_FRAME].m.mv.as_int = 0;
|
||||
}
|
||||
|
||||
// Do an Alt-ref frame MV search, if it exists and is different than
|
||||
// last/golden frame.
|
||||
if (alt_ref) {
|
||||
int a_motion_error;
|
||||
xd->plane[0].pre[0].buf = alt_ref->y_buffer + mb_y_offset;
|
||||
xd->plane[0].pre[0].stride = alt_ref->y_stride;
|
||||
a_motion_error =
|
||||
do_16x16_zerozero_search(cpi, &stats->ref[ALTREF_FRAME].m.mv);
|
||||
|
||||
stats->ref[ALTREF_FRAME].err = a_motion_error;
|
||||
} else {
|
||||
stats->ref[ALTREF_FRAME].err = INT_MAX;
|
||||
stats->ref[ALTREF_FRAME].m.mv.as_int = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void update_mbgraph_frame_stats(VP9_COMP *cpi,
|
||||
MBGRAPH_FRAME_STATS *stats,
|
||||
YV12_BUFFER_CONFIG *buf,
|
||||
YV12_BUFFER_CONFIG *golden_ref,
|
||||
YV12_BUFFER_CONFIG *alt_ref) {
|
||||
MACROBLOCK *const x = &cpi->td.mb;
|
||||
MACROBLOCKD *const xd = &x->e_mbd;
|
||||
VP9_COMMON *const cm = &cpi->common;
|
||||
|
||||
int mb_col, mb_row, offset = 0;
|
||||
int mb_y_offset = 0, arf_y_offset = 0, gld_y_offset = 0;
|
||||
MV gld_top_mv = { 0, 0 };
|
||||
MODE_INFO mi_local;
|
||||
MODE_INFO mi_above, mi_left;
|
||||
|
||||
vp9_zero(mi_local);
|
||||
// Set up limit values for motion vectors to prevent them extending outside
|
||||
// the UMV borders.
|
||||
x->mv_limits.row_min = -BORDER_MV_PIXELS_B16;
|
||||
x->mv_limits.row_max = (cm->mb_rows - 1) * 8 + BORDER_MV_PIXELS_B16;
|
||||
// Signal to vp9_predict_intra_block() that above is not available
|
||||
xd->above_mi = NULL;
|
||||
|
||||
xd->plane[0].dst.stride = buf->y_stride;
|
||||
xd->plane[0].pre[0].stride = buf->y_stride;
|
||||
xd->plane[1].dst.stride = buf->uv_stride;
|
||||
xd->mi[0] = &mi_local;
|
||||
mi_local.sb_type = BLOCK_16X16;
|
||||
mi_local.ref_frame[0] = LAST_FRAME;
|
||||
mi_local.ref_frame[1] = NONE;
|
||||
|
||||
for (mb_row = 0; mb_row < cm->mb_rows; mb_row++) {
|
||||
MV gld_left_mv = gld_top_mv;
|
||||
int mb_y_in_offset = mb_y_offset;
|
||||
int arf_y_in_offset = arf_y_offset;
|
||||
int gld_y_in_offset = gld_y_offset;
|
||||
|
||||
// Set up limit values for motion vectors to prevent them extending outside
|
||||
// the UMV borders.
|
||||
x->mv_limits.col_min = -BORDER_MV_PIXELS_B16;
|
||||
x->mv_limits.col_max = (cm->mb_cols - 1) * 8 + BORDER_MV_PIXELS_B16;
|
||||
// Signal to vp9_predict_intra_block() that left is not available
|
||||
xd->left_mi = NULL;
|
||||
|
||||
for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) {
|
||||
MBGRAPH_MB_STATS *mb_stats = &stats->mb_stats[offset + mb_col];
|
||||
|
||||
update_mbgraph_mb_stats(cpi, mb_stats, buf, mb_y_in_offset, golden_ref,
|
||||
&gld_left_mv, alt_ref, mb_row, mb_col);
|
||||
gld_left_mv = mb_stats->ref[GOLDEN_FRAME].m.mv.as_mv;
|
||||
if (mb_col == 0) {
|
||||
gld_top_mv = gld_left_mv;
|
||||
}
|
||||
// Signal to vp9_predict_intra_block() that left is available
|
||||
xd->left_mi = &mi_left;
|
||||
|
||||
mb_y_in_offset += 16;
|
||||
gld_y_in_offset += 16;
|
||||
arf_y_in_offset += 16;
|
||||
x->mv_limits.col_min -= 16;
|
||||
x->mv_limits.col_max -= 16;
|
||||
}
|
||||
|
||||
// Signal to vp9_predict_intra_block() that above is available
|
||||
xd->above_mi = &mi_above;
|
||||
|
||||
mb_y_offset += buf->y_stride * 16;
|
||||
gld_y_offset += golden_ref->y_stride * 16;
|
||||
if (alt_ref) arf_y_offset += alt_ref->y_stride * 16;
|
||||
x->mv_limits.row_min -= 16;
|
||||
x->mv_limits.row_max -= 16;
|
||||
offset += cm->mb_cols;
|
||||
}
|
||||
}
|
||||
|
||||
// void separate_arf_mbs_byzz
|
||||
static void separate_arf_mbs(VP9_COMP *cpi) {
|
||||
VP9_COMMON *const cm = &cpi->common;
|
||||
int mb_col, mb_row, offset, i;
|
||||
int mi_row, mi_col;
|
||||
int ncnt[4] = { 0 };
|
||||
int n_frames = cpi->mbgraph_n_frames;
|
||||
|
||||
int *arf_not_zz;
|
||||
|
||||
CHECK_MEM_ERROR(
|
||||
cm, arf_not_zz,
|
||||
vpx_calloc(cm->mb_rows * cm->mb_cols * sizeof(*arf_not_zz), 1));
|
||||
|
||||
// We are not interested in results beyond the alt ref itself.
|
||||
if (n_frames > cpi->rc.frames_till_gf_update_due)
|
||||
n_frames = cpi->rc.frames_till_gf_update_due;
|
||||
|
||||
// defer cost to reference frames
|
||||
for (i = n_frames - 1; i >= 0; i--) {
|
||||
MBGRAPH_FRAME_STATS *frame_stats = &cpi->mbgraph_stats[i];
|
||||
|
||||
for (offset = 0, mb_row = 0; mb_row < cm->mb_rows;
|
||||
offset += cm->mb_cols, mb_row++) {
|
||||
for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) {
|
||||
MBGRAPH_MB_STATS *mb_stats = &frame_stats->mb_stats[offset + mb_col];
|
||||
|
||||
int altref_err = mb_stats->ref[ALTREF_FRAME].err;
|
||||
int intra_err = mb_stats->ref[INTRA_FRAME].err;
|
||||
int golden_err = mb_stats->ref[GOLDEN_FRAME].err;
|
||||
|
||||
// Test for altref vs intra and gf and that its mv was 0,0.
|
||||
if (altref_err > 1000 || altref_err > intra_err ||
|
||||
altref_err > golden_err) {
|
||||
arf_not_zz[offset + mb_col]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// arf_not_zz is indexed by MB, but this loop is indexed by MI to avoid out
|
||||
// of bound access in segmentation_map
|
||||
for (mi_row = 0; mi_row < cm->mi_rows; mi_row++) {
|
||||
for (mi_col = 0; mi_col < cm->mi_cols; mi_col++) {
|
||||
// If any of the blocks in the sequence failed then the MB
|
||||
// goes in segment 0
|
||||
if (arf_not_zz[mi_row / 2 * cm->mb_cols + mi_col / 2]) {
|
||||
ncnt[0]++;
|
||||
cpi->segmentation_map[mi_row * cm->mi_cols + mi_col] = 0;
|
||||
} else {
|
||||
cpi->segmentation_map[mi_row * cm->mi_cols + mi_col] = 1;
|
||||
ncnt[1]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Only bother with segmentation if over 10% of the MBs in static segment
|
||||
// if ( ncnt[1] && (ncnt[0] / ncnt[1] < 10) )
|
||||
if (1) {
|
||||
// Note % of blocks that are marked as static
|
||||
if (cm->MBs)
|
||||
cpi->static_mb_pct = (ncnt[1] * 100) / (cm->mi_rows * cm->mi_cols);
|
||||
|
||||
// This error case should not be reachable as this function should
|
||||
// never be called with the common data structure uninitialized.
|
||||
else
|
||||
cpi->static_mb_pct = 0;
|
||||
|
||||
vp9_enable_segmentation(&cm->seg);
|
||||
} else {
|
||||
cpi->static_mb_pct = 0;
|
||||
vp9_disable_segmentation(&cm->seg);
|
||||
}
|
||||
|
||||
// Free localy allocated storage
|
||||
vpx_free(arf_not_zz);
|
||||
}
|
||||
|
||||
void vp9_update_mbgraph_stats(VP9_COMP *cpi) {
|
||||
VP9_COMMON *const cm = &cpi->common;
|
||||
int i, n_frames = vp9_lookahead_depth(cpi->lookahead);
|
||||
YV12_BUFFER_CONFIG *golden_ref = get_ref_frame_buffer(cpi, GOLDEN_FRAME);
|
||||
|
||||
assert(golden_ref != NULL);
|
||||
|
||||
// we need to look ahead beyond where the ARF transitions into
|
||||
// being a GF - so exit if we don't look ahead beyond that
|
||||
if (n_frames <= cpi->rc.frames_till_gf_update_due) return;
|
||||
|
||||
if (n_frames > MAX_LAG_BUFFERS) n_frames = MAX_LAG_BUFFERS;
|
||||
|
||||
cpi->mbgraph_n_frames = n_frames;
|
||||
for (i = 0; i < n_frames; i++) {
|
||||
MBGRAPH_FRAME_STATS *frame_stats = &cpi->mbgraph_stats[i];
|
||||
memset(frame_stats->mb_stats, 0,
|
||||
cm->mb_rows * cm->mb_cols * sizeof(*cpi->mbgraph_stats[i].mb_stats));
|
||||
}
|
||||
|
||||
// do motion search to find contribution of each reference to data
|
||||
// later on in this GF group
|
||||
// FIXME really, the GF/last MC search should be done forward, and
|
||||
// the ARF MC search backwards, to get optimal results for MV caching
|
||||
for (i = 0; i < n_frames; i++) {
|
||||
MBGRAPH_FRAME_STATS *frame_stats = &cpi->mbgraph_stats[i];
|
||||
struct lookahead_entry *q_cur = vp9_lookahead_peek(cpi->lookahead, i);
|
||||
|
||||
assert(q_cur != NULL);
|
||||
|
||||
update_mbgraph_frame_stats(cpi, frame_stats, &q_cur->img, golden_ref,
|
||||
cpi->Source);
|
||||
}
|
||||
|
||||
vpx_clear_system_state();
|
||||
|
||||
separate_arf_mbs(cpi);
|
||||
}
|
||||
@@ -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_ENCODER_VP9_MBGRAPH_H_
|
||||
#define VPX_VP9_ENCODER_VP9_MBGRAPH_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
struct {
|
||||
int err;
|
||||
union {
|
||||
int_mv mv;
|
||||
PREDICTION_MODE mode;
|
||||
} m;
|
||||
} ref[MAX_REF_FRAMES];
|
||||
} MBGRAPH_MB_STATS;
|
||||
|
||||
typedef struct {
|
||||
MBGRAPH_MB_STATS *mb_stats;
|
||||
} MBGRAPH_FRAME_STATS;
|
||||
|
||||
struct VP9_COMP;
|
||||
|
||||
void vp9_update_mbgraph_stats(struct VP9_COMP *cpi);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_ENCODER_VP9_MBGRAPH_H_
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* 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_ENCODER_VP9_MCOMP_H_
|
||||
#define VPX_VP9_ENCODER_VP9_MCOMP_H_
|
||||
|
||||
#include "vp9/encoder/vp9_block.h"
|
||||
#if CONFIG_NON_GREEDY_MV
|
||||
#include "vp9/encoder/vp9_non_greedy_mv.h"
|
||||
#endif // CONFIG_NON_GREEDY_MV
|
||||
#include "vpx_dsp/variance.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// The maximum number of steps in a step search given the largest
|
||||
// allowed initial step
|
||||
#define MAX_MVSEARCH_STEPS 11
|
||||
// Max full pel mv specified in the unit of full pixel
|
||||
// Enable the use of motion vector in range [-1023, 1023].
|
||||
#define MAX_FULL_PEL_VAL ((1 << (MAX_MVSEARCH_STEPS - 1)) - 1)
|
||||
// Maximum size of the first step in full pel units
|
||||
#define MAX_FIRST_STEP (1 << (MAX_MVSEARCH_STEPS - 1))
|
||||
// Allowed motion vector pixel distance outside image border
|
||||
// for Block_16x16
|
||||
#define BORDER_MV_PIXELS_B16 (16 + VP9_INTERP_EXTEND)
|
||||
|
||||
typedef struct search_site_config {
|
||||
// motion search sites
|
||||
MV ss_mv[8 * MAX_MVSEARCH_STEPS]; // Motion vector
|
||||
intptr_t ss_os[8 * MAX_MVSEARCH_STEPS]; // Offset
|
||||
int searches_per_step;
|
||||
int total_steps;
|
||||
} search_site_config;
|
||||
|
||||
static INLINE const uint8_t *get_buf_from_mv(const struct buf_2d *buf,
|
||||
const MV *mv) {
|
||||
return &buf->buf[mv->row * buf->stride + mv->col];
|
||||
}
|
||||
|
||||
void vp9_init_dsmotion_compensation(search_site_config *cfg, int stride);
|
||||
void vp9_init3smotion_compensation(search_site_config *cfg, int stride);
|
||||
|
||||
void vp9_set_mv_search_range(MvLimits *mv_limits, const MV *mv);
|
||||
int vp9_mv_bit_cost(const MV *mv, const MV *ref, const int *mvjcost,
|
||||
int *mvcost[2], int weight);
|
||||
|
||||
// Utility to compute variance + MV rate cost for a given MV
|
||||
int vp9_get_mvpred_var(const MACROBLOCK *x, const MV *best_mv,
|
||||
const MV *center_mv, const vp9_variance_fn_ptr_t *vfp,
|
||||
int use_mvcost);
|
||||
int vp9_get_mvpred_av_var(const MACROBLOCK *x, const MV *best_mv,
|
||||
const MV *center_mv, const uint8_t *second_pred,
|
||||
const vp9_variance_fn_ptr_t *vfp, int use_mvcost);
|
||||
|
||||
struct VP9_COMP;
|
||||
struct SPEED_FEATURES;
|
||||
|
||||
int vp9_init_search_range(int size);
|
||||
|
||||
int vp9_refining_search_sad(const struct macroblock *x, struct mv *ref_mv,
|
||||
int error_per_bit, int search_range,
|
||||
const struct vp9_variance_vtable *fn_ptr,
|
||||
const struct mv *center_mv);
|
||||
|
||||
// Perform integral projection based motion estimation.
|
||||
unsigned int vp9_int_pro_motion_estimation(const struct VP9_COMP *cpi,
|
||||
MACROBLOCK *x, BLOCK_SIZE bsize,
|
||||
int mi_row, int mi_col,
|
||||
const MV *ref_mv);
|
||||
|
||||
typedef uint32_t(fractional_mv_step_fp)(
|
||||
const MACROBLOCK *x, MV *bestmv, const MV *ref_mv, int allow_hp,
|
||||
int error_per_bit, const vp9_variance_fn_ptr_t *vfp,
|
||||
int forced_stop, // 0 - full, 1 - qtr only, 2 - half only
|
||||
int iters_per_step, int *cost_list, int *mvjcost, int *mvcost[2],
|
||||
uint32_t *distortion, uint32_t *sse1, const uint8_t *second_pred, int w,
|
||||
int h, int use_accurate_subpel_search);
|
||||
|
||||
extern fractional_mv_step_fp vp9_find_best_sub_pixel_tree;
|
||||
extern fractional_mv_step_fp vp9_find_best_sub_pixel_tree_pruned;
|
||||
extern fractional_mv_step_fp vp9_find_best_sub_pixel_tree_pruned_more;
|
||||
extern fractional_mv_step_fp vp9_find_best_sub_pixel_tree_pruned_evenmore;
|
||||
extern fractional_mv_step_fp vp9_skip_sub_pixel_tree;
|
||||
extern fractional_mv_step_fp vp9_return_max_sub_pixel_mv;
|
||||
extern fractional_mv_step_fp vp9_return_min_sub_pixel_mv;
|
||||
|
||||
typedef int (*vp9_full_search_fn_t)(const MACROBLOCK *x, const MV *ref_mv,
|
||||
int sad_per_bit, int distance,
|
||||
const vp9_variance_fn_ptr_t *fn_ptr,
|
||||
const MV *center_mv, MV *best_mv);
|
||||
|
||||
typedef int (*vp9_refining_search_fn_t)(const MACROBLOCK *x, MV *ref_mv,
|
||||
int sad_per_bit, int distance,
|
||||
const vp9_variance_fn_ptr_t *fn_ptr,
|
||||
const MV *center_mv);
|
||||
|
||||
typedef int (*vp9_diamond_search_fn_t)(
|
||||
const MACROBLOCK *x, const search_site_config *cfg, MV *ref_mv, MV *best_mv,
|
||||
int search_param, int sad_per_bit, int *num00,
|
||||
const vp9_variance_fn_ptr_t *fn_ptr, const MV *center_mv);
|
||||
|
||||
int vp9_refining_search_8p_c(const MACROBLOCK *x, MV *ref_mv, int error_per_bit,
|
||||
int search_range,
|
||||
const vp9_variance_fn_ptr_t *fn_ptr,
|
||||
const MV *center_mv, const uint8_t *second_pred);
|
||||
|
||||
struct VP9_COMP;
|
||||
|
||||
// "mvp_full" is the MV search starting point;
|
||||
// "ref_mv" is the context reference MV;
|
||||
// "tmp_mv" is the searched best MV.
|
||||
int vp9_full_pixel_search(const struct VP9_COMP *const cpi,
|
||||
const MACROBLOCK *const x, BLOCK_SIZE bsize,
|
||||
MV *mvp_full, int step_param, int search_method,
|
||||
int error_per_bit, int *cost_list, const MV *ref_mv,
|
||||
MV *tmp_mv, int var_max, int rd);
|
||||
|
||||
void vp9_set_subpel_mv_search_range(MvLimits *subpel_mv_limits,
|
||||
const MvLimits *umv_window_limits,
|
||||
const MV *ref_mv);
|
||||
|
||||
#if CONFIG_NON_GREEDY_MV
|
||||
struct TplDepStats;
|
||||
int64_t vp9_refining_search_sad_new(const MACROBLOCK *x, MV *best_full_mv,
|
||||
int lambda, int search_range,
|
||||
const vp9_variance_fn_ptr_t *fn_ptr,
|
||||
const int_mv *nb_full_mvs, int full_mv_num);
|
||||
|
||||
int vp9_full_pixel_diamond_new(const struct VP9_COMP *cpi, MACROBLOCK *x,
|
||||
BLOCK_SIZE bsize, MV *mvp_full, int step_param,
|
||||
int lambda, int do_refine,
|
||||
const int_mv *nb_full_mvs, int full_mv_num,
|
||||
MV *best_mv);
|
||||
|
||||
static INLINE MV get_full_mv(const MV *mv) {
|
||||
MV out_mv;
|
||||
out_mv.row = mv->row >> 3;
|
||||
out_mv.col = mv->col >> 3;
|
||||
return out_mv;
|
||||
}
|
||||
struct TplDepFrame;
|
||||
int vp9_prepare_nb_full_mvs(const struct MotionField *motion_field, int mi_row,
|
||||
int mi_col, int_mv *nb_full_mvs);
|
||||
|
||||
static INLINE BLOCK_SIZE get_square_block_size(BLOCK_SIZE bsize) {
|
||||
BLOCK_SIZE square_bsize;
|
||||
switch (bsize) {
|
||||
case BLOCK_4X4:
|
||||
case BLOCK_4X8:
|
||||
case BLOCK_8X4: square_bsize = BLOCK_4X4; break;
|
||||
case BLOCK_8X8:
|
||||
case BLOCK_8X16:
|
||||
case BLOCK_16X8: square_bsize = BLOCK_8X8; break;
|
||||
case BLOCK_16X16:
|
||||
case BLOCK_16X32:
|
||||
case BLOCK_32X16: square_bsize = BLOCK_16X16; break;
|
||||
case BLOCK_32X32:
|
||||
case BLOCK_32X64:
|
||||
case BLOCK_64X32:
|
||||
case BLOCK_64X64: square_bsize = BLOCK_32X32; break;
|
||||
default:
|
||||
square_bsize = BLOCK_INVALID;
|
||||
assert(0 && "ERROR: invalid block size");
|
||||
break;
|
||||
}
|
||||
return square_bsize;
|
||||
}
|
||||
#endif // CONFIG_NON_GREEDY_MV
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_ENCODER_VP9_MCOMP_H_
|
||||
@@ -0,0 +1,333 @@
|
||||
/*
|
||||
* 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 <assert.h>
|
||||
|
||||
#include "vp9/encoder/vp9_encoder.h"
|
||||
#include "vp9/encoder/vp9_ethread.h"
|
||||
#include "vp9/encoder/vp9_multi_thread.h"
|
||||
#include "vp9/encoder/vp9_temporal_filter.h"
|
||||
|
||||
void *vp9_enc_grp_get_next_job(MultiThreadHandle *multi_thread_ctxt,
|
||||
int tile_id) {
|
||||
RowMTInfo *row_mt_info;
|
||||
JobQueueHandle *job_queue_hdl = NULL;
|
||||
void *next = NULL;
|
||||
JobNode *job_info = NULL;
|
||||
#if CONFIG_MULTITHREAD
|
||||
pthread_mutex_t *mutex_handle = NULL;
|
||||
#endif
|
||||
|
||||
row_mt_info = (RowMTInfo *)(&multi_thread_ctxt->row_mt_info[tile_id]);
|
||||
job_queue_hdl = (JobQueueHandle *)&row_mt_info->job_queue_hdl;
|
||||
#if CONFIG_MULTITHREAD
|
||||
mutex_handle = &row_mt_info->job_mutex;
|
||||
#endif
|
||||
|
||||
// lock the mutex for queue access
|
||||
#if CONFIG_MULTITHREAD
|
||||
pthread_mutex_lock(mutex_handle);
|
||||
#endif
|
||||
next = job_queue_hdl->next;
|
||||
if (NULL != next) {
|
||||
JobQueue *job_queue = (JobQueue *)next;
|
||||
job_info = &job_queue->job_info;
|
||||
// Update the next job in the queue
|
||||
job_queue_hdl->next = job_queue->next;
|
||||
job_queue_hdl->num_jobs_acquired++;
|
||||
}
|
||||
|
||||
#if CONFIG_MULTITHREAD
|
||||
pthread_mutex_unlock(mutex_handle);
|
||||
#endif
|
||||
|
||||
return job_info;
|
||||
}
|
||||
|
||||
void vp9_row_mt_alloc_rd_thresh(VP9_COMP *const cpi,
|
||||
TileDataEnc *const this_tile) {
|
||||
VP9_COMMON *const cm = &cpi->common;
|
||||
const int sb_rows =
|
||||
(mi_cols_aligned_to_sb(cm->mi_rows) >> MI_BLOCK_SIZE_LOG2) + 1;
|
||||
int i;
|
||||
|
||||
this_tile->row_base_thresh_freq_fact =
|
||||
(int *)vpx_calloc(sb_rows * BLOCK_SIZES * MAX_MODES,
|
||||
sizeof(*(this_tile->row_base_thresh_freq_fact)));
|
||||
for (i = 0; i < sb_rows * BLOCK_SIZES * MAX_MODES; i++)
|
||||
this_tile->row_base_thresh_freq_fact[i] = RD_THRESH_INIT_FACT;
|
||||
}
|
||||
|
||||
void vp9_row_mt_mem_alloc(VP9_COMP *cpi) {
|
||||
struct VP9Common *cm = &cpi->common;
|
||||
MultiThreadHandle *multi_thread_ctxt = &cpi->multi_thread_ctxt;
|
||||
int tile_row, tile_col;
|
||||
const int tile_cols = 1 << cm->log2_tile_cols;
|
||||
const int tile_rows = 1 << cm->log2_tile_rows;
|
||||
const int sb_rows = mi_cols_aligned_to_sb(cm->mi_rows) >> MI_BLOCK_SIZE_LOG2;
|
||||
int jobs_per_tile_col, total_jobs;
|
||||
|
||||
// Allocate memory that is large enough for all row_mt stages. First pass
|
||||
// uses 16x16 block size.
|
||||
jobs_per_tile_col = VPXMAX(cm->mb_rows, sb_rows);
|
||||
// Calculate the total number of jobs
|
||||
total_jobs = jobs_per_tile_col * tile_cols;
|
||||
|
||||
multi_thread_ctxt->allocated_tile_cols = tile_cols;
|
||||
multi_thread_ctxt->allocated_tile_rows = tile_rows;
|
||||
multi_thread_ctxt->allocated_vert_unit_rows = jobs_per_tile_col;
|
||||
|
||||
multi_thread_ctxt->job_queue =
|
||||
(JobQueue *)vpx_memalign(32, total_jobs * sizeof(JobQueue));
|
||||
|
||||
#if CONFIG_MULTITHREAD
|
||||
// Create mutex for each tile
|
||||
for (tile_col = 0; tile_col < tile_cols; tile_col++) {
|
||||
RowMTInfo *row_mt_info = &multi_thread_ctxt->row_mt_info[tile_col];
|
||||
pthread_mutex_init(&row_mt_info->job_mutex, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Allocate memory for row based multi-threading
|
||||
for (tile_col = 0; tile_col < tile_cols; tile_col++) {
|
||||
TileDataEnc *this_tile = &cpi->tile_data[tile_col];
|
||||
vp9_row_mt_sync_mem_alloc(&this_tile->row_mt_sync, cm, jobs_per_tile_col);
|
||||
if (cpi->sf.adaptive_rd_thresh_row_mt) {
|
||||
if (this_tile->row_base_thresh_freq_fact != NULL) {
|
||||
vpx_free(this_tile->row_base_thresh_freq_fact);
|
||||
this_tile->row_base_thresh_freq_fact = NULL;
|
||||
}
|
||||
vp9_row_mt_alloc_rd_thresh(cpi, this_tile);
|
||||
}
|
||||
}
|
||||
|
||||
// Assign the sync pointer of tile row zero for every tile row > 0
|
||||
for (tile_row = 1; tile_row < tile_rows; tile_row++) {
|
||||
for (tile_col = 0; tile_col < tile_cols; tile_col++) {
|
||||
TileDataEnc *this_tile = &cpi->tile_data[tile_row * tile_cols + tile_col];
|
||||
TileDataEnc *this_col_tile = &cpi->tile_data[tile_col];
|
||||
this_tile->row_mt_sync = this_col_tile->row_mt_sync;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the number of vertical units in the given tile row
|
||||
for (tile_row = 0; tile_row < tile_rows; tile_row++) {
|
||||
TileDataEnc *this_tile = &cpi->tile_data[tile_row * tile_cols];
|
||||
TileInfo *tile_info = &this_tile->tile_info;
|
||||
multi_thread_ctxt->num_tile_vert_sbs[tile_row] =
|
||||
get_num_vert_units(*tile_info, MI_BLOCK_SIZE_LOG2);
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_row_mt_mem_dealloc(VP9_COMP *cpi) {
|
||||
MultiThreadHandle *multi_thread_ctxt = &cpi->multi_thread_ctxt;
|
||||
int tile_col;
|
||||
#if CONFIG_MULTITHREAD
|
||||
int tile_row;
|
||||
#endif
|
||||
|
||||
// Deallocate memory for job queue
|
||||
if (multi_thread_ctxt->job_queue) vpx_free(multi_thread_ctxt->job_queue);
|
||||
|
||||
#if CONFIG_MULTITHREAD
|
||||
// Destroy mutex for each tile
|
||||
for (tile_col = 0; tile_col < multi_thread_ctxt->allocated_tile_cols;
|
||||
tile_col++) {
|
||||
RowMTInfo *row_mt_info = &multi_thread_ctxt->row_mt_info[tile_col];
|
||||
if (row_mt_info) pthread_mutex_destroy(&row_mt_info->job_mutex);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Free row based multi-threading sync memory
|
||||
for (tile_col = 0; tile_col < multi_thread_ctxt->allocated_tile_cols;
|
||||
tile_col++) {
|
||||
TileDataEnc *this_tile = &cpi->tile_data[tile_col];
|
||||
vp9_row_mt_sync_mem_dealloc(&this_tile->row_mt_sync);
|
||||
}
|
||||
|
||||
#if CONFIG_MULTITHREAD
|
||||
for (tile_row = 0; tile_row < multi_thread_ctxt->allocated_tile_rows;
|
||||
tile_row++) {
|
||||
for (tile_col = 0; tile_col < multi_thread_ctxt->allocated_tile_cols;
|
||||
tile_col++) {
|
||||
TileDataEnc *this_tile =
|
||||
&cpi->tile_data[tile_row * multi_thread_ctxt->allocated_tile_cols +
|
||||
tile_col];
|
||||
if (this_tile->row_base_thresh_freq_fact != NULL) {
|
||||
vpx_free(this_tile->row_base_thresh_freq_fact);
|
||||
this_tile->row_base_thresh_freq_fact = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void vp9_multi_thread_tile_init(VP9_COMP *cpi) {
|
||||
VP9_COMMON *const cm = &cpi->common;
|
||||
const int tile_cols = 1 << cm->log2_tile_cols;
|
||||
const int sb_rows = mi_cols_aligned_to_sb(cm->mi_rows) >> MI_BLOCK_SIZE_LOG2;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < tile_cols; i++) {
|
||||
TileDataEnc *this_tile = &cpi->tile_data[i];
|
||||
int jobs_per_tile_col = cpi->oxcf.pass == 1 ? cm->mb_rows : sb_rows;
|
||||
|
||||
// Initialize cur_col to -1 for all rows.
|
||||
memset(this_tile->row_mt_sync.cur_col, -1,
|
||||
sizeof(*this_tile->row_mt_sync.cur_col) * jobs_per_tile_col);
|
||||
vp9_zero(this_tile->fp_data);
|
||||
this_tile->fp_data.image_data_start_row = INVALID_ROW;
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_assign_tile_to_thread(MultiThreadHandle *multi_thread_ctxt,
|
||||
int tile_cols, int num_workers) {
|
||||
int tile_id = 0;
|
||||
int i;
|
||||
|
||||
// Allocating the threads for the tiles
|
||||
for (i = 0; i < num_workers; i++) {
|
||||
multi_thread_ctxt->thread_id_to_tile_id[i] = tile_id++;
|
||||
if (tile_id == tile_cols) tile_id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int vp9_get_job_queue_status(MultiThreadHandle *multi_thread_ctxt,
|
||||
int cur_tile_id) {
|
||||
RowMTInfo *row_mt_info;
|
||||
JobQueueHandle *job_queue_hndl;
|
||||
#if CONFIG_MULTITHREAD
|
||||
pthread_mutex_t *mutex;
|
||||
#endif
|
||||
int num_jobs_remaining;
|
||||
|
||||
row_mt_info = &multi_thread_ctxt->row_mt_info[cur_tile_id];
|
||||
job_queue_hndl = &row_mt_info->job_queue_hdl;
|
||||
#if CONFIG_MULTITHREAD
|
||||
mutex = &row_mt_info->job_mutex;
|
||||
#endif
|
||||
|
||||
#if CONFIG_MULTITHREAD
|
||||
pthread_mutex_lock(mutex);
|
||||
#endif
|
||||
num_jobs_remaining =
|
||||
multi_thread_ctxt->jobs_per_tile_col - job_queue_hndl->num_jobs_acquired;
|
||||
#if CONFIG_MULTITHREAD
|
||||
pthread_mutex_unlock(mutex);
|
||||
#endif
|
||||
|
||||
return (num_jobs_remaining);
|
||||
}
|
||||
|
||||
void vp9_prepare_job_queue(VP9_COMP *cpi, JOB_TYPE job_type) {
|
||||
VP9_COMMON *const cm = &cpi->common;
|
||||
MultiThreadHandle *multi_thread_ctxt = &cpi->multi_thread_ctxt;
|
||||
JobQueue *job_queue = multi_thread_ctxt->job_queue;
|
||||
const int tile_cols = 1 << cm->log2_tile_cols;
|
||||
int job_row_num, jobs_per_tile, jobs_per_tile_col = 0, total_jobs;
|
||||
const int sb_rows = mi_cols_aligned_to_sb(cm->mi_rows) >> MI_BLOCK_SIZE_LOG2;
|
||||
int tile_col, i;
|
||||
|
||||
switch (job_type) {
|
||||
case ENCODE_JOB: jobs_per_tile_col = sb_rows; break;
|
||||
case FIRST_PASS_JOB: jobs_per_tile_col = cm->mb_rows; break;
|
||||
case ARNR_JOB:
|
||||
jobs_per_tile_col = ((cm->mi_rows + TF_ROUND) >> TF_SHIFT);
|
||||
break;
|
||||
default: assert(0);
|
||||
}
|
||||
|
||||
total_jobs = jobs_per_tile_col * tile_cols;
|
||||
|
||||
multi_thread_ctxt->jobs_per_tile_col = jobs_per_tile_col;
|
||||
// memset the entire job queue buffer to zero
|
||||
memset(job_queue, 0, total_jobs * sizeof(JobQueue));
|
||||
|
||||
// Job queue preparation
|
||||
for (tile_col = 0; tile_col < tile_cols; tile_col++) {
|
||||
RowMTInfo *tile_ctxt = &multi_thread_ctxt->row_mt_info[tile_col];
|
||||
JobQueue *job_queue_curr, *job_queue_temp;
|
||||
int tile_row = 0;
|
||||
|
||||
tile_ctxt->job_queue_hdl.next = (void *)job_queue;
|
||||
tile_ctxt->job_queue_hdl.num_jobs_acquired = 0;
|
||||
|
||||
job_queue_curr = job_queue;
|
||||
job_queue_temp = job_queue;
|
||||
|
||||
// loop over all the vertical rows
|
||||
for (job_row_num = 0, jobs_per_tile = 0; job_row_num < jobs_per_tile_col;
|
||||
job_row_num++, jobs_per_tile++) {
|
||||
job_queue_curr->job_info.vert_unit_row_num = job_row_num;
|
||||
job_queue_curr->job_info.tile_col_id = tile_col;
|
||||
job_queue_curr->job_info.tile_row_id = tile_row;
|
||||
job_queue_curr->next = (void *)(job_queue_temp + 1);
|
||||
job_queue_curr = ++job_queue_temp;
|
||||
|
||||
if (ENCODE_JOB == job_type) {
|
||||
if (jobs_per_tile >=
|
||||
multi_thread_ctxt->num_tile_vert_sbs[tile_row] - 1) {
|
||||
tile_row++;
|
||||
jobs_per_tile = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set the last pointer to NULL
|
||||
job_queue_curr += -1;
|
||||
job_queue_curr->next = (void *)NULL;
|
||||
|
||||
// Move to the next tile
|
||||
job_queue += jobs_per_tile_col;
|
||||
}
|
||||
|
||||
for (i = 0; i < cpi->num_workers; i++) {
|
||||
EncWorkerData *thread_data;
|
||||
thread_data = &cpi->tile_thr_data[i];
|
||||
thread_data->thread_id = i;
|
||||
|
||||
for (tile_col = 0; tile_col < tile_cols; tile_col++)
|
||||
thread_data->tile_completion_status[tile_col] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int vp9_get_tiles_proc_status(MultiThreadHandle *multi_thread_ctxt,
|
||||
int *tile_completion_status, int *cur_tile_id,
|
||||
int tile_cols) {
|
||||
int tile_col;
|
||||
int tile_id = -1; // Stores the tile ID with minimum proc done
|
||||
int max_num_jobs_remaining = 0;
|
||||
int num_jobs_remaining;
|
||||
|
||||
// Mark the completion to avoid check in the loop
|
||||
tile_completion_status[*cur_tile_id] = 1;
|
||||
// Check for the status of all the tiles
|
||||
for (tile_col = 0; tile_col < tile_cols; tile_col++) {
|
||||
if (tile_completion_status[tile_col] == 0) {
|
||||
num_jobs_remaining =
|
||||
vp9_get_job_queue_status(multi_thread_ctxt, tile_col);
|
||||
// Mark the completion to avoid checks during future switches across tiles
|
||||
if (num_jobs_remaining == 0) tile_completion_status[tile_col] = 1;
|
||||
if (num_jobs_remaining > max_num_jobs_remaining) {
|
||||
max_num_jobs_remaining = num_jobs_remaining;
|
||||
tile_id = tile_col;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (-1 == tile_id) {
|
||||
return 1;
|
||||
} else {
|
||||
// Update the cur ID to the next tile ID that will be processed,
|
||||
// which will be the least processed tile
|
||||
*cur_tile_id = tile_id;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef VPX_VP9_ENCODER_VP9_MULTI_THREAD_H_
|
||||
#define VPX_VP9_ENCODER_VP9_MULTI_THREAD_H_
|
||||
|
||||
#include "vp9/encoder/vp9_encoder.h"
|
||||
#include "vp9/encoder/vp9_job_queue.h"
|
||||
|
||||
void *vp9_enc_grp_get_next_job(MultiThreadHandle *multi_thread_ctxt,
|
||||
int tile_id);
|
||||
|
||||
void vp9_prepare_job_queue(VP9_COMP *cpi, JOB_TYPE job_type);
|
||||
|
||||
int vp9_get_job_queue_status(MultiThreadHandle *multi_thread_ctxt,
|
||||
int cur_tile_id);
|
||||
|
||||
void vp9_assign_tile_to_thread(MultiThreadHandle *multi_thread_ctxt,
|
||||
int tile_cols, int num_workers);
|
||||
|
||||
void vp9_multi_thread_tile_init(VP9_COMP *cpi);
|
||||
|
||||
void vp9_row_mt_mem_alloc(VP9_COMP *cpi);
|
||||
|
||||
void vp9_row_mt_alloc_rd_thresh(VP9_COMP *const cpi,
|
||||
TileDataEnc *const this_tile);
|
||||
|
||||
void vp9_row_mt_mem_dealloc(VP9_COMP *cpi);
|
||||
|
||||
int vp9_get_tiles_proc_status(MultiThreadHandle *multi_thread_ctxt,
|
||||
int *tile_completion_status, int *cur_tile_id,
|
||||
int tile_cols);
|
||||
|
||||
#endif // VPX_VP9_ENCODER_VP9_MULTI_THREAD_H_
|
||||
@@ -0,0 +1,302 @@
|
||||
/*
|
||||
* 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 <limits.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "./vpx_dsp_rtcd.h"
|
||||
#include "vpx_dsp/vpx_dsp_common.h"
|
||||
#include "vpx_scale/yv12config.h"
|
||||
#include "vpx/vpx_integer.h"
|
||||
#include "vp9/common/vp9_reconinter.h"
|
||||
#include "vp9/encoder/vp9_context_tree.h"
|
||||
#include "vp9/encoder/vp9_noise_estimate.h"
|
||||
#include "vp9/encoder/vp9_encoder.h"
|
||||
|
||||
#if CONFIG_VP9_TEMPORAL_DENOISING
|
||||
// For SVC: only do noise estimation on top spatial layer.
|
||||
static INLINE int noise_est_svc(const struct VP9_COMP *const cpi) {
|
||||
return (!cpi->use_svc ||
|
||||
(cpi->use_svc &&
|
||||
cpi->svc.spatial_layer_id == cpi->svc.number_spatial_layers - 1));
|
||||
}
|
||||
#endif
|
||||
|
||||
void vp9_noise_estimate_init(NOISE_ESTIMATE *const ne, int width, int height) {
|
||||
ne->enabled = 0;
|
||||
ne->level = (width * height < 1280 * 720) ? kLowLow : kLow;
|
||||
ne->value = 0;
|
||||
ne->count = 0;
|
||||
ne->thresh = 90;
|
||||
ne->last_w = 0;
|
||||
ne->last_h = 0;
|
||||
if (width * height >= 1920 * 1080) {
|
||||
ne->thresh = 200;
|
||||
} else if (width * height >= 1280 * 720) {
|
||||
ne->thresh = 140;
|
||||
} else if (width * height >= 640 * 360) {
|
||||
ne->thresh = 115;
|
||||
}
|
||||
ne->num_frames_estimate = 15;
|
||||
ne->adapt_thresh = (3 * ne->thresh) >> 1;
|
||||
}
|
||||
|
||||
static int enable_noise_estimation(VP9_COMP *const cpi) {
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
if (cpi->common.use_highbitdepth) return 0;
|
||||
#endif
|
||||
// Enable noise estimation if denoising is on.
|
||||
#if CONFIG_VP9_TEMPORAL_DENOISING
|
||||
if (cpi->oxcf.noise_sensitivity > 0 && noise_est_svc(cpi) &&
|
||||
cpi->common.width >= 320 && cpi->common.height >= 180)
|
||||
return 1;
|
||||
#endif
|
||||
// Only allow noise estimate under certain encoding mode.
|
||||
// Enabled for 1 pass CBR, speed >=5, and if resolution is same as original.
|
||||
// Not enabled for SVC mode and screen_content_mode.
|
||||
// Not enabled for low resolutions.
|
||||
if (cpi->oxcf.pass == 0 && cpi->oxcf.rc_mode == VPX_CBR &&
|
||||
cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ && cpi->oxcf.speed >= 5 &&
|
||||
cpi->resize_state == ORIG && cpi->resize_pending == 0 && !cpi->use_svc &&
|
||||
cpi->oxcf.content != VP9E_CONTENT_SCREEN &&
|
||||
cpi->common.width * cpi->common.height >= 640 * 360)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if CONFIG_VP9_TEMPORAL_DENOISING
|
||||
static void copy_frame(YV12_BUFFER_CONFIG *const dest,
|
||||
const YV12_BUFFER_CONFIG *const src) {
|
||||
int r;
|
||||
const uint8_t *srcbuf = src->y_buffer;
|
||||
uint8_t *destbuf = dest->y_buffer;
|
||||
|
||||
assert(dest->y_width == src->y_width);
|
||||
assert(dest->y_height == src->y_height);
|
||||
|
||||
for (r = 0; r < dest->y_height; ++r) {
|
||||
memcpy(destbuf, srcbuf, dest->y_width);
|
||||
destbuf += dest->y_stride;
|
||||
srcbuf += src->y_stride;
|
||||
}
|
||||
}
|
||||
#endif // CONFIG_VP9_TEMPORAL_DENOISING
|
||||
|
||||
NOISE_LEVEL vp9_noise_estimate_extract_level(NOISE_ESTIMATE *const ne) {
|
||||
int noise_level = kLowLow;
|
||||
if (ne->value > (ne->thresh << 1)) {
|
||||
noise_level = kHigh;
|
||||
} else {
|
||||
if (ne->value > ne->thresh)
|
||||
noise_level = kMedium;
|
||||
else if (ne->value > (ne->thresh >> 1))
|
||||
noise_level = kLow;
|
||||
else
|
||||
noise_level = kLowLow;
|
||||
}
|
||||
return noise_level;
|
||||
}
|
||||
|
||||
void vp9_update_noise_estimate(VP9_COMP *const cpi) {
|
||||
const VP9_COMMON *const cm = &cpi->common;
|
||||
NOISE_ESTIMATE *const ne = &cpi->noise_estimate;
|
||||
const int low_res = (cm->width <= 352 && cm->height <= 288);
|
||||
// Estimate of noise level every frame_period frames.
|
||||
int frame_period = 8;
|
||||
int thresh_consec_zeromv = 6;
|
||||
int frame_counter = cm->current_video_frame;
|
||||
// Estimate is between current source and last source.
|
||||
YV12_BUFFER_CONFIG *last_source = cpi->Last_Source;
|
||||
#if CONFIG_VP9_TEMPORAL_DENOISING
|
||||
if (cpi->oxcf.noise_sensitivity > 0 && noise_est_svc(cpi)) {
|
||||
last_source = &cpi->denoiser.last_source;
|
||||
// Tune these thresholds for different resolutions when denoising is
|
||||
// enabled.
|
||||
if (cm->width > 640 && cm->width <= 1920) {
|
||||
thresh_consec_zeromv = 2;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
ne->enabled = enable_noise_estimation(cpi);
|
||||
if (cpi->svc.number_spatial_layers > 1)
|
||||
frame_counter = cpi->svc.current_superframe;
|
||||
if (!ne->enabled || frame_counter % frame_period != 0 ||
|
||||
last_source == NULL ||
|
||||
(cpi->svc.number_spatial_layers == 1 &&
|
||||
(ne->last_w != cm->width || ne->last_h != cm->height))) {
|
||||
#if CONFIG_VP9_TEMPORAL_DENOISING
|
||||
if (cpi->oxcf.noise_sensitivity > 0 && noise_est_svc(cpi))
|
||||
copy_frame(&cpi->denoiser.last_source, cpi->Source);
|
||||
#endif
|
||||
if (last_source != NULL) {
|
||||
ne->last_w = cm->width;
|
||||
ne->last_h = cm->height;
|
||||
}
|
||||
return;
|
||||
} else if (frame_counter > 60 && cpi->svc.num_encoded_top_layer > 1 &&
|
||||
cpi->rc.frames_since_key > cpi->svc.number_spatial_layers &&
|
||||
cpi->svc.spatial_layer_id == cpi->svc.number_spatial_layers - 1 &&
|
||||
cpi->rc.avg_frame_low_motion < (low_res ? 60 : 40)) {
|
||||
// Force noise estimation to 0 and denoiser off if content has high motion.
|
||||
ne->level = kLowLow;
|
||||
ne->count = 0;
|
||||
ne->num_frames_estimate = 10;
|
||||
#if CONFIG_VP9_TEMPORAL_DENOISING
|
||||
if (cpi->oxcf.noise_sensitivity > 0 && noise_est_svc(cpi) &&
|
||||
cpi->svc.current_superframe > 1) {
|
||||
vp9_denoiser_set_noise_level(cpi, ne->level);
|
||||
copy_frame(&cpi->denoiser.last_source, cpi->Source);
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
} else {
|
||||
unsigned int bin_size = 100;
|
||||
unsigned int hist[MAX_VAR_HIST_BINS] = { 0 };
|
||||
unsigned int hist_avg[MAX_VAR_HIST_BINS];
|
||||
unsigned int max_bin = 0;
|
||||
unsigned int max_bin_count = 0;
|
||||
unsigned int bin_cnt;
|
||||
int bsize = BLOCK_16X16;
|
||||
// Loop over sub-sample of 16x16 blocks of frame, and for blocks that have
|
||||
// been encoded as zero/small mv at least x consecutive frames, compute
|
||||
// the variance to update estimate of noise in the source.
|
||||
const uint8_t *src_y = cpi->Source->y_buffer;
|
||||
const int src_ystride = cpi->Source->y_stride;
|
||||
const uint8_t *last_src_y = last_source->y_buffer;
|
||||
const int last_src_ystride = last_source->y_stride;
|
||||
const uint8_t *src_u = cpi->Source->u_buffer;
|
||||
const uint8_t *src_v = cpi->Source->v_buffer;
|
||||
const int src_uvstride = cpi->Source->uv_stride;
|
||||
int mi_row, mi_col;
|
||||
int num_low_motion = 0;
|
||||
int frame_low_motion = 1;
|
||||
for (mi_row = 0; mi_row < cm->mi_rows; mi_row++) {
|
||||
for (mi_col = 0; mi_col < cm->mi_cols; mi_col++) {
|
||||
int bl_index = mi_row * cm->mi_cols + mi_col;
|
||||
if (cpi->consec_zero_mv[bl_index] > thresh_consec_zeromv)
|
||||
num_low_motion++;
|
||||
}
|
||||
}
|
||||
if (num_low_motion < ((3 * cm->mi_rows * cm->mi_cols) >> 3))
|
||||
frame_low_motion = 0;
|
||||
for (mi_row = 0; mi_row < cm->mi_rows; mi_row++) {
|
||||
for (mi_col = 0; mi_col < cm->mi_cols; mi_col++) {
|
||||
// 16x16 blocks, 1/4 sample of frame.
|
||||
if (mi_row % 4 == 0 && mi_col % 4 == 0 && mi_row < cm->mi_rows - 1 &&
|
||||
mi_col < cm->mi_cols - 1) {
|
||||
int bl_index = mi_row * cm->mi_cols + mi_col;
|
||||
int bl_index1 = bl_index + 1;
|
||||
int bl_index2 = bl_index + cm->mi_cols;
|
||||
int bl_index3 = bl_index2 + 1;
|
||||
int consec_zeromv =
|
||||
VPXMIN(cpi->consec_zero_mv[bl_index],
|
||||
VPXMIN(cpi->consec_zero_mv[bl_index1],
|
||||
VPXMIN(cpi->consec_zero_mv[bl_index2],
|
||||
cpi->consec_zero_mv[bl_index3])));
|
||||
// Only consider blocks that are likely steady background. i.e, have
|
||||
// been encoded as zero/low motion x (= thresh_consec_zeromv) frames
|
||||
// in a row. consec_zero_mv[] defined for 8x8 blocks, so consider all
|
||||
// 4 sub-blocks for 16x16 block. And exclude this frame if
|
||||
// high_source_sad is true (i.e., scene/content change).
|
||||
if (frame_low_motion && consec_zeromv > thresh_consec_zeromv &&
|
||||
!cpi->rc.high_source_sad &&
|
||||
!cpi->svc.high_source_sad_superframe) {
|
||||
int is_skin = 0;
|
||||
if (cpi->use_skin_detection) {
|
||||
is_skin =
|
||||
vp9_compute_skin_block(src_y, src_u, src_v, src_ystride,
|
||||
src_uvstride, bsize, consec_zeromv, 0);
|
||||
}
|
||||
if (!is_skin) {
|
||||
unsigned int sse;
|
||||
// Compute variance between co-located blocks from current and
|
||||
// last input frames.
|
||||
unsigned int variance = cpi->fn_ptr[bsize].vf(
|
||||
src_y, src_ystride, last_src_y, last_src_ystride, &sse);
|
||||
unsigned int hist_index = variance / bin_size;
|
||||
if (hist_index < MAX_VAR_HIST_BINS)
|
||||
hist[hist_index]++;
|
||||
else if (hist_index < 3 * (MAX_VAR_HIST_BINS >> 1))
|
||||
hist[MAX_VAR_HIST_BINS - 1]++; // Account for the tail
|
||||
}
|
||||
}
|
||||
}
|
||||
src_y += 8;
|
||||
last_src_y += 8;
|
||||
src_u += 4;
|
||||
src_v += 4;
|
||||
}
|
||||
src_y += (src_ystride << 3) - (cm->mi_cols << 3);
|
||||
last_src_y += (last_src_ystride << 3) - (cm->mi_cols << 3);
|
||||
src_u += (src_uvstride << 2) - (cm->mi_cols << 2);
|
||||
src_v += (src_uvstride << 2) - (cm->mi_cols << 2);
|
||||
}
|
||||
ne->last_w = cm->width;
|
||||
ne->last_h = cm->height;
|
||||
// Adjust histogram to account for effect that histogram flattens
|
||||
// and shifts to zero as scene darkens.
|
||||
if (hist[0] > 10 && (hist[MAX_VAR_HIST_BINS - 1] > hist[0] >> 2)) {
|
||||
hist[0] = 0;
|
||||
hist[1] >>= 2;
|
||||
hist[2] >>= 2;
|
||||
hist[3] >>= 2;
|
||||
hist[4] >>= 1;
|
||||
hist[5] >>= 1;
|
||||
hist[6] = 3 * hist[6] >> 1;
|
||||
hist[MAX_VAR_HIST_BINS - 1] >>= 1;
|
||||
}
|
||||
|
||||
// Average hist[] and find largest bin
|
||||
for (bin_cnt = 0; bin_cnt < MAX_VAR_HIST_BINS; bin_cnt++) {
|
||||
if (bin_cnt == 0)
|
||||
hist_avg[bin_cnt] = (hist[0] + hist[1] + hist[2]) / 3;
|
||||
else if (bin_cnt == MAX_VAR_HIST_BINS - 1)
|
||||
hist_avg[bin_cnt] = hist[MAX_VAR_HIST_BINS - 1] >> 2;
|
||||
else if (bin_cnt == MAX_VAR_HIST_BINS - 2)
|
||||
hist_avg[bin_cnt] = (hist[bin_cnt - 1] + 2 * hist[bin_cnt] +
|
||||
(hist[bin_cnt + 1] >> 1) + 2) >>
|
||||
2;
|
||||
else
|
||||
hist_avg[bin_cnt] =
|
||||
(hist[bin_cnt - 1] + 2 * hist[bin_cnt] + hist[bin_cnt + 1] + 2) >>
|
||||
2;
|
||||
|
||||
if (hist_avg[bin_cnt] > max_bin_count) {
|
||||
max_bin_count = hist_avg[bin_cnt];
|
||||
max_bin = bin_cnt;
|
||||
}
|
||||
}
|
||||
|
||||
// Scale by 40 to work with existing thresholds
|
||||
ne->value = (int)((3 * ne->value + max_bin * 40) >> 2);
|
||||
// Quickly increase VNR strength when the noise level increases suddenly.
|
||||
if (ne->level < kMedium && ne->value > ne->adapt_thresh) {
|
||||
ne->count = ne->num_frames_estimate;
|
||||
} else {
|
||||
ne->count++;
|
||||
}
|
||||
if (ne->count == ne->num_frames_estimate) {
|
||||
// Reset counter and check noise level condition.
|
||||
ne->num_frames_estimate = 30;
|
||||
ne->count = 0;
|
||||
ne->level = vp9_noise_estimate_extract_level(ne);
|
||||
#if CONFIG_VP9_TEMPORAL_DENOISING
|
||||
if (cpi->oxcf.noise_sensitivity > 0 && noise_est_svc(cpi))
|
||||
vp9_denoiser_set_noise_level(cpi, ne->level);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#if CONFIG_VP9_TEMPORAL_DENOISING
|
||||
if (cpi->oxcf.noise_sensitivity > 0 && noise_est_svc(cpi))
|
||||
copy_frame(&cpi->denoiser.last_source, cpi->Source);
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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_ENCODER_VP9_NOISE_ESTIMATE_H_
|
||||
#define VPX_VP9_ENCODER_VP9_NOISE_ESTIMATE_H_
|
||||
|
||||
#include "vp9/encoder/vp9_block.h"
|
||||
#include "vp9/encoder/vp9_skin_detection.h"
|
||||
#include "vpx_scale/yv12config.h"
|
||||
|
||||
#if CONFIG_VP9_TEMPORAL_DENOISING
|
||||
#include "vp9/encoder/vp9_denoiser.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define MAX_VAR_HIST_BINS 20
|
||||
|
||||
typedef enum noise_level { kLowLow, kLow, kMedium, kHigh } NOISE_LEVEL;
|
||||
|
||||
typedef struct noise_estimate {
|
||||
int enabled;
|
||||
NOISE_LEVEL level;
|
||||
int value;
|
||||
int thresh;
|
||||
int adapt_thresh;
|
||||
int count;
|
||||
int last_w;
|
||||
int last_h;
|
||||
int num_frames_estimate;
|
||||
} NOISE_ESTIMATE;
|
||||
|
||||
struct VP9_COMP;
|
||||
|
||||
void vp9_noise_estimate_init(NOISE_ESTIMATE *const ne, int width, int height);
|
||||
|
||||
NOISE_LEVEL vp9_noise_estimate_extract_level(NOISE_ESTIMATE *const ne);
|
||||
|
||||
void vp9_update_noise_estimate(struct VP9_COMP *const cpi);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_ENCODER_VP9_NOISE_ESTIMATE_H_
|
||||
@@ -0,0 +1,533 @@
|
||||
/*
|
||||
* Copyright (c) 2019 The WebM project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can 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_mv.h"
|
||||
#include "vp9/encoder/vp9_non_greedy_mv.h"
|
||||
// TODO(angiebird): move non_greedy_mv related functions to this file
|
||||
|
||||
#define LOG2_TABLE_SIZE 1024
|
||||
static const int log2_table[LOG2_TABLE_SIZE] = {
|
||||
0, // This is a dummy value
|
||||
0, 1048576, 1661954, 2097152, 2434718, 2710530, 2943725,
|
||||
3145728, 3323907, 3483294, 3627477, 3759106, 3880192, 3992301,
|
||||
4096672, 4194304, 4286015, 4372483, 4454275, 4531870, 4605679,
|
||||
4676053, 4743299, 4807682, 4869436, 4928768, 4985861, 5040877,
|
||||
5093962, 5145248, 5194851, 5242880, 5289431, 5334591, 5378443,
|
||||
5421059, 5462508, 5502851, 5542146, 5580446, 5617800, 5654255,
|
||||
5689851, 5724629, 5758625, 5791875, 5824409, 5856258, 5887450,
|
||||
5918012, 5947969, 5977344, 6006160, 6034437, 6062195, 6089453,
|
||||
6116228, 6142538, 6168398, 6193824, 6218829, 6243427, 6267632,
|
||||
6291456, 6314910, 6338007, 6360756, 6383167, 6405252, 6427019,
|
||||
6448477, 6469635, 6490501, 6511084, 6531390, 6551427, 6571202,
|
||||
6590722, 6609993, 6629022, 6647815, 6666376, 6684713, 6702831,
|
||||
6720734, 6738427, 6755916, 6773205, 6790299, 6807201, 6823917,
|
||||
6840451, 6856805, 6872985, 6888993, 6904834, 6920510, 6936026,
|
||||
6951384, 6966588, 6981641, 6996545, 7011304, 7025920, 7040397,
|
||||
7054736, 7068940, 7083013, 7096956, 7110771, 7124461, 7138029,
|
||||
7151476, 7164804, 7178017, 7191114, 7204100, 7216974, 7229740,
|
||||
7242400, 7254954, 7267405, 7279754, 7292003, 7304154, 7316208,
|
||||
7328167, 7340032, 7351805, 7363486, 7375079, 7386583, 7398000,
|
||||
7409332, 7420579, 7431743, 7442826, 7453828, 7464751, 7475595,
|
||||
7486362, 7497053, 7507669, 7518211, 7528680, 7539077, 7549404,
|
||||
7559660, 7569847, 7579966, 7590017, 7600003, 7609923, 7619778,
|
||||
7629569, 7639298, 7648964, 7658569, 7668114, 7677598, 7687023,
|
||||
7696391, 7705700, 7714952, 7724149, 7733289, 7742375, 7751407,
|
||||
7760385, 7769310, 7778182, 7787003, 7795773, 7804492, 7813161,
|
||||
7821781, 7830352, 7838875, 7847350, 7855777, 7864158, 7872493,
|
||||
7880782, 7889027, 7897226, 7905381, 7913492, 7921561, 7929586,
|
||||
7937569, 7945510, 7953410, 7961268, 7969086, 7976864, 7984602,
|
||||
7992301, 7999960, 8007581, 8015164, 8022709, 8030217, 8037687,
|
||||
8045121, 8052519, 8059880, 8067206, 8074496, 8081752, 8088973,
|
||||
8096159, 8103312, 8110431, 8117516, 8124569, 8131589, 8138576,
|
||||
8145532, 8152455, 8159347, 8166208, 8173037, 8179836, 8186605,
|
||||
8193343, 8200052, 8206731, 8213380, 8220001, 8226593, 8233156,
|
||||
8239690, 8246197, 8252676, 8259127, 8265550, 8271947, 8278316,
|
||||
8284659, 8290976, 8297266, 8303530, 8309768, 8315981, 8322168,
|
||||
8328330, 8334467, 8340579, 8346667, 8352730, 8358769, 8364784,
|
||||
8370775, 8376743, 8382687, 8388608, 8394506, 8400381, 8406233,
|
||||
8412062, 8417870, 8423655, 8429418, 8435159, 8440878, 8446576,
|
||||
8452252, 8457908, 8463542, 8469155, 8474748, 8480319, 8485871,
|
||||
8491402, 8496913, 8502404, 8507875, 8513327, 8518759, 8524171,
|
||||
8529564, 8534938, 8540293, 8545629, 8550947, 8556245, 8561525,
|
||||
8566787, 8572031, 8577256, 8582464, 8587653, 8592825, 8597980,
|
||||
8603116, 8608236, 8613338, 8618423, 8623491, 8628542, 8633576,
|
||||
8638593, 8643594, 8648579, 8653547, 8658499, 8663434, 8668354,
|
||||
8673258, 8678145, 8683017, 8687874, 8692715, 8697540, 8702350,
|
||||
8707145, 8711925, 8716690, 8721439, 8726174, 8730894, 8735599,
|
||||
8740290, 8744967, 8749628, 8754276, 8758909, 8763528, 8768134,
|
||||
8772725, 8777302, 8781865, 8786415, 8790951, 8795474, 8799983,
|
||||
8804478, 8808961, 8813430, 8817886, 8822328, 8826758, 8831175,
|
||||
8835579, 8839970, 8844349, 8848715, 8853068, 8857409, 8861737,
|
||||
8866053, 8870357, 8874649, 8878928, 8883195, 8887451, 8891694,
|
||||
8895926, 8900145, 8904353, 8908550, 8912734, 8916908, 8921069,
|
||||
8925220, 8929358, 8933486, 8937603, 8941708, 8945802, 8949885,
|
||||
8953957, 8958018, 8962068, 8966108, 8970137, 8974155, 8978162,
|
||||
8982159, 8986145, 8990121, 8994086, 8998041, 9001986, 9005920,
|
||||
9009844, 9013758, 9017662, 9021556, 9025440, 9029314, 9033178,
|
||||
9037032, 9040877, 9044711, 9048536, 9052352, 9056157, 9059953,
|
||||
9063740, 9067517, 9071285, 9075044, 9078793, 9082533, 9086263,
|
||||
9089985, 9093697, 9097400, 9101095, 9104780, 9108456, 9112123,
|
||||
9115782, 9119431, 9123072, 9126704, 9130328, 9133943, 9137549,
|
||||
9141146, 9144735, 9148316, 9151888, 9155452, 9159007, 9162554,
|
||||
9166092, 9169623, 9173145, 9176659, 9180165, 9183663, 9187152,
|
||||
9190634, 9194108, 9197573, 9201031, 9204481, 9207923, 9211357,
|
||||
9214784, 9218202, 9221613, 9225017, 9228412, 9231800, 9235181,
|
||||
9238554, 9241919, 9245277, 9248628, 9251971, 9255307, 9258635,
|
||||
9261956, 9265270, 9268577, 9271876, 9275169, 9278454, 9281732,
|
||||
9285002, 9288266, 9291523, 9294773, 9298016, 9301252, 9304481,
|
||||
9307703, 9310918, 9314126, 9317328, 9320523, 9323711, 9326892,
|
||||
9330067, 9333235, 9336397, 9339552, 9342700, 9345842, 9348977,
|
||||
9352106, 9355228, 9358344, 9361454, 9364557, 9367654, 9370744,
|
||||
9373828, 9376906, 9379978, 9383043, 9386102, 9389155, 9392202,
|
||||
9395243, 9398278, 9401306, 9404329, 9407345, 9410356, 9413360,
|
||||
9416359, 9419351, 9422338, 9425319, 9428294, 9431263, 9434226,
|
||||
9437184, 9440136, 9443082, 9446022, 9448957, 9451886, 9454809,
|
||||
9457726, 9460638, 9463545, 9466446, 9469341, 9472231, 9475115,
|
||||
9477994, 9480867, 9483735, 9486597, 9489454, 9492306, 9495152,
|
||||
9497993, 9500828, 9503659, 9506484, 9509303, 9512118, 9514927,
|
||||
9517731, 9520530, 9523324, 9526112, 9528895, 9531674, 9534447,
|
||||
9537215, 9539978, 9542736, 9545489, 9548237, 9550980, 9553718,
|
||||
9556451, 9559179, 9561903, 9564621, 9567335, 9570043, 9572747,
|
||||
9575446, 9578140, 9580830, 9583514, 9586194, 9588869, 9591540,
|
||||
9594205, 9596866, 9599523, 9602174, 9604821, 9607464, 9610101,
|
||||
9612735, 9615363, 9617987, 9620607, 9623222, 9625832, 9628438,
|
||||
9631040, 9633637, 9636229, 9638818, 9641401, 9643981, 9646556,
|
||||
9649126, 9651692, 9654254, 9656812, 9659365, 9661914, 9664459,
|
||||
9666999, 9669535, 9672067, 9674594, 9677118, 9679637, 9682152,
|
||||
9684663, 9687169, 9689672, 9692170, 9694665, 9697155, 9699641,
|
||||
9702123, 9704601, 9707075, 9709545, 9712010, 9714472, 9716930,
|
||||
9719384, 9721834, 9724279, 9726721, 9729159, 9731593, 9734024,
|
||||
9736450, 9738872, 9741291, 9743705, 9746116, 9748523, 9750926,
|
||||
9753326, 9755721, 9758113, 9760501, 9762885, 9765266, 9767642,
|
||||
9770015, 9772385, 9774750, 9777112, 9779470, 9781825, 9784175,
|
||||
9786523, 9788866, 9791206, 9793543, 9795875, 9798204, 9800530,
|
||||
9802852, 9805170, 9807485, 9809797, 9812104, 9814409, 9816710,
|
||||
9819007, 9821301, 9823591, 9825878, 9828161, 9830441, 9832718,
|
||||
9834991, 9837261, 9839527, 9841790, 9844050, 9846306, 9848559,
|
||||
9850808, 9853054, 9855297, 9857537, 9859773, 9862006, 9864235,
|
||||
9866462, 9868685, 9870904, 9873121, 9875334, 9877544, 9879751,
|
||||
9881955, 9884155, 9886352, 9888546, 9890737, 9892925, 9895109,
|
||||
9897291, 9899469, 9901644, 9903816, 9905985, 9908150, 9910313,
|
||||
9912473, 9914629, 9916783, 9918933, 9921080, 9923225, 9925366,
|
||||
9927504, 9929639, 9931771, 9933900, 9936027, 9938150, 9940270,
|
||||
9942387, 9944502, 9946613, 9948721, 9950827, 9952929, 9955029,
|
||||
9957126, 9959219, 9961310, 9963398, 9965484, 9967566, 9969645,
|
||||
9971722, 9973796, 9975866, 9977934, 9980000, 9982062, 9984122,
|
||||
9986179, 9988233, 9990284, 9992332, 9994378, 9996421, 9998461,
|
||||
10000498, 10002533, 10004565, 10006594, 10008621, 10010644, 10012665,
|
||||
10014684, 10016700, 10018713, 10020723, 10022731, 10024736, 10026738,
|
||||
10028738, 10030735, 10032729, 10034721, 10036710, 10038697, 10040681,
|
||||
10042662, 10044641, 10046617, 10048591, 10050562, 10052530, 10054496,
|
||||
10056459, 10058420, 10060379, 10062334, 10064287, 10066238, 10068186,
|
||||
10070132, 10072075, 10074016, 10075954, 10077890, 10079823, 10081754,
|
||||
10083682, 10085608, 10087532, 10089453, 10091371, 10093287, 10095201,
|
||||
10097112, 10099021, 10100928, 10102832, 10104733, 10106633, 10108529,
|
||||
10110424, 10112316, 10114206, 10116093, 10117978, 10119861, 10121742,
|
||||
10123620, 10125495, 10127369, 10129240, 10131109, 10132975, 10134839,
|
||||
10136701, 10138561, 10140418, 10142273, 10144126, 10145976, 10147825,
|
||||
10149671, 10151514, 10153356, 10155195, 10157032, 10158867, 10160699,
|
||||
10162530, 10164358, 10166184, 10168007, 10169829, 10171648, 10173465,
|
||||
10175280, 10177093, 10178904, 10180712, 10182519, 10184323, 10186125,
|
||||
10187925, 10189722, 10191518, 10193311, 10195103, 10196892, 10198679,
|
||||
10200464, 10202247, 10204028, 10205806, 10207583, 10209357, 10211130,
|
||||
10212900, 10214668, 10216435, 10218199, 10219961, 10221721, 10223479,
|
||||
10225235, 10226989, 10228741, 10230491, 10232239, 10233985, 10235728,
|
||||
10237470, 10239210, 10240948, 10242684, 10244417, 10246149, 10247879,
|
||||
10249607, 10251333, 10253057, 10254779, 10256499, 10258217, 10259933,
|
||||
10261647, 10263360, 10265070, 10266778, 10268485, 10270189, 10271892,
|
||||
10273593, 10275292, 10276988, 10278683, 10280376, 10282068, 10283757,
|
||||
10285444, 10287130, 10288814, 10290495, 10292175, 10293853, 10295530,
|
||||
10297204, 10298876, 10300547, 10302216, 10303883, 10305548, 10307211,
|
||||
10308873, 10310532, 10312190, 10313846, 10315501, 10317153, 10318804,
|
||||
10320452, 10322099, 10323745, 10325388, 10327030, 10328670, 10330308,
|
||||
10331944, 10333578, 10335211, 10336842, 10338472, 10340099, 10341725,
|
||||
10343349, 10344971, 10346592, 10348210, 10349828, 10351443, 10353057,
|
||||
10354668, 10356279, 10357887, 10359494, 10361099, 10362702, 10364304,
|
||||
10365904, 10367502, 10369099, 10370694, 10372287, 10373879, 10375468,
|
||||
10377057, 10378643, 10380228, 10381811, 10383393, 10384973, 10386551,
|
||||
10388128, 10389703, 10391276, 10392848, 10394418, 10395986, 10397553,
|
||||
10399118, 10400682, 10402244, 10403804, 10405363, 10406920, 10408476,
|
||||
10410030, 10411582, 10413133, 10414682, 10416230, 10417776, 10419320,
|
||||
10420863, 10422404, 10423944, 10425482, 10427019, 10428554, 10430087,
|
||||
10431619, 10433149, 10434678, 10436206, 10437731, 10439256, 10440778,
|
||||
10442299, 10443819, 10445337, 10446854, 10448369, 10449882, 10451394,
|
||||
10452905, 10454414, 10455921, 10457427, 10458932, 10460435, 10461936,
|
||||
10463436, 10464935, 10466432, 10467927, 10469422, 10470914, 10472405,
|
||||
10473895, 10475383, 10476870, 10478355, 10479839, 10481322, 10482802,
|
||||
10484282,
|
||||
};
|
||||
|
||||
static int mi_size_to_block_size(int mi_bsize, int mi_num) {
|
||||
return (mi_num % mi_bsize) ? mi_num / mi_bsize + 1 : mi_num / mi_bsize;
|
||||
}
|
||||
|
||||
Status vp9_alloc_motion_field_info(MotionFieldInfo *motion_field_info,
|
||||
int frame_num, int mi_rows, int mi_cols) {
|
||||
int frame_idx, rf_idx, square_block_idx;
|
||||
if (motion_field_info->allocated) {
|
||||
// TODO(angiebird): Avoid re-allocate buffer if possible
|
||||
vp9_free_motion_field_info(motion_field_info);
|
||||
}
|
||||
motion_field_info->frame_num = frame_num;
|
||||
motion_field_info->motion_field_array =
|
||||
vpx_calloc(frame_num, sizeof(*motion_field_info->motion_field_array));
|
||||
for (frame_idx = 0; frame_idx < frame_num; ++frame_idx) {
|
||||
for (rf_idx = 0; rf_idx < MAX_INTER_REF_FRAMES; ++rf_idx) {
|
||||
for (square_block_idx = 0; square_block_idx < SQUARE_BLOCK_SIZES;
|
||||
++square_block_idx) {
|
||||
BLOCK_SIZE bsize = square_block_idx_to_bsize(square_block_idx);
|
||||
const int mi_height = num_8x8_blocks_high_lookup[bsize];
|
||||
const int mi_width = num_8x8_blocks_wide_lookup[bsize];
|
||||
const int block_rows = mi_size_to_block_size(mi_height, mi_rows);
|
||||
const int block_cols = mi_size_to_block_size(mi_width, mi_cols);
|
||||
MotionField *motion_field =
|
||||
&motion_field_info
|
||||
->motion_field_array[frame_idx][rf_idx][square_block_idx];
|
||||
Status status =
|
||||
vp9_alloc_motion_field(motion_field, bsize, block_rows, block_cols);
|
||||
if (status == STATUS_FAILED) {
|
||||
return STATUS_FAILED;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
motion_field_info->allocated = 1;
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
Status vp9_alloc_motion_field(MotionField *motion_field, BLOCK_SIZE bsize,
|
||||
int block_rows, int block_cols) {
|
||||
Status status = STATUS_OK;
|
||||
motion_field->ready = 0;
|
||||
motion_field->bsize = bsize;
|
||||
motion_field->block_rows = block_rows;
|
||||
motion_field->block_cols = block_cols;
|
||||
motion_field->block_num = block_rows * block_cols;
|
||||
motion_field->mf =
|
||||
vpx_calloc(motion_field->block_num, sizeof(*motion_field->mf));
|
||||
if (motion_field->mf == NULL) {
|
||||
status = STATUS_FAILED;
|
||||
}
|
||||
motion_field->set_mv =
|
||||
vpx_calloc(motion_field->block_num, sizeof(*motion_field->set_mv));
|
||||
if (motion_field->set_mv == NULL) {
|
||||
vpx_free(motion_field->mf);
|
||||
motion_field->mf = NULL;
|
||||
status = STATUS_FAILED;
|
||||
}
|
||||
motion_field->local_structure = vpx_calloc(
|
||||
motion_field->block_num, sizeof(*motion_field->local_structure));
|
||||
if (motion_field->local_structure == NULL) {
|
||||
vpx_free(motion_field->mf);
|
||||
motion_field->mf = NULL;
|
||||
vpx_free(motion_field->set_mv);
|
||||
motion_field->set_mv = NULL;
|
||||
status = STATUS_FAILED;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
void vp9_free_motion_field(MotionField *motion_field) {
|
||||
vpx_free(motion_field->mf);
|
||||
vpx_free(motion_field->set_mv);
|
||||
vpx_free(motion_field->local_structure);
|
||||
vp9_zero(*motion_field);
|
||||
}
|
||||
|
||||
void vp9_free_motion_field_info(MotionFieldInfo *motion_field_info) {
|
||||
if (motion_field_info->allocated) {
|
||||
int frame_idx, rf_idx, square_block_idx;
|
||||
for (frame_idx = 0; frame_idx < motion_field_info->frame_num; ++frame_idx) {
|
||||
for (rf_idx = 0; rf_idx < MAX_INTER_REF_FRAMES; ++rf_idx) {
|
||||
for (square_block_idx = 0; square_block_idx < SQUARE_BLOCK_SIZES;
|
||||
++square_block_idx) {
|
||||
MotionField *motion_field =
|
||||
&motion_field_info
|
||||
->motion_field_array[frame_idx][rf_idx][square_block_idx];
|
||||
vp9_free_motion_field(motion_field);
|
||||
}
|
||||
}
|
||||
}
|
||||
vpx_free(motion_field_info->motion_field_array);
|
||||
motion_field_info->motion_field_array = NULL;
|
||||
motion_field_info->frame_num = 0;
|
||||
motion_field_info->allocated = 0;
|
||||
}
|
||||
}
|
||||
|
||||
MotionField *vp9_motion_field_info_get_motion_field(
|
||||
MotionFieldInfo *motion_field_info, int frame_idx, int rf_idx,
|
||||
BLOCK_SIZE bsize) {
|
||||
int square_block_idx = get_square_block_idx(bsize);
|
||||
assert(frame_idx < motion_field_info->frame_num);
|
||||
assert(motion_field_info->allocated == 1);
|
||||
return &motion_field_info
|
||||
->motion_field_array[frame_idx][rf_idx][square_block_idx];
|
||||
}
|
||||
|
||||
int vp9_motion_field_is_mv_set(const MotionField *motion_field, int brow,
|
||||
int bcol) {
|
||||
assert(brow >= 0 && brow < motion_field->block_rows);
|
||||
assert(bcol >= 0 && bcol < motion_field->block_cols);
|
||||
return motion_field->set_mv[brow * motion_field->block_cols + bcol];
|
||||
}
|
||||
|
||||
int_mv vp9_motion_field_get_mv(const MotionField *motion_field, int brow,
|
||||
int bcol) {
|
||||
assert(brow >= 0 && brow < motion_field->block_rows);
|
||||
assert(bcol >= 0 && bcol < motion_field->block_cols);
|
||||
return motion_field->mf[brow * motion_field->block_cols + bcol];
|
||||
}
|
||||
|
||||
int_mv vp9_motion_field_mi_get_mv(const MotionField *motion_field, int mi_row,
|
||||
int mi_col) {
|
||||
const int mi_height = num_8x8_blocks_high_lookup[motion_field->bsize];
|
||||
const int mi_width = num_8x8_blocks_wide_lookup[motion_field->bsize];
|
||||
const int brow = mi_row / mi_height;
|
||||
const int bcol = mi_col / mi_width;
|
||||
assert(mi_row % mi_height == 0);
|
||||
assert(mi_col % mi_width == 0);
|
||||
return vp9_motion_field_get_mv(motion_field, brow, bcol);
|
||||
}
|
||||
|
||||
void vp9_motion_field_mi_set_mv(MotionField *motion_field, int mi_row,
|
||||
int mi_col, int_mv mv) {
|
||||
const int mi_height = num_8x8_blocks_high_lookup[motion_field->bsize];
|
||||
const int mi_width = num_8x8_blocks_wide_lookup[motion_field->bsize];
|
||||
const int brow = mi_row / mi_height;
|
||||
const int bcol = mi_col / mi_width;
|
||||
assert(mi_row % mi_height == 0);
|
||||
assert(mi_col % mi_width == 0);
|
||||
assert(brow >= 0 && brow < motion_field->block_rows);
|
||||
assert(bcol >= 0 && bcol < motion_field->block_cols);
|
||||
motion_field->mf[brow * motion_field->block_cols + bcol] = mv;
|
||||
motion_field->set_mv[brow * motion_field->block_cols + bcol] = 1;
|
||||
}
|
||||
|
||||
void vp9_motion_field_reset_mvs(MotionField *motion_field) {
|
||||
memset(motion_field->set_mv, 0,
|
||||
motion_field->block_num * sizeof(*motion_field->set_mv));
|
||||
}
|
||||
|
||||
static int64_t log2_approximation(int64_t v) {
|
||||
assert(v > 0);
|
||||
if (v < LOG2_TABLE_SIZE) {
|
||||
return log2_table[v];
|
||||
} else {
|
||||
// use linear approximation when v >= 2^10
|
||||
const int slope =
|
||||
1477; // slope = 1 / (log(2) * 1024) * (1 << LOG2_PRECISION)
|
||||
assert(LOG2_TABLE_SIZE == 1 << 10);
|
||||
|
||||
return slope * (v - LOG2_TABLE_SIZE) + (10 << LOG2_PRECISION);
|
||||
}
|
||||
}
|
||||
|
||||
int64_t vp9_nb_mvs_inconsistency(const MV *mv, const int_mv *nb_full_mvs,
|
||||
int mv_num) {
|
||||
// The behavior of this function is to compute log2 of mv difference,
|
||||
// i.e. min log2(1 + row_diff * row_diff + col_diff * col_diff)
|
||||
// against available neighbor mvs.
|
||||
// Since the log2 is monotonically increasing, we can compute
|
||||
// min row_diff * row_diff + col_diff * col_diff first
|
||||
// then apply log2 in the end.
|
||||
int i;
|
||||
int64_t min_abs_diff = INT64_MAX;
|
||||
int cnt = 0;
|
||||
assert(mv_num <= NB_MVS_NUM);
|
||||
for (i = 0; i < mv_num; ++i) {
|
||||
MV nb_mv = nb_full_mvs[i].as_mv;
|
||||
const int64_t row_diff = abs(mv->row - nb_mv.row);
|
||||
const int64_t col_diff = abs(mv->col - nb_mv.col);
|
||||
const int64_t abs_diff = row_diff * row_diff + col_diff * col_diff;
|
||||
assert(nb_full_mvs[i].as_int != INVALID_MV);
|
||||
min_abs_diff = VPXMIN(abs_diff, min_abs_diff);
|
||||
++cnt;
|
||||
}
|
||||
if (cnt) {
|
||||
return log2_approximation(1 + min_abs_diff);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static FloatMV get_smooth_motion_vector(const FloatMV scaled_search_mv,
|
||||
const FloatMV *tmp_mf,
|
||||
const int (*M)[MF_LOCAL_STRUCTURE_SIZE],
|
||||
int rows, int cols, int row, int col,
|
||||
float alpha) {
|
||||
const FloatMV tmp_mv = tmp_mf[row * cols + col];
|
||||
int idx_row, idx_col;
|
||||
FloatMV avg_nb_mv = { 0.0f, 0.0f };
|
||||
FloatMV mv = { 0.0f, 0.0f };
|
||||
float filter[3][3] = { { 1.0f / 12.0f, 1.0f / 6.0f, 1.0f / 12.0f },
|
||||
{ 1.0f / 6.0f, 0.0f, 1.0f / 6.0f },
|
||||
{ 1.0f / 12.0f, 1.0f / 6.0f, 1.0f / 12.0f } };
|
||||
for (idx_row = 0; idx_row < 3; ++idx_row) {
|
||||
int nb_row = row + idx_row - 1;
|
||||
for (idx_col = 0; idx_col < 3; ++idx_col) {
|
||||
int nb_col = col + idx_col - 1;
|
||||
if (nb_row < 0 || nb_col < 0 || nb_row >= rows || nb_col >= cols) {
|
||||
avg_nb_mv.row += (tmp_mv.row) * filter[idx_row][idx_col];
|
||||
avg_nb_mv.col += (tmp_mv.col) * filter[idx_row][idx_col];
|
||||
} else {
|
||||
const FloatMV nb_mv = tmp_mf[nb_row * cols + nb_col];
|
||||
avg_nb_mv.row += (nb_mv.row) * filter[idx_row][idx_col];
|
||||
avg_nb_mv.col += (nb_mv.col) * filter[idx_row][idx_col];
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
// M is the local variance of reference frame
|
||||
float M00 = M[row * cols + col][0];
|
||||
float M01 = M[row * cols + col][1];
|
||||
float M10 = M[row * cols + col][2];
|
||||
float M11 = M[row * cols + col][3];
|
||||
|
||||
float det = (M00 + alpha) * (M11 + alpha) - M01 * M10;
|
||||
|
||||
float inv_M00 = (M11 + alpha) / det;
|
||||
float inv_M01 = -M01 / det;
|
||||
float inv_M10 = -M10 / det;
|
||||
float inv_M11 = (M00 + alpha) / det;
|
||||
|
||||
float inv_MM00 = inv_M00 * M00 + inv_M01 * M10;
|
||||
float inv_MM01 = inv_M00 * M01 + inv_M01 * M11;
|
||||
float inv_MM10 = inv_M10 * M00 + inv_M11 * M10;
|
||||
float inv_MM11 = inv_M10 * M01 + inv_M11 * M11;
|
||||
|
||||
mv.row = inv_M00 * avg_nb_mv.row * alpha + inv_M01 * avg_nb_mv.col * alpha +
|
||||
inv_MM00 * scaled_search_mv.row + inv_MM01 * scaled_search_mv.col;
|
||||
mv.col = inv_M10 * avg_nb_mv.row * alpha + inv_M11 * avg_nb_mv.col * alpha +
|
||||
inv_MM10 * scaled_search_mv.row + inv_MM11 * scaled_search_mv.col;
|
||||
}
|
||||
return mv;
|
||||
}
|
||||
|
||||
void vp9_get_smooth_motion_field(const MV *search_mf,
|
||||
const int (*M)[MF_LOCAL_STRUCTURE_SIZE],
|
||||
int rows, int cols, BLOCK_SIZE bsize,
|
||||
float alpha, int num_iters, MV *smooth_mf) {
|
||||
// M is the local variation of reference frame
|
||||
// build two buffers
|
||||
FloatMV *input = (FloatMV *)malloc(rows * cols * sizeof(FloatMV));
|
||||
FloatMV *output = (FloatMV *)malloc(rows * cols * sizeof(FloatMV));
|
||||
int idx;
|
||||
int row, col;
|
||||
int bw = 4 << b_width_log2_lookup[bsize];
|
||||
int bh = 4 << b_height_log2_lookup[bsize];
|
||||
// copy search results to input buffer
|
||||
for (idx = 0; idx < rows * cols; ++idx) {
|
||||
input[idx].row = (float)search_mf[idx].row / bh;
|
||||
input[idx].col = (float)search_mf[idx].col / bw;
|
||||
}
|
||||
for (idx = 0; idx < num_iters; ++idx) {
|
||||
FloatMV *tmp;
|
||||
for (row = 0; row < rows; ++row) {
|
||||
for (col = 0; col < cols; ++col) {
|
||||
// note: the scaled_search_mf and smooth_mf are all scaled by macroblock
|
||||
// size
|
||||
const MV search_mv = search_mf[row * cols + col];
|
||||
FloatMV scaled_search_mv = { (float)search_mv.row / bh,
|
||||
(float)search_mv.col / bw };
|
||||
output[row * cols + col] = get_smooth_motion_vector(
|
||||
scaled_search_mv, input, M, rows, cols, row, col, alpha);
|
||||
}
|
||||
}
|
||||
// swap buffers
|
||||
tmp = input;
|
||||
input = output;
|
||||
output = tmp;
|
||||
}
|
||||
// copy smoothed results to output
|
||||
for (idx = 0; idx < rows * cols; ++idx) {
|
||||
smooth_mf[idx].row = (int)(input[idx].row * bh);
|
||||
smooth_mf[idx].col = (int)(input[idx].col * bw);
|
||||
}
|
||||
free(input);
|
||||
free(output);
|
||||
}
|
||||
|
||||
void vp9_get_local_structure(const YV12_BUFFER_CONFIG *cur_frame,
|
||||
const YV12_BUFFER_CONFIG *ref_frame,
|
||||
const MV *search_mf,
|
||||
const vp9_variance_fn_ptr_t *fn_ptr, int rows,
|
||||
int cols, BLOCK_SIZE bsize,
|
||||
int (*M)[MF_LOCAL_STRUCTURE_SIZE]) {
|
||||
const int bw = 4 << b_width_log2_lookup[bsize];
|
||||
const int bh = 4 << b_height_log2_lookup[bsize];
|
||||
const int cur_stride = cur_frame->y_stride;
|
||||
const int ref_stride = ref_frame->y_stride;
|
||||
const int width = ref_frame->y_width;
|
||||
const int height = ref_frame->y_height;
|
||||
int row, col;
|
||||
for (row = 0; row < rows; ++row) {
|
||||
for (col = 0; col < cols; ++col) {
|
||||
int cur_offset = row * bh * cur_stride + col * bw;
|
||||
uint8_t *center = cur_frame->y_buffer + cur_offset;
|
||||
int ref_h = row * bh + search_mf[row * cols + col].row;
|
||||
int ref_w = col * bw + search_mf[row * cols + col].col;
|
||||
int ref_offset;
|
||||
uint8_t *target;
|
||||
uint8_t *nb;
|
||||
int search_dist;
|
||||
int nb_dist;
|
||||
int I_row = 0, I_col = 0;
|
||||
// TODO(Dan): handle the case that when reference frame block beyond the
|
||||
// boundary
|
||||
ref_h = ref_h < 0 ? 0 : (ref_h >= height - bh ? height - bh - 1 : ref_h);
|
||||
ref_w = ref_w < 0 ? 0 : (ref_w >= width - bw ? width - bw - 1 : ref_w);
|
||||
// compute search results distortion
|
||||
// TODO(Dan): maybe need to use vp9 function to find the reference block,
|
||||
// to compare with the results of my python code, I first use my way to
|
||||
// compute the reference block
|
||||
ref_offset = ref_h * ref_stride + ref_w;
|
||||
target = ref_frame->y_buffer + ref_offset;
|
||||
search_dist = fn_ptr->sdf(center, cur_stride, target, ref_stride);
|
||||
// compute target's neighbors' distortions
|
||||
// TODO(Dan): if using padding, the boundary condition may vary
|
||||
// up
|
||||
if (ref_h - bh >= 0) {
|
||||
nb = target - ref_stride * bh;
|
||||
nb_dist = fn_ptr->sdf(center, cur_stride, nb, ref_stride);
|
||||
I_row += nb_dist - search_dist;
|
||||
}
|
||||
// down
|
||||
if (ref_h + bh < height - bh) {
|
||||
nb = target + ref_stride * bh;
|
||||
nb_dist = fn_ptr->sdf(center, cur_stride, nb, ref_stride);
|
||||
I_row += nb_dist - search_dist;
|
||||
}
|
||||
if (ref_h - bh >= 0 && ref_h + bh < height - bh) {
|
||||
I_row /= 2;
|
||||
}
|
||||
I_row /= (bw * bh);
|
||||
// left
|
||||
if (ref_w - bw >= 0) {
|
||||
nb = target - bw;
|
||||
nb_dist = fn_ptr->sdf(center, cur_stride, nb, ref_stride);
|
||||
I_col += nb_dist - search_dist;
|
||||
}
|
||||
// down
|
||||
if (ref_w + bw < width - bw) {
|
||||
nb = target + bw;
|
||||
nb_dist = fn_ptr->sdf(center, cur_stride, nb, ref_stride);
|
||||
I_col += nb_dist - search_dist;
|
||||
}
|
||||
if (ref_w - bw >= 0 && ref_w + bw < width - bw) {
|
||||
I_col /= 2;
|
||||
}
|
||||
I_col /= (bw * bh);
|
||||
M[row * cols + col][0] = I_row * I_row;
|
||||
M[row * cols + col][1] = I_row * I_col;
|
||||
M[row * cols + col][2] = I_col * I_row;
|
||||
M[row * cols + col][3] = I_col * I_col;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (c) 2019 The WebM project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can 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_NON_GREEDY_MV_H_
|
||||
#define VPX_VP9_ENCODER_VP9_NON_GREEDY_MV_H_
|
||||
|
||||
#include "vp9/common/vp9_enums.h"
|
||||
#include "vp9/common/vp9_blockd.h"
|
||||
#include "vpx_scale/yv12config.h"
|
||||
#include "vpx_dsp/variance.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#define NB_MVS_NUM 4
|
||||
#define LOG2_PRECISION 20
|
||||
#define MF_LOCAL_STRUCTURE_SIZE 4
|
||||
#define SQUARE_BLOCK_SIZES 4
|
||||
|
||||
typedef enum Status { STATUS_OK = 0, STATUS_FAILED = 1 } Status;
|
||||
|
||||
typedef struct MotionField {
|
||||
int ready;
|
||||
BLOCK_SIZE bsize;
|
||||
int block_rows;
|
||||
int block_cols;
|
||||
int block_num; // block_num == block_rows * block_cols
|
||||
int (*local_structure)[MF_LOCAL_STRUCTURE_SIZE];
|
||||
int_mv *mf;
|
||||
int *set_mv;
|
||||
int mv_log_scale;
|
||||
} MotionField;
|
||||
|
||||
typedef struct MotionFieldInfo {
|
||||
int frame_num;
|
||||
int allocated;
|
||||
MotionField (*motion_field_array)[MAX_INTER_REF_FRAMES][SQUARE_BLOCK_SIZES];
|
||||
} MotionFieldInfo;
|
||||
|
||||
typedef struct {
|
||||
float row, col;
|
||||
} FloatMV;
|
||||
|
||||
static INLINE int get_square_block_idx(BLOCK_SIZE bsize) {
|
||||
if (bsize == BLOCK_4X4) {
|
||||
return 0;
|
||||
}
|
||||
if (bsize == BLOCK_8X8) {
|
||||
return 1;
|
||||
}
|
||||
if (bsize == BLOCK_16X16) {
|
||||
return 2;
|
||||
}
|
||||
if (bsize == BLOCK_32X32) {
|
||||
return 3;
|
||||
}
|
||||
assert(0 && "ERROR: non-square block size");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static INLINE BLOCK_SIZE square_block_idx_to_bsize(int square_block_idx) {
|
||||
if (square_block_idx == 0) {
|
||||
return BLOCK_4X4;
|
||||
}
|
||||
if (square_block_idx == 1) {
|
||||
return BLOCK_8X8;
|
||||
}
|
||||
if (square_block_idx == 2) {
|
||||
return BLOCK_16X16;
|
||||
}
|
||||
if (square_block_idx == 3) {
|
||||
return BLOCK_32X32;
|
||||
}
|
||||
assert(0 && "ERROR: invalid square_block_idx");
|
||||
return BLOCK_INVALID;
|
||||
}
|
||||
|
||||
Status vp9_alloc_motion_field_info(MotionFieldInfo *motion_field_info,
|
||||
int frame_num, int mi_rows, int mi_cols);
|
||||
|
||||
Status vp9_alloc_motion_field(MotionField *motion_field, BLOCK_SIZE bsize,
|
||||
int block_rows, int block_cols);
|
||||
|
||||
void vp9_free_motion_field(MotionField *motion_field);
|
||||
|
||||
void vp9_free_motion_field_info(MotionFieldInfo *motion_field_info);
|
||||
|
||||
int64_t vp9_nb_mvs_inconsistency(const MV *mv, const int_mv *nb_full_mvs,
|
||||
int mv_num);
|
||||
|
||||
void vp9_get_smooth_motion_field(const MV *search_mf,
|
||||
const int (*M)[MF_LOCAL_STRUCTURE_SIZE],
|
||||
int rows, int cols, BLOCK_SIZE bize,
|
||||
float alpha, int num_iters, MV *smooth_mf);
|
||||
|
||||
void vp9_get_local_structure(const YV12_BUFFER_CONFIG *cur_frame,
|
||||
const YV12_BUFFER_CONFIG *ref_frame,
|
||||
const MV *search_mf,
|
||||
const vp9_variance_fn_ptr_t *fn_ptr, int rows,
|
||||
int cols, BLOCK_SIZE bsize,
|
||||
int (*M)[MF_LOCAL_STRUCTURE_SIZE]);
|
||||
|
||||
MotionField *vp9_motion_field_info_get_motion_field(
|
||||
MotionFieldInfo *motion_field_info, int frame_idx, int rf_idx,
|
||||
BLOCK_SIZE bsize);
|
||||
|
||||
void vp9_motion_field_mi_set_mv(MotionField *motion_field, int mi_row,
|
||||
int mi_col, int_mv mv);
|
||||
|
||||
void vp9_motion_field_reset_mvs(MotionField *motion_field);
|
||||
|
||||
int_mv vp9_motion_field_get_mv(const MotionField *motion_field, int brow,
|
||||
int bcol);
|
||||
int_mv vp9_motion_field_mi_get_mv(const MotionField *motion_field, int mi_row,
|
||||
int mi_col);
|
||||
int vp9_motion_field_is_mv_set(const MotionField *motion_field, int brow,
|
||||
int bcol);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
#endif // VPX_VP9_ENCODER_VP9_NON_GREEDY_MV_H_
|
||||
@@ -0,0 +1,975 @@
|
||||
/*
|
||||
* 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_ENCODER_VP9_PARTITION_MODELS_H_
|
||||
#define VPX_VP9_ENCODER_VP9_PARTITION_MODELS_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define NN_MAX_HIDDEN_LAYERS 10
|
||||
#define NN_MAX_NODES_PER_LAYER 128
|
||||
|
||||
// Neural net model config. It defines the layout of a neural net model, such as
|
||||
// the number of inputs/outputs, number of layers, the number of nodes in each
|
||||
// layer, as well as the weights and bias of each node.
|
||||
typedef struct {
|
||||
int num_inputs; // Number of input nodes, i.e. features.
|
||||
int num_outputs; // Number of output nodes.
|
||||
int num_hidden_layers; // Number of hidden layers, maximum 10.
|
||||
// Number of nodes for each hidden layer.
|
||||
int num_hidden_nodes[NN_MAX_HIDDEN_LAYERS];
|
||||
// Weight parameters, indexed by layer.
|
||||
const float *weights[NN_MAX_HIDDEN_LAYERS + 1];
|
||||
// Bias parameters, indexed by layer.
|
||||
const float *bias[NN_MAX_HIDDEN_LAYERS + 1];
|
||||
} NN_CONFIG;
|
||||
|
||||
// Partition search breakout model.
|
||||
#define FEATURES 4
|
||||
#define Q_CTX 3
|
||||
#define RESOLUTION_CTX 2
|
||||
static const float
|
||||
vp9_partition_breakout_weights_64[RESOLUTION_CTX][Q_CTX][FEATURES + 1] = {
|
||||
{
|
||||
{
|
||||
-0.016673f,
|
||||
-0.001025f,
|
||||
-0.000032f,
|
||||
0.000833f,
|
||||
1.94261885f - 2.1f,
|
||||
},
|
||||
{
|
||||
-0.160867f,
|
||||
-0.002101f,
|
||||
0.000011f,
|
||||
0.002448f,
|
||||
1.65738142f - 2.5f,
|
||||
},
|
||||
{
|
||||
-0.628934f,
|
||||
-0.011459f,
|
||||
-0.000009f,
|
||||
0.013833f,
|
||||
1.47982645f - 1.6f,
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
-0.064309f,
|
||||
-0.006121f,
|
||||
0.000232f,
|
||||
0.005778f,
|
||||
0.7989465f - 5.0f,
|
||||
},
|
||||
{
|
||||
-0.314957f,
|
||||
-0.009346f,
|
||||
-0.000225f,
|
||||
0.010072f,
|
||||
2.80695581f - 5.5f,
|
||||
},
|
||||
{
|
||||
-0.635535f,
|
||||
-0.015135f,
|
||||
0.000091f,
|
||||
0.015247f,
|
||||
2.90381241f - 5.0f,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static const float
|
||||
vp9_partition_breakout_weights_32[RESOLUTION_CTX][Q_CTX][FEATURES + 1] = {
|
||||
{
|
||||
{
|
||||
-0.010554f,
|
||||
-0.003081f,
|
||||
-0.000134f,
|
||||
0.004491f,
|
||||
1.68445992f - 3.5f,
|
||||
},
|
||||
{
|
||||
-0.051489f,
|
||||
-0.007609f,
|
||||
0.000016f,
|
||||
0.009792f,
|
||||
1.28089404f - 2.5f,
|
||||
},
|
||||
{
|
||||
-0.163097f,
|
||||
-0.013081f,
|
||||
0.000022f,
|
||||
0.019006f,
|
||||
1.36129403f - 3.2f,
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
-0.024629f,
|
||||
-0.006492f,
|
||||
-0.000254f,
|
||||
0.004895f,
|
||||
1.27919173f - 4.5f,
|
||||
},
|
||||
{
|
||||
-0.083936f,
|
||||
-0.009827f,
|
||||
-0.000200f,
|
||||
0.010399f,
|
||||
2.73731065f - 4.5f,
|
||||
},
|
||||
{
|
||||
-0.279052f,
|
||||
-0.013334f,
|
||||
0.000289f,
|
||||
0.023203f,
|
||||
2.43595719f - 3.5f,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static const float
|
||||
vp9_partition_breakout_weights_16[RESOLUTION_CTX][Q_CTX][FEATURES + 1] = {
|
||||
{
|
||||
{
|
||||
-0.013154f,
|
||||
-0.002404f,
|
||||
-0.000977f,
|
||||
0.008450f,
|
||||
2.57404566f - 5.5f,
|
||||
},
|
||||
{
|
||||
-0.019146f,
|
||||
-0.004018f,
|
||||
0.000064f,
|
||||
0.008187f,
|
||||
2.15043926f - 2.5f,
|
||||
},
|
||||
{
|
||||
-0.075755f,
|
||||
-0.010858f,
|
||||
0.000030f,
|
||||
0.024505f,
|
||||
2.06848121f - 2.5f,
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
-0.007636f,
|
||||
-0.002751f,
|
||||
-0.000682f,
|
||||
0.005968f,
|
||||
0.19225763f - 4.5f,
|
||||
},
|
||||
{
|
||||
-0.047306f,
|
||||
-0.009113f,
|
||||
-0.000518f,
|
||||
0.016007f,
|
||||
2.61068869f - 4.0f,
|
||||
},
|
||||
{
|
||||
-0.069336f,
|
||||
-0.010448f,
|
||||
-0.001120f,
|
||||
0.023083f,
|
||||
1.47591054f - 5.5f,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static const float vp9_partition_breakout_weights_8[RESOLUTION_CTX][Q_CTX]
|
||||
[FEATURES + 1] = {
|
||||
{
|
||||
{
|
||||
-0.011807f,
|
||||
-0.009873f,
|
||||
-0.000931f,
|
||||
0.034768f,
|
||||
1.32254851f - 2.0f,
|
||||
},
|
||||
{
|
||||
-0.003861f,
|
||||
-0.002701f,
|
||||
0.000100f,
|
||||
0.013876f,
|
||||
1.96755111f - 1.5f,
|
||||
},
|
||||
{
|
||||
-0.013522f,
|
||||
-0.008677f,
|
||||
-0.000562f,
|
||||
0.034468f,
|
||||
1.53440356f - 1.5f,
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
-0.003221f,
|
||||
-0.002125f,
|
||||
0.000993f,
|
||||
0.012768f,
|
||||
0.03541421f - 2.0f,
|
||||
},
|
||||
{
|
||||
-0.006069f,
|
||||
-0.007335f,
|
||||
0.000229f,
|
||||
0.026104f,
|
||||
0.17135315f - 1.5f,
|
||||
},
|
||||
{
|
||||
-0.039894f,
|
||||
-0.011419f,
|
||||
0.000070f,
|
||||
0.061817f,
|
||||
0.6739977f - 1.5f,
|
||||
},
|
||||
},
|
||||
};
|
||||
#undef FEATURES
|
||||
#undef Q_CTX
|
||||
#undef RESOLUTION_CTX
|
||||
|
||||
// Rectangular partition search pruning model.
|
||||
#define FEATURES 8
|
||||
#define LABELS 4
|
||||
#define NODES 16
|
||||
static const float vp9_rect_part_nn_weights_16_layer0[FEATURES * NODES] = {
|
||||
-0.432522f, 0.133070f, -0.169187f, 0.768340f, 0.891228f, 0.554458f,
|
||||
0.356000f, 0.403621f, 0.809165f, 0.778214f, -0.520357f, 0.301451f,
|
||||
-0.386972f, -0.314402f, 0.021878f, 1.148746f, -0.462258f, -0.175524f,
|
||||
-0.344589f, -0.475159f, -0.232322f, 0.471147f, -0.489948f, 0.467740f,
|
||||
-0.391550f, 0.208601f, 0.054138f, 0.076859f, -0.309497f, -0.095927f,
|
||||
0.225917f, 0.011582f, -0.520730f, -0.585497f, 0.174036f, 0.072521f,
|
||||
0.120771f, -0.517234f, -0.581908f, -0.034003f, -0.694722f, -0.364368f,
|
||||
0.290584f, 0.038373f, 0.685654f, 0.394019f, 0.759667f, 1.257502f,
|
||||
-0.610516f, -0.185434f, 0.211997f, -0.172458f, 0.044605f, 0.145316f,
|
||||
-0.182525f, -0.147376f, 0.578742f, 0.312412f, -0.446135f, -0.389112f,
|
||||
0.454033f, 0.260490f, 0.664285f, 0.395856f, -0.231827f, 0.215228f,
|
||||
0.014856f, -0.395462f, 0.479646f, -0.391445f, -0.357788f, 0.166238f,
|
||||
-0.056818f, -0.027783f, 0.060880f, -1.604710f, 0.531268f, 0.282184f,
|
||||
0.714944f, 0.093523f, -0.218312f, -0.095546f, -0.285621f, -0.190871f,
|
||||
-0.448340f, -0.016611f, 0.413913f, -0.286720f, -0.158828f, -0.092635f,
|
||||
-0.279551f, 0.166509f, -0.088162f, 0.446543f, -0.276830f, -0.065642f,
|
||||
-0.176346f, -0.984754f, 0.338738f, 0.403809f, 0.738065f, 1.154439f,
|
||||
0.750764f, 0.770959f, -0.269403f, 0.295651f, -0.331858f, 0.367144f,
|
||||
0.279279f, 0.157419f, -0.348227f, -0.168608f, -0.956000f, -0.647136f,
|
||||
0.250516f, 0.858084f, 0.809802f, 0.492408f, 0.804841f, 0.282802f,
|
||||
0.079395f, -0.291771f, -0.024382f, -1.615880f, -0.445166f, -0.407335f,
|
||||
-0.483044f, 0.141126f,
|
||||
};
|
||||
|
||||
static const float vp9_rect_part_nn_bias_16_layer0[NODES] = {
|
||||
0.275384f, -0.053745f, 0.000000f, 0.000000f, -0.178103f, 0.513965f,
|
||||
-0.161352f, 0.228551f, 0.000000f, 1.013712f, 0.000000f, 0.000000f,
|
||||
-1.144009f, -0.000006f, -0.241727f, 2.048764f,
|
||||
};
|
||||
|
||||
static const float vp9_rect_part_nn_weights_16_layer1[NODES * LABELS] = {
|
||||
-1.435278f, 2.204691f, -0.410718f, 0.202708f, 0.109208f, 1.059142f,
|
||||
-0.306360f, 0.845906f, 0.489654f, -1.121915f, -0.169133f, -0.003385f,
|
||||
0.660590f, -0.018711f, 1.227158f, -2.967504f, 1.407345f, -1.293243f,
|
||||
-0.386921f, 0.300492f, 0.338824f, -0.083250f, -0.069454f, -1.001827f,
|
||||
-0.327891f, 0.899353f, 0.367397f, -0.118601f, -0.171936f, -0.420646f,
|
||||
-0.803319f, 2.029634f, 0.940268f, -0.664484f, 0.339916f, 0.315944f,
|
||||
0.157374f, -0.402482f, -0.491695f, 0.595827f, 0.015031f, 0.255887f,
|
||||
-0.466327f, -0.212598f, 0.136485f, 0.033363f, -0.796921f, 1.414304f,
|
||||
-0.282185f, -2.673571f, -0.280994f, 0.382658f, -0.350902f, 0.227926f,
|
||||
0.062602f, -1.000199f, 0.433731f, 1.176439f, -0.163216f, -0.229015f,
|
||||
-0.640098f, -0.438852f, -0.947700f, 2.203434f,
|
||||
};
|
||||
|
||||
static const float vp9_rect_part_nn_bias_16_layer1[LABELS] = {
|
||||
-0.875510f,
|
||||
0.982408f,
|
||||
0.560854f,
|
||||
-0.415209f,
|
||||
};
|
||||
|
||||
static const NN_CONFIG vp9_rect_part_nnconfig_16 = {
|
||||
FEATURES, // num_inputs
|
||||
LABELS, // num_outputs
|
||||
1, // num_hidden_layers
|
||||
{
|
||||
NODES,
|
||||
}, // num_hidden_nodes
|
||||
{
|
||||
vp9_rect_part_nn_weights_16_layer0,
|
||||
vp9_rect_part_nn_weights_16_layer1,
|
||||
},
|
||||
{
|
||||
vp9_rect_part_nn_bias_16_layer0,
|
||||
vp9_rect_part_nn_bias_16_layer1,
|
||||
},
|
||||
};
|
||||
|
||||
static const float vp9_rect_part_nn_weights_32_layer0[FEATURES * NODES] = {
|
||||
-0.147312f, -0.753248f, 0.540206f, 0.661415f, 0.484117f, -0.341609f,
|
||||
0.016183f, 0.064177f, 0.781580f, 0.902232f, -0.505342f, 0.325183f,
|
||||
-0.231072f, -0.120107f, -0.076216f, 0.120038f, 0.403695f, -0.463301f,
|
||||
-0.192158f, 0.407442f, 0.106633f, 1.072371f, -0.446779f, 0.467353f,
|
||||
0.318812f, -0.505996f, -0.008768f, -0.239598f, 0.085480f, 0.284640f,
|
||||
-0.365045f, -0.048083f, -0.112090f, -0.067089f, 0.304138f, -0.228809f,
|
||||
0.383651f, -0.196882f, 0.477039f, -0.217978f, -0.506931f, -0.125675f,
|
||||
0.050456f, 1.086598f, 0.732128f, 0.326941f, 0.103952f, 0.121769f,
|
||||
-0.154487f, -0.255514f, 0.030591f, -0.382797f, -0.019981f, -0.326570f,
|
||||
0.149691f, -0.435633f, -0.070795f, 0.167691f, 0.251413f, -0.153405f,
|
||||
0.160347f, 0.455107f, -0.968580f, -0.575879f, 0.623115f, -0.069793f,
|
||||
-0.379768f, -0.965807f, -0.062057f, 0.071312f, 0.457098f, 0.350372f,
|
||||
-0.460659f, -0.985393f, 0.359963f, -0.093677f, 0.404272f, -0.326896f,
|
||||
-0.277752f, 0.609322f, -0.114193f, -0.230701f, 0.089208f, 0.645381f,
|
||||
0.494485f, 0.467876f, -0.166187f, 0.251044f, -0.394661f, 0.192895f,
|
||||
-0.344777f, -0.041893f, -0.111163f, 0.066347f, 0.378158f, -0.455465f,
|
||||
0.339839f, -0.418207f, -0.356515f, -0.227536f, -0.211091f, -0.122945f,
|
||||
0.361772f, -0.338095f, 0.004564f, -0.398510f, 0.060876f, -2.132504f,
|
||||
-0.086776f, -0.029166f, 0.039241f, 0.222534f, -0.188565f, -0.288792f,
|
||||
-0.160789f, -0.123905f, 0.397916f, -0.063779f, 0.167210f, -0.445004f,
|
||||
0.056889f, 0.207280f, 0.000101f, 0.384507f, -1.721239f, -2.036402f,
|
||||
-2.084403f, -2.060483f,
|
||||
};
|
||||
|
||||
static const float vp9_rect_part_nn_bias_32_layer0[NODES] = {
|
||||
-0.859251f, -0.109938f, 0.091838f, 0.187817f, -0.728265f, 0.253080f,
|
||||
0.000000f, -0.357195f, -0.031290f, -1.373237f, -0.761086f, 0.000000f,
|
||||
-0.024504f, 1.765711f, 0.000000f, 1.505390f,
|
||||
};
|
||||
|
||||
static const float vp9_rect_part_nn_weights_32_layer1[NODES * LABELS] = {
|
||||
0.680940f, 1.367178f, 0.403075f, 0.029957f, 0.500917f, 1.407776f,
|
||||
-0.354002f, 0.011667f, 1.663767f, 0.959155f, 0.428323f, -0.205345f,
|
||||
-0.081850f, -3.920103f, -0.243802f, -4.253933f, -0.034020f, -1.361057f,
|
||||
0.128236f, -0.138422f, -0.025790f, -0.563518f, -0.148715f, -0.344381f,
|
||||
-1.677389f, -0.868332f, -0.063792f, 0.052052f, 0.359591f, 2.739808f,
|
||||
-0.414304f, 3.036597f, -0.075368f, -1.019680f, 0.642501f, 0.209779f,
|
||||
-0.374539f, -0.718294f, -0.116616f, -0.043212f, -1.787809f, -0.773262f,
|
||||
0.068734f, 0.508309f, 0.099334f, 1.802239f, -0.333538f, 2.708645f,
|
||||
-0.447682f, -2.355555f, -0.506674f, -0.061028f, -0.310305f, -0.375475f,
|
||||
0.194572f, 0.431788f, -0.789624f, -0.031962f, 0.358353f, 0.382937f,
|
||||
0.232002f, 2.321813f, -0.037523f, 2.104652f,
|
||||
};
|
||||
|
||||
static const float vp9_rect_part_nn_bias_32_layer1[LABELS] = {
|
||||
-0.693383f,
|
||||
0.773661f,
|
||||
0.426878f,
|
||||
-0.070619f,
|
||||
};
|
||||
|
||||
static const NN_CONFIG vp9_rect_part_nnconfig_32 = {
|
||||
FEATURES, // num_inputs
|
||||
LABELS, // num_outputs
|
||||
1, // num_hidden_layers
|
||||
{
|
||||
NODES,
|
||||
}, // num_hidden_nodes
|
||||
{
|
||||
vp9_rect_part_nn_weights_32_layer0,
|
||||
vp9_rect_part_nn_weights_32_layer1,
|
||||
},
|
||||
{
|
||||
vp9_rect_part_nn_bias_32_layer0,
|
||||
vp9_rect_part_nn_bias_32_layer1,
|
||||
},
|
||||
};
|
||||
#undef NODES
|
||||
|
||||
#define NODES 24
|
||||
static const float vp9_rect_part_nn_weights_64_layer0[FEATURES * NODES] = {
|
||||
0.024671f, -0.220610f, -0.284362f, -0.069556f, -0.315700f, 0.187861f,
|
||||
0.139782f, 0.063110f, 0.796561f, 0.172868f, -0.662194f, -1.393074f,
|
||||
0.085003f, 0.393381f, 0.358477f, -0.187268f, -0.370745f, 0.218287f,
|
||||
0.027271f, -0.254089f, -0.048236f, -0.459137f, 0.253171f, 0.122598f,
|
||||
-0.550107f, -0.568456f, 0.159866f, -0.246534f, 0.096384f, -0.255460f,
|
||||
0.077864f, -0.334837f, 0.026921f, -0.697252f, 0.345262f, 1.343578f,
|
||||
0.815984f, 1.118211f, 1.574016f, 0.578476f, -0.285967f, -0.508672f,
|
||||
0.118137f, 0.037695f, 1.540510f, 1.256648f, 1.163819f, 1.172027f,
|
||||
0.661551f, -0.111980f, -0.434204f, -0.894217f, 0.570524f, 0.050292f,
|
||||
-0.113680f, 0.000784f, -0.211554f, -0.369394f, 0.158306f, -0.512505f,
|
||||
-0.238696f, 0.091498f, -0.448490f, -0.491268f, -0.353112f, -0.303315f,
|
||||
-0.428438f, 0.127998f, -0.406790f, -0.401786f, -0.279888f, -0.384223f,
|
||||
0.026100f, 0.041621f, -0.315818f, -0.087888f, 0.353497f, 0.163123f,
|
||||
-0.380128f, -0.090334f, -0.216647f, -0.117849f, -0.173502f, 0.301871f,
|
||||
0.070854f, 0.114627f, -0.050545f, -0.160381f, 0.595294f, 0.492696f,
|
||||
-0.453858f, -1.154139f, 0.126000f, 0.034550f, 0.456665f, -0.236618f,
|
||||
-0.112640f, 0.050759f, -0.449162f, 0.110059f, 0.147116f, 0.249358f,
|
||||
-0.049894f, 0.063351f, -0.004467f, 0.057242f, -0.482015f, -0.174335f,
|
||||
-0.085617f, -0.333808f, -0.358440f, -0.069006f, 0.099260f, -1.243430f,
|
||||
-0.052963f, 0.112088f, -2.661115f, -2.445893f, -2.688174f, -2.624232f,
|
||||
0.030494f, 0.161311f, 0.012136f, 0.207564f, -2.776856f, -2.791940f,
|
||||
-2.623962f, -2.918820f, 1.231619f, -0.376692f, -0.698078f, 0.110336f,
|
||||
-0.285378f, 0.258367f, -0.180159f, -0.376608f, -0.034348f, -0.130206f,
|
||||
0.160020f, 0.852977f, 0.580573f, 1.450782f, 1.357596f, 0.787382f,
|
||||
-0.544004f, -0.014795f, 0.032121f, -0.557696f, 0.159994f, -0.540908f,
|
||||
0.180380f, -0.398045f, 0.705095f, 0.515103f, -0.511521f, -1.271374f,
|
||||
-0.231019f, 0.423647f, 0.064907f, -0.255338f, -0.877748f, -0.667205f,
|
||||
0.267847f, 0.135229f, 0.617844f, 1.349849f, 1.012623f, 0.730506f,
|
||||
-0.078571f, 0.058401f, 0.053221f, -2.426146f, -0.098808f, -0.138508f,
|
||||
-0.153299f, 0.149116f, -0.444243f, 0.301807f, 0.065066f, 0.092929f,
|
||||
-0.372784f, -0.095540f, 0.192269f, 0.237894f, 0.080228f, -0.214074f,
|
||||
-0.011426f, -2.352367f, -0.085394f, -0.190361f, -0.001177f, 0.089197f,
|
||||
};
|
||||
|
||||
static const float vp9_rect_part_nn_bias_64_layer0[NODES] = {
|
||||
0.000000f, -0.057652f, -0.175413f, -0.175389f, -1.084097f, -1.423801f,
|
||||
-0.076307f, -0.193803f, 0.000000f, -0.066474f, -0.050318f, -0.019832f,
|
||||
-0.038814f, -0.144184f, 2.652451f, 2.415006f, 0.197464f, -0.729842f,
|
||||
-0.173774f, 0.239171f, 0.486425f, 2.463304f, -0.175279f, 2.352637f,
|
||||
};
|
||||
|
||||
static const float vp9_rect_part_nn_weights_64_layer1[NODES * LABELS] = {
|
||||
-0.063237f, 1.925696f, -0.182145f, -0.226687f, 0.602941f, -0.941140f,
|
||||
0.814598f, -0.117063f, 0.282988f, 0.066369f, 0.096951f, 1.049735f,
|
||||
-0.188188f, -0.281227f, -4.836746f, -5.047797f, 0.892358f, 0.417145f,
|
||||
-0.279849f, 1.335945f, 0.660338f, -2.757938f, -0.115714f, -1.862183f,
|
||||
-0.045980f, -1.597624f, -0.586822f, -0.615589f, -0.330537f, 1.068496f,
|
||||
-0.167290f, 0.141290f, -0.112100f, 0.232761f, 0.252307f, -0.399653f,
|
||||
0.353118f, 0.241583f, 2.635241f, 4.026119f, -1.137327f, -0.052446f,
|
||||
-0.139814f, -1.104256f, -0.759391f, 2.508457f, -0.526297f, 2.095348f,
|
||||
-0.444473f, -1.090452f, 0.584122f, 0.468729f, -0.368865f, 1.041425f,
|
||||
-1.079504f, 0.348837f, 0.390091f, 0.416191f, 0.212906f, -0.660255f,
|
||||
0.053630f, 0.209476f, 3.595525f, 2.257293f, -0.514030f, 0.074203f,
|
||||
-0.375862f, -1.998307f, -0.930310f, 1.866686f, -0.247137f, 1.087789f,
|
||||
0.100186f, 0.298150f, 0.165265f, 0.050478f, 0.249167f, 0.371789f,
|
||||
-0.294497f, 0.202954f, 0.037310f, 0.193159f, 0.161551f, 0.301597f,
|
||||
0.299286f, 0.185946f, 0.822976f, 2.066130f, -1.724588f, 0.055977f,
|
||||
-0.330747f, -0.067747f, -0.475801f, 1.555958f, -0.025808f, -0.081516f,
|
||||
};
|
||||
|
||||
static const float vp9_rect_part_nn_bias_64_layer1[LABELS] = {
|
||||
-0.090723f,
|
||||
0.894968f,
|
||||
0.844754f,
|
||||
-3.496194f,
|
||||
};
|
||||
|
||||
static const NN_CONFIG vp9_rect_part_nnconfig_64 = {
|
||||
FEATURES, // num_inputs
|
||||
LABELS, // num_outputs
|
||||
1, // num_hidden_layers
|
||||
{
|
||||
NODES,
|
||||
}, // num_hidden_nodes
|
||||
{
|
||||
vp9_rect_part_nn_weights_64_layer0,
|
||||
vp9_rect_part_nn_weights_64_layer1,
|
||||
},
|
||||
{
|
||||
vp9_rect_part_nn_bias_64_layer0,
|
||||
vp9_rect_part_nn_bias_64_layer1,
|
||||
},
|
||||
};
|
||||
#undef FEATURES
|
||||
#undef LABELS
|
||||
#undef NODES
|
||||
|
||||
#define FEATURES 7
|
||||
// Partition pruning model(neural nets).
|
||||
static const float vp9_partition_nn_weights_64x64_layer0[FEATURES * 8] = {
|
||||
-3.571348f, 0.014835f, -3.255393f, -0.098090f, -0.013120f, 0.000221f,
|
||||
0.056273f, 0.190179f, -0.268130f, -1.828242f, -0.010655f, 0.937244f,
|
||||
-0.435120f, 0.512125f, 1.610679f, 0.190816f, -0.799075f, -0.377348f,
|
||||
-0.144232f, 0.614383f, -0.980388f, 1.754150f, -0.185603f, -0.061854f,
|
||||
-0.807172f, 1.240177f, 1.419531f, -0.438544f, -5.980774f, 0.139045f,
|
||||
-0.032359f, -0.068887f, -1.237918f, 0.115706f, 0.003164f, 2.924212f,
|
||||
1.246838f, -0.035833f, 0.810011f, -0.805894f, 0.010966f, 0.076463f,
|
||||
-4.226380f, -2.437764f, -0.010619f, -0.020935f, -0.451494f, 0.300079f,
|
||||
-0.168961f, -3.326450f, -2.731094f, 0.002518f, 0.018840f, -1.656815f,
|
||||
0.068039f, 0.010586f,
|
||||
};
|
||||
|
||||
static const float vp9_partition_nn_bias_64x64_layer0[8] = {
|
||||
-3.469882f, 0.683989f, 0.194010f, 0.313782f,
|
||||
-3.153335f, 2.245849f, -1.946190f, -3.740020f,
|
||||
};
|
||||
|
||||
static const float vp9_partition_nn_weights_64x64_layer1[8] = {
|
||||
-8.058566f, 0.108306f, -0.280620f, -0.818823f,
|
||||
-6.445117f, 0.865364f, -1.127127f, -8.808660f,
|
||||
};
|
||||
|
||||
static const float vp9_partition_nn_bias_64x64_layer1[1] = {
|
||||
6.46909416f,
|
||||
};
|
||||
|
||||
static const NN_CONFIG vp9_partition_nnconfig_64x64 = {
|
||||
FEATURES, // num_inputs
|
||||
1, // num_outputs
|
||||
1, // num_hidden_layers
|
||||
{
|
||||
8,
|
||||
}, // num_hidden_nodes
|
||||
{
|
||||
vp9_partition_nn_weights_64x64_layer0,
|
||||
vp9_partition_nn_weights_64x64_layer1,
|
||||
},
|
||||
{
|
||||
vp9_partition_nn_bias_64x64_layer0,
|
||||
vp9_partition_nn_bias_64x64_layer1,
|
||||
},
|
||||
};
|
||||
|
||||
static const float vp9_partition_nn_weights_32x32_layer0[FEATURES * 8] = {
|
||||
-0.295437f, -4.002648f, -0.205399f, -0.060919f, 0.708037f, 0.027221f,
|
||||
-0.039137f, -0.907724f, -3.151662f, 0.007106f, 0.018726f, -0.534928f,
|
||||
0.022744f, 0.000159f, -1.717189f, -3.229031f, -0.027311f, 0.269863f,
|
||||
-0.400747f, -0.394366f, -0.108878f, 0.603027f, 0.455369f, -0.197170f,
|
||||
1.241746f, -1.347820f, -0.575636f, -0.462879f, -2.296426f, 0.196696f,
|
||||
-0.138347f, -0.030754f, -0.200774f, 0.453795f, 0.055625f, -3.163116f,
|
||||
-0.091003f, -0.027028f, -0.042984f, -0.605185f, 0.143240f, -0.036439f,
|
||||
-0.801228f, 0.313409f, -0.159942f, 0.031267f, 0.886454f, -1.531644f,
|
||||
-0.089655f, 0.037683f, -0.163441f, -0.130454f, -0.058344f, 0.060011f,
|
||||
0.275387f, 1.552226f,
|
||||
};
|
||||
|
||||
static const float vp9_partition_nn_bias_32x32_layer0[8] = {
|
||||
-0.838372f, -2.609089f, -0.055763f, 1.329485f,
|
||||
-1.297638f, -2.636622f, -0.826909f, 1.012644f,
|
||||
};
|
||||
|
||||
static const float vp9_partition_nn_weights_32x32_layer1[8] = {
|
||||
-1.792632f, -7.322353f, -0.683386f, 0.676564f,
|
||||
-1.488118f, -7.527719f, 1.240163f, 0.614309f,
|
||||
};
|
||||
|
||||
static const float vp9_partition_nn_bias_32x32_layer1[1] = {
|
||||
4.97422546f,
|
||||
};
|
||||
|
||||
static const NN_CONFIG vp9_partition_nnconfig_32x32 = {
|
||||
FEATURES, // num_inputs
|
||||
1, // num_outputs
|
||||
1, // num_hidden_layers
|
||||
{
|
||||
8,
|
||||
}, // num_hidden_nodes
|
||||
{
|
||||
vp9_partition_nn_weights_32x32_layer0,
|
||||
vp9_partition_nn_weights_32x32_layer1,
|
||||
},
|
||||
{
|
||||
vp9_partition_nn_bias_32x32_layer0,
|
||||
vp9_partition_nn_bias_32x32_layer1,
|
||||
},
|
||||
};
|
||||
|
||||
static const float vp9_partition_nn_weights_16x16_layer0[FEATURES * 8] = {
|
||||
-1.717673f, -4.718130f, -0.125725f, -0.183427f, -0.511764f, 0.035328f,
|
||||
0.130891f, -3.096753f, 0.174968f, -0.188769f, -0.640796f, 1.305661f,
|
||||
1.700638f, -0.073806f, -4.006781f, -1.630999f, -0.064863f, -0.086410f,
|
||||
-0.148617f, 0.172733f, -0.018619f, 2.152595f, 0.778405f, -0.156455f,
|
||||
0.612995f, -0.467878f, 0.152022f, -0.236183f, 0.339635f, -0.087119f,
|
||||
-3.196610f, -1.080401f, -0.637704f, -0.059974f, 1.706298f, -0.793705f,
|
||||
-6.399260f, 0.010624f, -0.064199f, -0.650621f, 0.338087f, -0.001531f,
|
||||
1.023655f, -3.700272f, -0.055281f, -0.386884f, 0.375504f, -0.898678f,
|
||||
0.281156f, -0.314611f, 0.863354f, -0.040582f, -0.145019f, 0.029329f,
|
||||
-2.197880f, -0.108733f,
|
||||
};
|
||||
|
||||
static const float vp9_partition_nn_bias_16x16_layer0[8] = {
|
||||
0.411516f, -2.143737f, -3.693192f, 2.123142f,
|
||||
-1.356910f, -3.561016f, -0.765045f, -2.417082f,
|
||||
};
|
||||
|
||||
static const float vp9_partition_nn_weights_16x16_layer1[8] = {
|
||||
-0.619755f, -2.202391f, -4.337171f, 0.611319f,
|
||||
0.377677f, -4.998723f, -1.052235f, 1.949922f,
|
||||
};
|
||||
|
||||
static const float vp9_partition_nn_bias_16x16_layer1[1] = {
|
||||
3.20981717f,
|
||||
};
|
||||
|
||||
static const NN_CONFIG vp9_partition_nnconfig_16x16 = {
|
||||
FEATURES, // num_inputs
|
||||
1, // num_outputs
|
||||
1, // num_hidden_layers
|
||||
{
|
||||
8,
|
||||
}, // num_hidden_nodes
|
||||
{
|
||||
vp9_partition_nn_weights_16x16_layer0,
|
||||
vp9_partition_nn_weights_16x16_layer1,
|
||||
},
|
||||
{
|
||||
vp9_partition_nn_bias_16x16_layer0,
|
||||
vp9_partition_nn_bias_16x16_layer1,
|
||||
},
|
||||
};
|
||||
#undef FEATURES
|
||||
|
||||
#define FEATURES 6
|
||||
static const float vp9_var_part_nn_weights_64_layer0[FEATURES * 8] = {
|
||||
-0.249572f, 0.205532f, -2.175608f, 1.094836f, -2.986370f, 0.193160f,
|
||||
-0.143823f, 0.378511f, -1.997788f, -2.166866f, -1.930158f, -1.202127f,
|
||||
-0.611875f, -0.506422f, -0.432487f, 0.071205f, 0.578172f, -0.154285f,
|
||||
-0.051830f, 0.331681f, -1.457177f, -2.443546f, -2.000302f, -1.389283f,
|
||||
0.372084f, -0.464917f, 2.265235f, 2.385787f, 2.312722f, 2.127868f,
|
||||
-0.403963f, -0.177860f, -0.436751f, -0.560539f, 0.254903f, 0.193976f,
|
||||
-0.305611f, 0.256632f, 0.309388f, -0.437439f, 1.702640f, -5.007069f,
|
||||
-0.323450f, 0.294227f, 1.267193f, 1.056601f, 0.387181f, -0.191215f,
|
||||
};
|
||||
|
||||
static const float vp9_var_part_nn_bias_64_layer0[8] = {
|
||||
-0.044396f, -0.938166f, 0.000000f, -0.916375f,
|
||||
1.242299f, 0.000000f, -0.405734f, 0.014206f,
|
||||
};
|
||||
|
||||
static const float vp9_var_part_nn_weights_64_layer1[8] = {
|
||||
1.635945f, 0.979557f, 0.455315f, 1.197199f,
|
||||
-2.251024f, -0.464953f, 1.378676f, -0.111927f,
|
||||
};
|
||||
|
||||
static const float vp9_var_part_nn_bias_64_layer1[1] = {
|
||||
-0.37972447f,
|
||||
};
|
||||
|
||||
static const NN_CONFIG vp9_var_part_nnconfig_64 = {
|
||||
FEATURES, // num_inputs
|
||||
1, // num_outputs
|
||||
1, // num_hidden_layers
|
||||
{
|
||||
8,
|
||||
}, // num_hidden_nodes
|
||||
{
|
||||
vp9_var_part_nn_weights_64_layer0,
|
||||
vp9_var_part_nn_weights_64_layer1,
|
||||
},
|
||||
{
|
||||
vp9_var_part_nn_bias_64_layer0,
|
||||
vp9_var_part_nn_bias_64_layer1,
|
||||
},
|
||||
};
|
||||
|
||||
static const float vp9_var_part_nn_weights_32_layer0[FEATURES * 8] = {
|
||||
0.067243f, -0.083598f, -2.191159f, 2.726434f, -3.324013f, 3.477977f,
|
||||
0.323736f, -0.510199f, 2.960693f, 2.937661f, 2.888476f, 2.938315f,
|
||||
-0.307602f, -0.503353f, -0.080725f, -0.473909f, -0.417162f, 0.457089f,
|
||||
0.665153f, -0.273210f, 0.028279f, 0.972220f, -0.445596f, 1.756611f,
|
||||
-0.177892f, -0.091758f, 0.436661f, -0.521506f, 0.133786f, 0.266743f,
|
||||
0.637367f, -0.160084f, -1.396269f, 1.020841f, -1.112971f, 0.919496f,
|
||||
-0.235883f, 0.651954f, 0.109061f, -0.429463f, 0.740839f, -0.962060f,
|
||||
0.299519f, -0.386298f, 1.550231f, 2.464915f, 1.311969f, 2.561612f,
|
||||
};
|
||||
|
||||
static const float vp9_var_part_nn_bias_32_layer0[8] = {
|
||||
0.368242f, 0.736617f, 0.000000f, 0.757287f,
|
||||
0.000000f, 0.613248f, -0.776390f, 0.928497f,
|
||||
};
|
||||
|
||||
static const float vp9_var_part_nn_weights_32_layer1[8] = {
|
||||
0.939884f, -2.420850f, -0.410489f, -0.186690f,
|
||||
0.063287f, -0.522011f, 0.484527f, -0.639625f,
|
||||
};
|
||||
|
||||
static const float vp9_var_part_nn_bias_32_layer1[1] = {
|
||||
-0.6455006f,
|
||||
};
|
||||
|
||||
static const NN_CONFIG vp9_var_part_nnconfig_32 = {
|
||||
FEATURES, // num_inputs
|
||||
1, // num_outputs
|
||||
1, // num_hidden_layers
|
||||
{
|
||||
8,
|
||||
}, // num_hidden_nodes
|
||||
{
|
||||
vp9_var_part_nn_weights_32_layer0,
|
||||
vp9_var_part_nn_weights_32_layer1,
|
||||
},
|
||||
{
|
||||
vp9_var_part_nn_bias_32_layer0,
|
||||
vp9_var_part_nn_bias_32_layer1,
|
||||
},
|
||||
};
|
||||
|
||||
static const float vp9_var_part_nn_weights_16_layer0[FEATURES * 8] = {
|
||||
0.742567f, -0.580624f, -0.244528f, 0.331661f, -0.113949f, -0.559295f,
|
||||
-0.386061f, 0.438653f, 1.467463f, 0.211589f, 0.513972f, 1.067855f,
|
||||
-0.876679f, 0.088560f, -0.687483f, -0.380304f, -0.016412f, 0.146380f,
|
||||
0.015318f, 0.000351f, -2.764887f, 3.269717f, 2.752428f, -2.236754f,
|
||||
0.561539f, -0.852050f, -0.084667f, 0.202057f, 0.197049f, 0.364922f,
|
||||
-0.463801f, 0.431790f, 1.872096f, -0.091887f, -0.055034f, 2.443492f,
|
||||
-0.156958f, -0.189571f, -0.542424f, -0.589804f, -0.354422f, 0.401605f,
|
||||
0.642021f, -0.875117f, 2.040794f, 1.921070f, 1.792413f, 1.839727f,
|
||||
};
|
||||
|
||||
static const float vp9_var_part_nn_bias_16_layer0[8] = {
|
||||
2.901234f, -1.940932f, -0.198970f, -0.406524f,
|
||||
0.059422f, -1.879207f, -0.232340f, 2.979821f,
|
||||
};
|
||||
|
||||
static const float vp9_var_part_nn_weights_16_layer1[8] = {
|
||||
-0.528731f, 0.375234f, -0.088422f, 0.668629f,
|
||||
0.870449f, 0.578735f, 0.546103f, -1.957207f,
|
||||
};
|
||||
|
||||
static const float vp9_var_part_nn_bias_16_layer1[1] = {
|
||||
-1.95769405f,
|
||||
};
|
||||
|
||||
static const NN_CONFIG vp9_var_part_nnconfig_16 = {
|
||||
FEATURES, // num_inputs
|
||||
1, // num_outputs
|
||||
1, // num_hidden_layers
|
||||
{
|
||||
8,
|
||||
}, // num_hidden_nodes
|
||||
{
|
||||
vp9_var_part_nn_weights_16_layer0,
|
||||
vp9_var_part_nn_weights_16_layer1,
|
||||
},
|
||||
{
|
||||
vp9_var_part_nn_bias_16_layer0,
|
||||
vp9_var_part_nn_bias_16_layer1,
|
||||
},
|
||||
};
|
||||
#undef FEATURES
|
||||
|
||||
#define FEATURES 12
|
||||
#define LABELS 1
|
||||
#define NODES 8
|
||||
static const float vp9_part_split_nn_weights_64_layer0[FEATURES * NODES] = {
|
||||
-0.609728f, -0.409099f, -0.472449f, 0.183769f, -0.457740f, 0.081089f,
|
||||
0.171003f, 0.578696f, -0.019043f, -0.856142f, 0.557369f, -1.779424f,
|
||||
-0.274044f, -0.320632f, -0.392531f, -0.359462f, -0.404106f, -0.288357f,
|
||||
0.200620f, 0.038013f, -0.430093f, 0.235083f, -0.487442f, 0.424814f,
|
||||
-0.232758f, -0.442943f, 0.229397f, -0.540301f, -0.648421f, -0.649747f,
|
||||
-0.171638f, 0.603824f, 0.468497f, -0.421580f, 0.178840f, -0.533838f,
|
||||
-0.029471f, -0.076296f, 0.197426f, -0.187908f, -0.003950f, -0.065740f,
|
||||
0.085165f, -0.039674f, -5.640702f, 1.909538f, -1.434604f, 3.294606f,
|
||||
-0.788812f, 0.196864f, 0.057012f, -0.019757f, 0.336233f, 0.075378f,
|
||||
0.081503f, 0.491864f, -1.899470f, -1.764173f, -1.888137f, -1.762343f,
|
||||
0.845542f, 0.202285f, 0.381948f, -0.150996f, 0.556893f, -0.305354f,
|
||||
0.561482f, -0.021974f, -0.703117f, 0.268638f, -0.665736f, 1.191005f,
|
||||
-0.081568f, -0.115653f, 0.272029f, -0.140074f, 0.072683f, 0.092651f,
|
||||
-0.472287f, -0.055790f, -0.434425f, 0.352055f, 0.048246f, 0.372865f,
|
||||
0.111499f, -0.338304f, 0.739133f, 0.156519f, -0.594644f, 0.137295f,
|
||||
0.613350f, -0.165102f, -1.003731f, 0.043070f, -0.887896f, -0.174202f,
|
||||
};
|
||||
|
||||
static const float vp9_part_split_nn_bias_64_layer0[NODES] = {
|
||||
1.182714f, 0.000000f, 0.902019f, 0.953115f,
|
||||
-1.372486f, -1.288740f, -0.155144f, -3.041362f,
|
||||
};
|
||||
|
||||
static const float vp9_part_split_nn_weights_64_layer1[NODES * LABELS] = {
|
||||
0.841214f, 0.456016f, 0.869270f, 1.692999f,
|
||||
-1.700494f, -0.911761f, 0.030111f, -1.447548f,
|
||||
};
|
||||
|
||||
static const float vp9_part_split_nn_bias_64_layer1[LABELS] = {
|
||||
1.17782545f,
|
||||
};
|
||||
|
||||
static const NN_CONFIG vp9_part_split_nnconfig_64 = {
|
||||
FEATURES, // num_inputs
|
||||
LABELS, // num_outputs
|
||||
1, // num_hidden_layers
|
||||
{
|
||||
NODES,
|
||||
}, // num_hidden_nodes
|
||||
{
|
||||
vp9_part_split_nn_weights_64_layer0,
|
||||
vp9_part_split_nn_weights_64_layer1,
|
||||
},
|
||||
{
|
||||
vp9_part_split_nn_bias_64_layer0,
|
||||
vp9_part_split_nn_bias_64_layer1,
|
||||
},
|
||||
};
|
||||
|
||||
static const float vp9_part_split_nn_weights_32_layer0[FEATURES * NODES] = {
|
||||
-0.105488f, -0.218662f, 0.010980f, -0.226979f, 0.028076f, 0.743430f,
|
||||
0.789266f, 0.031907f, -1.464200f, 0.222336f, -1.068493f, -0.052712f,
|
||||
-0.176181f, -0.102654f, -0.973932f, -0.182637f, -0.198000f, 0.335977f,
|
||||
0.271346f, 0.133005f, 1.674203f, 0.689567f, 0.657133f, 0.283524f,
|
||||
0.115529f, 0.738327f, 0.317184f, -0.179736f, 0.403691f, 0.679350f,
|
||||
0.048925f, 0.271338f, -1.538921f, -0.900737f, -1.377845f, 0.084245f,
|
||||
0.803122f, -0.107806f, 0.103045f, -0.023335f, -0.098116f, -0.127809f,
|
||||
0.037665f, -0.523225f, 1.622185f, 1.903999f, 1.358889f, 1.680785f,
|
||||
0.027743f, 0.117906f, -0.158810f, 0.057775f, 0.168257f, 0.062414f,
|
||||
0.086228f, -0.087381f, -3.066082f, 3.021855f, -4.092155f, 2.550104f,
|
||||
-0.230022f, -0.207445f, -0.000347f, 0.034042f, 0.097057f, 0.220088f,
|
||||
-0.228841f, -0.029405f, -1.507174f, -1.455184f, 2.624904f, 2.643355f,
|
||||
0.319912f, 0.585531f, -1.018225f, -0.699606f, 1.026490f, 0.169952f,
|
||||
-0.093579f, -0.142352f, -0.107256f, 0.059598f, 0.043190f, 0.507543f,
|
||||
-0.138617f, 0.030197f, 0.059574f, -0.634051f, -0.586724f, -0.148020f,
|
||||
-0.334380f, 0.459547f, 1.620600f, 0.496850f, 0.639480f, -0.465715f,
|
||||
};
|
||||
|
||||
static const float vp9_part_split_nn_bias_32_layer0[NODES] = {
|
||||
-1.125885f, 0.753197f, -0.825808f, 0.004839f,
|
||||
0.583920f, 0.718062f, 0.976741f, 0.796188f,
|
||||
};
|
||||
|
||||
static const float vp9_part_split_nn_weights_32_layer1[NODES * LABELS] = {
|
||||
-0.458745f, 0.724624f, -0.479720f, -2.199872f,
|
||||
1.162661f, 1.194153f, -0.716896f, 0.824080f,
|
||||
};
|
||||
|
||||
static const float vp9_part_split_nn_bias_32_layer1[LABELS] = {
|
||||
0.71644074f,
|
||||
};
|
||||
|
||||
static const NN_CONFIG vp9_part_split_nnconfig_32 = {
|
||||
FEATURES, // num_inputs
|
||||
LABELS, // num_outputs
|
||||
1, // num_hidden_layers
|
||||
{
|
||||
NODES,
|
||||
}, // num_hidden_nodes
|
||||
{
|
||||
vp9_part_split_nn_weights_32_layer0,
|
||||
vp9_part_split_nn_weights_32_layer1,
|
||||
},
|
||||
{
|
||||
vp9_part_split_nn_bias_32_layer0,
|
||||
vp9_part_split_nn_bias_32_layer1,
|
||||
},
|
||||
};
|
||||
|
||||
static const float vp9_part_split_nn_weights_16_layer0[FEATURES * NODES] = {
|
||||
-0.003629f, -0.046852f, 0.220428f, -0.033042f, 0.049365f, 0.112818f,
|
||||
-0.306149f, -0.005872f, 1.066947f, -2.290226f, 2.159505f, -0.618714f,
|
||||
-0.213294f, 0.451372f, -0.199459f, 0.223730f, -0.321709f, 0.063364f,
|
||||
0.148704f, -0.293371f, 0.077225f, -0.421947f, -0.515543f, -0.240975f,
|
||||
-0.418516f, 1.036523f, -0.009165f, 0.032484f, 1.086549f, 0.220322f,
|
||||
-0.247585f, -0.221232f, -0.225050f, 0.993051f, 0.285907f, 1.308846f,
|
||||
0.707456f, 0.335152f, 0.234556f, 0.264590f, -0.078033f, 0.542226f,
|
||||
0.057777f, 0.163471f, 0.039245f, -0.725960f, 0.963780f, -0.972001f,
|
||||
0.252237f, -0.192745f, -0.836571f, -0.460539f, -0.528713f, -0.160198f,
|
||||
-0.621108f, 0.486405f, -0.221923f, 1.519426f, -0.857871f, 0.411595f,
|
||||
0.947188f, 0.203339f, 0.174526f, 0.016382f, 0.256879f, 0.049818f,
|
||||
0.057836f, -0.659096f, 0.459894f, 0.174695f, 0.379359f, 0.062530f,
|
||||
-0.210201f, -0.355788f, -0.208432f, -0.401723f, -0.115373f, 0.191336f,
|
||||
-0.109342f, 0.002455f, -0.078746f, -0.391871f, 0.149892f, -0.239615f,
|
||||
-0.520709f, 0.118568f, -0.437975f, 0.118116f, -0.565426f, -0.206446f,
|
||||
0.113407f, 0.558894f, 0.534627f, 1.154350f, -0.116833f, 1.723311f,
|
||||
};
|
||||
|
||||
static const float vp9_part_split_nn_bias_16_layer0[NODES] = {
|
||||
0.013109f, -0.034341f, 0.679845f, -0.035781f,
|
||||
-0.104183f, 0.098055f, -0.041130f, 0.160107f,
|
||||
};
|
||||
|
||||
static const float vp9_part_split_nn_weights_16_layer1[NODES * LABELS] = {
|
||||
1.499564f, -0.403259f, 1.366532f, -0.469868f,
|
||||
0.482227f, -2.076697f, 0.527691f, 0.540495f,
|
||||
};
|
||||
|
||||
static const float vp9_part_split_nn_bias_16_layer1[LABELS] = {
|
||||
0.01134653f,
|
||||
};
|
||||
|
||||
static const NN_CONFIG vp9_part_split_nnconfig_16 = {
|
||||
FEATURES, // num_inputs
|
||||
LABELS, // num_outputs
|
||||
1, // num_hidden_layers
|
||||
{
|
||||
NODES,
|
||||
}, // num_hidden_nodes
|
||||
{
|
||||
vp9_part_split_nn_weights_16_layer0,
|
||||
vp9_part_split_nn_weights_16_layer1,
|
||||
},
|
||||
{
|
||||
vp9_part_split_nn_bias_16_layer0,
|
||||
vp9_part_split_nn_bias_16_layer1,
|
||||
},
|
||||
};
|
||||
|
||||
static const float vp9_part_split_nn_weights_8_layer0[FEATURES * NODES] = {
|
||||
-0.668875f, -0.159078f, -0.062663f, -0.483785f, -0.146814f, -0.608975f,
|
||||
-0.589145f, 0.203704f, -0.051007f, -0.113769f, -0.477511f, -0.122603f,
|
||||
-1.329890f, 1.403386f, 0.199636f, -0.161139f, 2.182090f, -0.014307f,
|
||||
0.015755f, -0.208468f, 0.884353f, 0.815920f, 0.632464f, 0.838225f,
|
||||
1.369483f, -0.029068f, 0.570213f, -0.573546f, 0.029617f, 0.562054f,
|
||||
-0.653093f, -0.211910f, -0.661013f, -0.384418f, -0.574038f, -0.510069f,
|
||||
0.173047f, -0.274231f, -1.044008f, -0.422040f, -0.810296f, 0.144069f,
|
||||
-0.406704f, 0.411230f, -0.144023f, 0.745651f, -0.595091f, 0.111787f,
|
||||
0.840651f, 0.030123f, -0.242155f, 0.101486f, -0.017889f, -0.254467f,
|
||||
-0.285407f, -0.076675f, -0.549542f, -0.013544f, -0.686566f, -0.755150f,
|
||||
1.623949f, -0.286369f, 0.170976f, 0.016442f, -0.598353f, -0.038540f,
|
||||
0.202597f, -0.933582f, 0.599510f, 0.362273f, 0.577722f, 0.477603f,
|
||||
0.767097f, 0.431532f, 0.457034f, 0.223279f, 0.381349f, 0.033777f,
|
||||
0.423923f, -0.664762f, 0.385662f, 0.075744f, 0.182681f, 0.024118f,
|
||||
0.319408f, -0.528864f, 0.976537f, -0.305971f, -0.189380f, -0.241689f,
|
||||
-1.318092f, 0.088647f, -0.109030f, -0.945654f, 1.082797f, 0.184564f,
|
||||
};
|
||||
|
||||
static const float vp9_part_split_nn_bias_8_layer0[NODES] = {
|
||||
-0.237472f, 2.051396f, 0.297062f, -0.730194f,
|
||||
0.060472f, -0.565959f, 0.560869f, -0.395448f,
|
||||
};
|
||||
|
||||
static const float vp9_part_split_nn_weights_8_layer1[NODES * LABELS] = {
|
||||
0.568121f, 1.575915f, -0.544309f, 0.751595f,
|
||||
-0.117911f, -1.340730f, -0.739671f, 0.661216f,
|
||||
};
|
||||
|
||||
static const float vp9_part_split_nn_bias_8_layer1[LABELS] = {
|
||||
-0.63375306f,
|
||||
};
|
||||
|
||||
static const NN_CONFIG vp9_part_split_nnconfig_8 = {
|
||||
FEATURES, // num_inputs
|
||||
LABELS, // num_outputs
|
||||
1, // num_hidden_layers
|
||||
{
|
||||
NODES,
|
||||
}, // num_hidden_nodes
|
||||
{
|
||||
vp9_part_split_nn_weights_8_layer0,
|
||||
vp9_part_split_nn_weights_8_layer1,
|
||||
},
|
||||
{
|
||||
vp9_part_split_nn_bias_8_layer0,
|
||||
vp9_part_split_nn_bias_8_layer1,
|
||||
},
|
||||
};
|
||||
#undef NODES
|
||||
#undef FEATURES
|
||||
#undef LABELS
|
||||
|
||||
// Partition pruning model(linear).
|
||||
static const float vp9_partition_feature_mean[24] = {
|
||||
303501.697372f, 3042630.372158f, 24.694696f, 1.392182f,
|
||||
689.413511f, 162.027012f, 1.478213f, 0.0,
|
||||
135382.260230f, 912738.513263f, 28.845217f, 1.515230f,
|
||||
544.158492f, 131.807995f, 1.436863f, 0.0f,
|
||||
43682.377587f, 208131.711766f, 28.084737f, 1.356677f,
|
||||
138.254122f, 119.522553f, 1.252322f, 0.0f,
|
||||
};
|
||||
|
||||
static const float vp9_partition_feature_std[24] = {
|
||||
673689.212982f, 5996652.516628f, 0.024449f, 1.989792f,
|
||||
985.880847f, 0.014638f, 2.001898f, 0.0f,
|
||||
208798.775332f, 1812548.443284f, 0.018693f, 1.838009f,
|
||||
396.986910f, 0.015657f, 1.332541f, 0.0f,
|
||||
55888.847031f, 448587.962714f, 0.017900f, 1.904776f,
|
||||
98.652832f, 0.016598f, 1.320992f, 0.0f,
|
||||
};
|
||||
|
||||
// Error tolerance: 0.01%-0.0.05%-0.1%
|
||||
static const float vp9_partition_linear_weights[24] = {
|
||||
0.111736f, 0.289977f, 0.042219f, 0.204765f, 0.120410f, -0.143863f,
|
||||
0.282376f, 0.847811f, 0.637161f, 0.131570f, 0.018636f, 0.202134f,
|
||||
0.112797f, 0.028162f, 0.182450f, 1.124367f, 0.386133f, 0.083700f,
|
||||
0.050028f, 0.150873f, 0.061119f, 0.109318f, 0.127255f, 0.625211f,
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_ENCODER_VP9_PARTITION_MODELS_H_
|
||||
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
* Copyright (c) 2010 The WebM project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "./vpx_scale_rtcd.h"
|
||||
#include "vpx_dsp/psnr.h"
|
||||
#include "vpx_mem/vpx_mem.h"
|
||||
#include "vpx_ports/mem.h"
|
||||
|
||||
#include "vp9/common/vp9_loopfilter.h"
|
||||
#include "vp9/common/vp9_onyxc_int.h"
|
||||
#include "vp9/common/vp9_quant_common.h"
|
||||
|
||||
#include "vp9/encoder/vp9_encoder.h"
|
||||
#include "vp9/encoder/vp9_picklpf.h"
|
||||
#include "vp9/encoder/vp9_quantize.h"
|
||||
|
||||
static unsigned int get_section_intra_rating(const VP9_COMP *cpi) {
|
||||
unsigned int section_intra_rating;
|
||||
|
||||
section_intra_rating = (cpi->common.frame_type == KEY_FRAME)
|
||||
? cpi->twopass.key_frame_section_intra_rating
|
||||
: cpi->twopass.section_intra_rating;
|
||||
|
||||
return section_intra_rating;
|
||||
}
|
||||
|
||||
static int get_max_filter_level(const VP9_COMP *cpi) {
|
||||
if (cpi->oxcf.pass == 2) {
|
||||
unsigned int section_intra_rating = get_section_intra_rating(cpi);
|
||||
return section_intra_rating > 8 ? MAX_LOOP_FILTER * 3 / 4 : MAX_LOOP_FILTER;
|
||||
} else {
|
||||
return MAX_LOOP_FILTER;
|
||||
}
|
||||
}
|
||||
|
||||
static int64_t try_filter_frame(const YV12_BUFFER_CONFIG *sd,
|
||||
VP9_COMP *const cpi, int filt_level,
|
||||
int partial_frame) {
|
||||
VP9_COMMON *const cm = &cpi->common;
|
||||
int64_t filt_err;
|
||||
|
||||
vp9_build_mask_frame(cm, filt_level, partial_frame);
|
||||
|
||||
if (cpi->num_workers > 1)
|
||||
vp9_loop_filter_frame_mt(cm->frame_to_show, cm, cpi->td.mb.e_mbd.plane,
|
||||
filt_level, 1, partial_frame, cpi->workers,
|
||||
cpi->num_workers, &cpi->lf_row_sync);
|
||||
else
|
||||
vp9_loop_filter_frame(cm->frame_to_show, cm, &cpi->td.mb.e_mbd, filt_level,
|
||||
1, partial_frame);
|
||||
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
if (cm->use_highbitdepth) {
|
||||
filt_err = vpx_highbd_get_y_sse(sd, cm->frame_to_show);
|
||||
} else {
|
||||
filt_err = vpx_get_y_sse(sd, cm->frame_to_show);
|
||||
}
|
||||
#else
|
||||
filt_err = vpx_get_y_sse(sd, cm->frame_to_show);
|
||||
#endif // CONFIG_VP9_HIGHBITDEPTH
|
||||
|
||||
// Re-instate the unfiltered frame
|
||||
vpx_yv12_copy_y(&cpi->last_frame_uf, cm->frame_to_show);
|
||||
|
||||
return filt_err;
|
||||
}
|
||||
|
||||
static int search_filter_level(const YV12_BUFFER_CONFIG *sd, VP9_COMP *cpi,
|
||||
int partial_frame) {
|
||||
const VP9_COMMON *const cm = &cpi->common;
|
||||
const struct loopfilter *const lf = &cm->lf;
|
||||
const int min_filter_level = 0;
|
||||
const int max_filter_level = get_max_filter_level(cpi);
|
||||
int filt_direction = 0;
|
||||
int64_t best_err;
|
||||
int filt_best;
|
||||
|
||||
// Start the search at the previous frame filter level unless it is now out of
|
||||
// range.
|
||||
int filt_mid = clamp(lf->last_filt_level, min_filter_level, max_filter_level);
|
||||
int filter_step = filt_mid < 16 ? 4 : filt_mid / 4;
|
||||
// Sum squared error at each filter level
|
||||
int64_t ss_err[MAX_LOOP_FILTER + 1];
|
||||
unsigned int section_intra_rating = get_section_intra_rating(cpi);
|
||||
|
||||
// Set each entry to -1
|
||||
memset(ss_err, 0xFF, sizeof(ss_err));
|
||||
|
||||
// Make a copy of the unfiltered / processed recon buffer
|
||||
vpx_yv12_copy_y(cm->frame_to_show, &cpi->last_frame_uf);
|
||||
|
||||
best_err = try_filter_frame(sd, cpi, filt_mid, partial_frame);
|
||||
filt_best = filt_mid;
|
||||
ss_err[filt_mid] = best_err;
|
||||
|
||||
while (filter_step > 0) {
|
||||
const int filt_high = VPXMIN(filt_mid + filter_step, max_filter_level);
|
||||
const int filt_low = VPXMAX(filt_mid - filter_step, min_filter_level);
|
||||
|
||||
// Bias against raising loop filter in favor of lowering it.
|
||||
int64_t bias = (best_err >> (15 - (filt_mid / 8))) * filter_step;
|
||||
|
||||
if ((cpi->oxcf.pass == 2) && (section_intra_rating < 20))
|
||||
bias = (bias * section_intra_rating) / 20;
|
||||
|
||||
// yx, bias less for large block size
|
||||
if (cm->tx_mode != ONLY_4X4) bias >>= 1;
|
||||
|
||||
if (filt_direction <= 0 && filt_low != filt_mid) {
|
||||
// Get Low filter error score
|
||||
if (ss_err[filt_low] < 0) {
|
||||
ss_err[filt_low] = try_filter_frame(sd, cpi, filt_low, partial_frame);
|
||||
}
|
||||
// If value is close to the best so far then bias towards a lower loop
|
||||
// filter value.
|
||||
if ((ss_err[filt_low] - bias) < best_err) {
|
||||
// Was it actually better than the previous best?
|
||||
if (ss_err[filt_low] < best_err) best_err = ss_err[filt_low];
|
||||
|
||||
filt_best = filt_low;
|
||||
}
|
||||
}
|
||||
|
||||
// Now look at filt_high
|
||||
if (filt_direction >= 0 && filt_high != filt_mid) {
|
||||
if (ss_err[filt_high] < 0) {
|
||||
ss_err[filt_high] = try_filter_frame(sd, cpi, filt_high, partial_frame);
|
||||
}
|
||||
// Was it better than the previous best?
|
||||
if (ss_err[filt_high] < (best_err - bias)) {
|
||||
best_err = ss_err[filt_high];
|
||||
filt_best = filt_high;
|
||||
}
|
||||
}
|
||||
|
||||
// Half the step distance if the best filter value was the same as last time
|
||||
if (filt_best == filt_mid) {
|
||||
filter_step /= 2;
|
||||
filt_direction = 0;
|
||||
} else {
|
||||
filt_direction = (filt_best < filt_mid) ? -1 : 1;
|
||||
filt_mid = filt_best;
|
||||
}
|
||||
}
|
||||
|
||||
return filt_best;
|
||||
}
|
||||
|
||||
void vp9_pick_filter_level(const YV12_BUFFER_CONFIG *sd, VP9_COMP *cpi,
|
||||
LPF_PICK_METHOD method) {
|
||||
VP9_COMMON *const cm = &cpi->common;
|
||||
struct loopfilter *const lf = &cm->lf;
|
||||
|
||||
lf->sharpness_level = 0;
|
||||
|
||||
if (method == LPF_PICK_MINIMAL_LPF && lf->filter_level) {
|
||||
lf->filter_level = 0;
|
||||
} else if (method >= LPF_PICK_FROM_Q) {
|
||||
const int min_filter_level = 0;
|
||||
const int max_filter_level = get_max_filter_level(cpi);
|
||||
const int q = vp9_ac_quant(cm->base_qindex, 0, cm->bit_depth);
|
||||
// These values were determined by linear fitting the result of the
|
||||
// searched level, filt_guess = q * 0.316206 + 3.87252
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
int filt_guess;
|
||||
switch (cm->bit_depth) {
|
||||
case VPX_BITS_8:
|
||||
filt_guess = ROUND_POWER_OF_TWO(q * 20723 + 1015158, 18);
|
||||
break;
|
||||
case VPX_BITS_10:
|
||||
filt_guess = ROUND_POWER_OF_TWO(q * 20723 + 4060632, 20);
|
||||
break;
|
||||
default:
|
||||
assert(cm->bit_depth == VPX_BITS_12);
|
||||
filt_guess = ROUND_POWER_OF_TWO(q * 20723 + 16242526, 22);
|
||||
break;
|
||||
}
|
||||
#else
|
||||
int filt_guess = ROUND_POWER_OF_TWO(q * 20723 + 1015158, 18);
|
||||
#endif // CONFIG_VP9_HIGHBITDEPTH
|
||||
if (cpi->oxcf.pass == 0 && cpi->oxcf.rc_mode == VPX_CBR &&
|
||||
cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ && cm->seg.enabled &&
|
||||
(cm->base_qindex < 200 || cm->width * cm->height > 320 * 240) &&
|
||||
cpi->oxcf.content != VP9E_CONTENT_SCREEN && cm->frame_type != KEY_FRAME)
|
||||
filt_guess = 5 * filt_guess >> 3;
|
||||
|
||||
if (cm->frame_type == KEY_FRAME) filt_guess -= 4;
|
||||
lf->filter_level = clamp(filt_guess, min_filter_level, max_filter_level);
|
||||
} else {
|
||||
lf->filter_level =
|
||||
search_filter_level(sd, cpi, method == LPF_PICK_FROM_SUBIMAGE);
|
||||
}
|
||||
}
|
||||
@@ -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_ENCODER_VP9_PICKLPF_H_
|
||||
#define VPX_VP9_ENCODER_VP9_PICKLPF_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "vp9/encoder/vp9_encoder.h"
|
||||
|
||||
struct yv12_buffer_config;
|
||||
struct VP9_COMP;
|
||||
|
||||
void vp9_pick_filter_level(const struct yv12_buffer_config *sd,
|
||||
struct VP9_COMP *cpi, LPF_PICK_METHOD method);
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_ENCODER_VP9_PICKLPF_H_
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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_PICKMODE_H_
|
||||
#define VPX_VP9_ENCODER_VP9_PICKMODE_H_
|
||||
|
||||
#include "vp9/encoder/vp9_encoder.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void vp9_pick_intra_mode(VP9_COMP *cpi, MACROBLOCK *x, RD_COST *rd_cost,
|
||||
BLOCK_SIZE bsize, PICK_MODE_CONTEXT *ctx);
|
||||
|
||||
void vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x, TileDataEnc *tile_data,
|
||||
int mi_row, int mi_col, RD_COST *rd_cost,
|
||||
BLOCK_SIZE bsize, PICK_MODE_CONTEXT *ctx);
|
||||
|
||||
void vp9_pick_inter_mode_sub8x8(VP9_COMP *cpi, MACROBLOCK *x, int mi_row,
|
||||
int mi_col, RD_COST *rd_cost, BLOCK_SIZE bsize,
|
||||
PICK_MODE_CONTEXT *ctx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_ENCODER_VP9_PICKMODE_H_
|
||||
@@ -0,0 +1,356 @@
|
||||
/*
|
||||
* Copyright (c) 2010 The WebM project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include "./vpx_dsp_rtcd.h"
|
||||
#include "vpx_mem/vpx_mem.h"
|
||||
#include "vpx_ports/mem.h"
|
||||
|
||||
#include "vp9/common/vp9_quant_common.h"
|
||||
#include "vp9/common/vp9_seg_common.h"
|
||||
|
||||
#include "vp9/encoder/vp9_encoder.h"
|
||||
#include "vp9/encoder/vp9_quantize.h"
|
||||
#include "vp9/encoder/vp9_rd.h"
|
||||
|
||||
void vp9_quantize_fp_c(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) {
|
||||
int i, eob = -1;
|
||||
(void)iscan;
|
||||
(void)skip_block;
|
||||
assert(!skip_block);
|
||||
|
||||
memset(qcoeff_ptr, 0, n_coeffs * sizeof(*qcoeff_ptr));
|
||||
memset(dqcoeff_ptr, 0, n_coeffs * sizeof(*dqcoeff_ptr));
|
||||
|
||||
// Quantization pass: All coefficients with index >= zero_flag are
|
||||
// skippable. Note: zero_flag can be zero.
|
||||
for (i = 0; i < n_coeffs; i++) {
|
||||
const int rc = scan[i];
|
||||
const int coeff = coeff_ptr[rc];
|
||||
const int coeff_sign = (coeff >> 31);
|
||||
const int abs_coeff = (coeff ^ coeff_sign) - coeff_sign;
|
||||
|
||||
int tmp = clamp(abs_coeff + round_ptr[rc != 0], INT16_MIN, INT16_MAX);
|
||||
tmp = (tmp * quant_ptr[rc != 0]) >> 16;
|
||||
|
||||
qcoeff_ptr[rc] = (tmp ^ coeff_sign) - coeff_sign;
|
||||
dqcoeff_ptr[rc] = qcoeff_ptr[rc] * dequant_ptr[rc != 0];
|
||||
|
||||
if (tmp) eob = i;
|
||||
}
|
||||
*eob_ptr = eob + 1;
|
||||
}
|
||||
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
void vp9_highbd_quantize_fp_c(const tran_low_t *coeff_ptr, intptr_t 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) {
|
||||
int i;
|
||||
int eob = -1;
|
||||
|
||||
(void)iscan;
|
||||
(void)skip_block;
|
||||
assert(!skip_block);
|
||||
|
||||
memset(qcoeff_ptr, 0, n_coeffs * sizeof(*qcoeff_ptr));
|
||||
memset(dqcoeff_ptr, 0, n_coeffs * sizeof(*dqcoeff_ptr));
|
||||
|
||||
// Quantization pass: All coefficients with index >= zero_flag are
|
||||
// skippable. Note: zero_flag can be zero.
|
||||
for (i = 0; i < n_coeffs; i++) {
|
||||
const int rc = scan[i];
|
||||
const int coeff = coeff_ptr[rc];
|
||||
const int coeff_sign = (coeff >> 31);
|
||||
const int abs_coeff = (coeff ^ coeff_sign) - coeff_sign;
|
||||
const int64_t tmp = abs_coeff + round_ptr[rc != 0];
|
||||
const int abs_qcoeff = (int)((tmp * quant_ptr[rc != 0]) >> 16);
|
||||
qcoeff_ptr[rc] = (tran_low_t)(abs_qcoeff ^ coeff_sign) - coeff_sign;
|
||||
dqcoeff_ptr[rc] = qcoeff_ptr[rc] * dequant_ptr[rc != 0];
|
||||
if (abs_qcoeff) eob = i;
|
||||
}
|
||||
*eob_ptr = eob + 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
// TODO(jingning) Refactor this file and combine functions with similar
|
||||
// operations.
|
||||
void vp9_quantize_fp_32x32_c(const tran_low_t *coeff_ptr, intptr_t n_coeffs,
|
||||
int skip_block, const int16_t *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) {
|
||||
int i, eob = -1;
|
||||
(void)iscan;
|
||||
(void)skip_block;
|
||||
assert(!skip_block);
|
||||
|
||||
memset(qcoeff_ptr, 0, n_coeffs * sizeof(*qcoeff_ptr));
|
||||
memset(dqcoeff_ptr, 0, n_coeffs * sizeof(*dqcoeff_ptr));
|
||||
|
||||
for (i = 0; i < n_coeffs; i++) {
|
||||
const int rc = scan[i];
|
||||
const int coeff = coeff_ptr[rc];
|
||||
const int coeff_sign = (coeff >> 31);
|
||||
int tmp = 0;
|
||||
int abs_coeff = (coeff ^ coeff_sign) - coeff_sign;
|
||||
|
||||
if (abs_coeff >= (dequant_ptr[rc != 0] >> 2)) {
|
||||
abs_coeff += ROUND_POWER_OF_TWO(round_ptr[rc != 0], 1);
|
||||
abs_coeff = clamp(abs_coeff, INT16_MIN, INT16_MAX);
|
||||
tmp = (abs_coeff * quant_ptr[rc != 0]) >> 15;
|
||||
qcoeff_ptr[rc] = (tmp ^ coeff_sign) - coeff_sign;
|
||||
dqcoeff_ptr[rc] = qcoeff_ptr[rc] * dequant_ptr[rc != 0] / 2;
|
||||
}
|
||||
|
||||
if (tmp) eob = i;
|
||||
}
|
||||
*eob_ptr = eob + 1;
|
||||
}
|
||||
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
void vp9_highbd_quantize_fp_32x32_c(
|
||||
const tran_low_t *coeff_ptr, intptr_t n_coeffs, int skip_block,
|
||||
const int16_t *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) {
|
||||
int i, eob = -1;
|
||||
|
||||
(void)iscan;
|
||||
(void)skip_block;
|
||||
assert(!skip_block);
|
||||
|
||||
memset(qcoeff_ptr, 0, n_coeffs * sizeof(*qcoeff_ptr));
|
||||
memset(dqcoeff_ptr, 0, n_coeffs * sizeof(*dqcoeff_ptr));
|
||||
|
||||
for (i = 0; i < n_coeffs; i++) {
|
||||
int abs_qcoeff = 0;
|
||||
const int rc = scan[i];
|
||||
const int coeff = coeff_ptr[rc];
|
||||
const int coeff_sign = (coeff >> 31);
|
||||
const int abs_coeff = (coeff ^ coeff_sign) - coeff_sign;
|
||||
|
||||
if (abs_coeff >= (dequant_ptr[rc != 0] >> 2)) {
|
||||
const int64_t tmp = abs_coeff + ROUND_POWER_OF_TWO(round_ptr[rc != 0], 1);
|
||||
abs_qcoeff = (int)((tmp * quant_ptr[rc != 0]) >> 15);
|
||||
qcoeff_ptr[rc] = (tran_low_t)((abs_qcoeff ^ coeff_sign) - coeff_sign);
|
||||
dqcoeff_ptr[rc] = qcoeff_ptr[rc] * dequant_ptr[rc != 0] / 2;
|
||||
}
|
||||
|
||||
if (abs_qcoeff) eob = i;
|
||||
}
|
||||
*eob_ptr = eob + 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
void vp9_regular_quantize_b_4x4(MACROBLOCK *x, int plane, int block,
|
||||
const int16_t *scan, const int16_t *iscan) {
|
||||
MACROBLOCKD *const xd = &x->e_mbd;
|
||||
struct macroblock_plane *p = &x->plane[plane];
|
||||
struct macroblockd_plane *pd = &xd->plane[plane];
|
||||
tran_low_t *qcoeff = BLOCK_OFFSET(p->qcoeff, block),
|
||||
*dqcoeff = BLOCK_OFFSET(pd->dqcoeff, block);
|
||||
const int n_coeffs = 4 * 4;
|
||||
|
||||
if (x->skip_block) {
|
||||
memset(qcoeff, 0, n_coeffs * sizeof(*qcoeff));
|
||||
memset(dqcoeff, 0, n_coeffs * sizeof(*dqcoeff));
|
||||
return;
|
||||
}
|
||||
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) {
|
||||
vpx_highbd_quantize_b(BLOCK_OFFSET(p->coeff, block), n_coeffs,
|
||||
x->skip_block, p->zbin, p->round, p->quant,
|
||||
p->quant_shift, qcoeff, dqcoeff, pd->dequant,
|
||||
&p->eobs[block], scan, iscan);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
vpx_quantize_b(BLOCK_OFFSET(p->coeff, block), n_coeffs, x->skip_block,
|
||||
p->zbin, p->round, p->quant, p->quant_shift, qcoeff, dqcoeff,
|
||||
pd->dequant, &p->eobs[block], scan, iscan);
|
||||
}
|
||||
|
||||
static void invert_quant(int16_t *quant, int16_t *shift, int d) {
|
||||
unsigned t;
|
||||
int l, m;
|
||||
t = d;
|
||||
for (l = 0; t > 1; l++) t >>= 1;
|
||||
m = 1 + (1 << (16 + l)) / d;
|
||||
*quant = (int16_t)(m - (1 << 16));
|
||||
*shift = 1 << (16 - l);
|
||||
}
|
||||
|
||||
static int get_qzbin_factor(int q, vpx_bit_depth_t bit_depth) {
|
||||
const int quant = vp9_dc_quant(q, 0, bit_depth);
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
switch (bit_depth) {
|
||||
case VPX_BITS_8: return q == 0 ? 64 : (quant < 148 ? 84 : 80);
|
||||
case VPX_BITS_10: return q == 0 ? 64 : (quant < 592 ? 84 : 80);
|
||||
default:
|
||||
assert(bit_depth == VPX_BITS_12);
|
||||
return q == 0 ? 64 : (quant < 2368 ? 84 : 80);
|
||||
}
|
||||
#else
|
||||
(void)bit_depth;
|
||||
return q == 0 ? 64 : (quant < 148 ? 84 : 80);
|
||||
#endif
|
||||
}
|
||||
|
||||
void vp9_init_quantizer(VP9_COMP *cpi) {
|
||||
VP9_COMMON *const cm = &cpi->common;
|
||||
QUANTS *const quants = &cpi->quants;
|
||||
int i, q, quant;
|
||||
|
||||
for (q = 0; q < QINDEX_RANGE; q++) {
|
||||
int qzbin_factor = get_qzbin_factor(q, cm->bit_depth);
|
||||
int qrounding_factor = q == 0 ? 64 : 48;
|
||||
const int sharpness_adjustment = 16 * (7 - cpi->oxcf.sharpness) / 7;
|
||||
|
||||
if (cpi->oxcf.sharpness > 0 && q > 0) {
|
||||
qzbin_factor = 64 + sharpness_adjustment;
|
||||
qrounding_factor = 64 - sharpness_adjustment;
|
||||
}
|
||||
|
||||
for (i = 0; i < 2; ++i) {
|
||||
int qrounding_factor_fp = i == 0 ? 48 : 42;
|
||||
if (q == 0) qrounding_factor_fp = 64;
|
||||
if (cpi->oxcf.sharpness > 0)
|
||||
qrounding_factor_fp = 64 - sharpness_adjustment;
|
||||
// y
|
||||
quant = i == 0 ? vp9_dc_quant(q, cm->y_dc_delta_q, cm->bit_depth)
|
||||
: vp9_ac_quant(q, 0, cm->bit_depth);
|
||||
invert_quant(&quants->y_quant[q][i], &quants->y_quant_shift[q][i], quant);
|
||||
quants->y_quant_fp[q][i] = (1 << 16) / quant;
|
||||
quants->y_round_fp[q][i] = (qrounding_factor_fp * quant) >> 7;
|
||||
quants->y_zbin[q][i] = ROUND_POWER_OF_TWO(qzbin_factor * quant, 7);
|
||||
quants->y_round[q][i] = (qrounding_factor * quant) >> 7;
|
||||
cpi->y_dequant[q][i] = quant;
|
||||
|
||||
// uv
|
||||
quant = i == 0 ? vp9_dc_quant(q, cm->uv_dc_delta_q, cm->bit_depth)
|
||||
: vp9_ac_quant(q, cm->uv_ac_delta_q, cm->bit_depth);
|
||||
invert_quant(&quants->uv_quant[q][i], &quants->uv_quant_shift[q][i],
|
||||
quant);
|
||||
quants->uv_quant_fp[q][i] = (1 << 16) / quant;
|
||||
quants->uv_round_fp[q][i] = (qrounding_factor_fp * quant) >> 7;
|
||||
quants->uv_zbin[q][i] = ROUND_POWER_OF_TWO(qzbin_factor * quant, 7);
|
||||
quants->uv_round[q][i] = (qrounding_factor * quant) >> 7;
|
||||
cpi->uv_dequant[q][i] = quant;
|
||||
}
|
||||
|
||||
for (i = 2; i < 8; i++) {
|
||||
quants->y_quant[q][i] = quants->y_quant[q][1];
|
||||
quants->y_quant_fp[q][i] = quants->y_quant_fp[q][1];
|
||||
quants->y_round_fp[q][i] = quants->y_round_fp[q][1];
|
||||
quants->y_quant_shift[q][i] = quants->y_quant_shift[q][1];
|
||||
quants->y_zbin[q][i] = quants->y_zbin[q][1];
|
||||
quants->y_round[q][i] = quants->y_round[q][1];
|
||||
cpi->y_dequant[q][i] = cpi->y_dequant[q][1];
|
||||
|
||||
quants->uv_quant[q][i] = quants->uv_quant[q][1];
|
||||
quants->uv_quant_fp[q][i] = quants->uv_quant_fp[q][1];
|
||||
quants->uv_round_fp[q][i] = quants->uv_round_fp[q][1];
|
||||
quants->uv_quant_shift[q][i] = quants->uv_quant_shift[q][1];
|
||||
quants->uv_zbin[q][i] = quants->uv_zbin[q][1];
|
||||
quants->uv_round[q][i] = quants->uv_round[q][1];
|
||||
cpi->uv_dequant[q][i] = cpi->uv_dequant[q][1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_init_plane_quantizers(VP9_COMP *cpi, MACROBLOCK *x) {
|
||||
const VP9_COMMON *const cm = &cpi->common;
|
||||
MACROBLOCKD *const xd = &x->e_mbd;
|
||||
QUANTS *const quants = &cpi->quants;
|
||||
const int segment_id = xd->mi[0]->segment_id;
|
||||
const int qindex = vp9_get_qindex(&cm->seg, segment_id, cm->base_qindex);
|
||||
const int rdmult = vp9_compute_rd_mult(cpi, qindex + cm->y_dc_delta_q);
|
||||
int i;
|
||||
|
||||
// Y
|
||||
x->plane[0].quant = quants->y_quant[qindex];
|
||||
x->plane[0].quant_fp = quants->y_quant_fp[qindex];
|
||||
memcpy(x->plane[0].round_fp, quants->y_round_fp[qindex],
|
||||
8 * sizeof(*(x->plane[0].round_fp)));
|
||||
x->plane[0].quant_shift = quants->y_quant_shift[qindex];
|
||||
x->plane[0].zbin = quants->y_zbin[qindex];
|
||||
x->plane[0].round = quants->y_round[qindex];
|
||||
xd->plane[0].dequant = cpi->y_dequant[qindex];
|
||||
x->plane[0].quant_thred[0] = x->plane[0].zbin[0] * x->plane[0].zbin[0];
|
||||
x->plane[0].quant_thred[1] = x->plane[0].zbin[1] * x->plane[0].zbin[1];
|
||||
|
||||
// UV
|
||||
for (i = 1; i < 3; i++) {
|
||||
x->plane[i].quant = quants->uv_quant[qindex];
|
||||
x->plane[i].quant_fp = quants->uv_quant_fp[qindex];
|
||||
memcpy(x->plane[i].round_fp, quants->uv_round_fp[qindex],
|
||||
8 * sizeof(*(x->plane[i].round_fp)));
|
||||
x->plane[i].quant_shift = quants->uv_quant_shift[qindex];
|
||||
x->plane[i].zbin = quants->uv_zbin[qindex];
|
||||
x->plane[i].round = quants->uv_round[qindex];
|
||||
xd->plane[i].dequant = cpi->uv_dequant[qindex];
|
||||
x->plane[i].quant_thred[0] = x->plane[i].zbin[0] * x->plane[i].zbin[0];
|
||||
x->plane[i].quant_thred[1] = x->plane[i].zbin[1] * x->plane[i].zbin[1];
|
||||
}
|
||||
|
||||
x->skip_block = segfeature_active(&cm->seg, segment_id, SEG_LVL_SKIP);
|
||||
x->q_index = qindex;
|
||||
|
||||
set_error_per_bit(x, rdmult);
|
||||
|
||||
vp9_initialize_me_consts(cpi, x, x->q_index);
|
||||
}
|
||||
|
||||
void vp9_frame_init_quantizer(VP9_COMP *cpi) {
|
||||
vp9_init_plane_quantizers(cpi, &cpi->td.mb);
|
||||
}
|
||||
|
||||
void vp9_set_quantizer(VP9_COMMON *cm, int q) {
|
||||
// quantizer has to be reinitialized with vp9_init_quantizer() if any
|
||||
// delta_q changes.
|
||||
cm->base_qindex = q;
|
||||
cm->y_dc_delta_q = 0;
|
||||
cm->uv_dc_delta_q = 0;
|
||||
cm->uv_ac_delta_q = 0;
|
||||
}
|
||||
|
||||
// Table that converts 0-63 Q-range values passed in outside to the Qindex
|
||||
// range used internally.
|
||||
static const int quantizer_to_qindex[] = {
|
||||
0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48,
|
||||
52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92, 96, 100,
|
||||
104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 148, 152,
|
||||
156, 160, 164, 168, 172, 176, 180, 184, 188, 192, 196, 200, 204,
|
||||
208, 212, 216, 220, 224, 228, 232, 236, 240, 244, 249, 255,
|
||||
};
|
||||
|
||||
int vp9_quantizer_to_qindex(int quantizer) {
|
||||
return quantizer_to_qindex[quantizer];
|
||||
}
|
||||
|
||||
int vp9_qindex_to_quantizer(int qindex) {
|
||||
int quantizer;
|
||||
|
||||
for (quantizer = 0; quantizer < 64; ++quantizer)
|
||||
if (quantizer_to_qindex[quantizer] >= qindex) return quantizer;
|
||||
|
||||
return 63;
|
||||
}
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
#ifndef VPX_VP9_ENCODER_VP9_QUANTIZE_H_
|
||||
#define VPX_VP9_ENCODER_VP9_QUANTIZE_H_
|
||||
|
||||
#include "./vpx_config.h"
|
||||
#include "vp9/encoder/vp9_block.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
DECLARE_ALIGNED(16, int16_t, y_quant[QINDEX_RANGE][8]);
|
||||
DECLARE_ALIGNED(16, int16_t, y_quant_shift[QINDEX_RANGE][8]);
|
||||
DECLARE_ALIGNED(16, int16_t, y_zbin[QINDEX_RANGE][8]);
|
||||
DECLARE_ALIGNED(16, int16_t, y_round[QINDEX_RANGE][8]);
|
||||
|
||||
// TODO(jingning): in progress of re-working the quantization. will decide
|
||||
// if we want to deprecate the current use of y_quant.
|
||||
DECLARE_ALIGNED(16, int16_t, y_quant_fp[QINDEX_RANGE][8]);
|
||||
DECLARE_ALIGNED(16, int16_t, uv_quant_fp[QINDEX_RANGE][8]);
|
||||
DECLARE_ALIGNED(16, int16_t, y_round_fp[QINDEX_RANGE][8]);
|
||||
DECLARE_ALIGNED(16, int16_t, uv_round_fp[QINDEX_RANGE][8]);
|
||||
|
||||
DECLARE_ALIGNED(16, int16_t, uv_quant[QINDEX_RANGE][8]);
|
||||
DECLARE_ALIGNED(16, int16_t, uv_quant_shift[QINDEX_RANGE][8]);
|
||||
DECLARE_ALIGNED(16, int16_t, uv_zbin[QINDEX_RANGE][8]);
|
||||
DECLARE_ALIGNED(16, int16_t, uv_round[QINDEX_RANGE][8]);
|
||||
} QUANTS;
|
||||
|
||||
void vp9_regular_quantize_b_4x4(MACROBLOCK *x, int plane, int block,
|
||||
const int16_t *scan, const int16_t *iscan);
|
||||
|
||||
struct VP9_COMP;
|
||||
struct VP9Common;
|
||||
|
||||
void vp9_frame_init_quantizer(struct VP9_COMP *cpi);
|
||||
|
||||
void vp9_init_plane_quantizers(struct VP9_COMP *cpi, MACROBLOCK *x);
|
||||
|
||||
void vp9_init_quantizer(struct VP9_COMP *cpi);
|
||||
|
||||
void vp9_set_quantizer(struct VP9Common *cm, int q);
|
||||
|
||||
int vp9_quantizer_to_qindex(int quantizer);
|
||||
|
||||
int vp9_qindex_to_quantizer(int qindex);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_ENCODER_VP9_QUANTIZE_H_
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,337 @@
|
||||
/*
|
||||
* 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_ENCODER_VP9_RATECTRL_H_
|
||||
#define VPX_VP9_ENCODER_VP9_RATECTRL_H_
|
||||
|
||||
#include "vpx/vpx_codec.h"
|
||||
#include "vpx/vpx_integer.h"
|
||||
|
||||
#include "vp9/common/vp9_blockd.h"
|
||||
#include "vp9/encoder/vp9_lookahead.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Used to control aggressive VBR mode.
|
||||
// #define AGGRESSIVE_VBR 1
|
||||
|
||||
// Bits Per MB at different Q (Multiplied by 512)
|
||||
#define BPER_MB_NORMBITS 9
|
||||
|
||||
#define MIN_GF_INTERVAL 4
|
||||
#define MAX_GF_INTERVAL 16
|
||||
#define FIXED_GF_INTERVAL 8 // Used in some testing modes only
|
||||
#define ONEHALFONLY_RESIZE 0
|
||||
|
||||
#define FRAME_OVERHEAD_BITS 200
|
||||
|
||||
// Threshold used to define a KF group as static (e.g. a slide show).
|
||||
// Essentially this means that no frame in the group has more than 1% of MBs
|
||||
// that are not marked as coded with 0,0 motion in the first pass.
|
||||
#define STATIC_KF_GROUP_THRESH 99
|
||||
|
||||
// The maximum duration of a GF group that is static (for example a slide show).
|
||||
#define MAX_STATIC_GF_GROUP_LENGTH 250
|
||||
|
||||
typedef enum {
|
||||
INTER_NORMAL = 0,
|
||||
INTER_HIGH = 1,
|
||||
GF_ARF_LOW = 2,
|
||||
GF_ARF_STD = 3,
|
||||
KF_STD = 4,
|
||||
RATE_FACTOR_LEVELS = 5
|
||||
} RATE_FACTOR_LEVEL;
|
||||
|
||||
// Internal frame scaling level.
|
||||
typedef enum {
|
||||
UNSCALED = 0, // Frame is unscaled.
|
||||
SCALE_STEP1 = 1, // First-level down-scaling.
|
||||
FRAME_SCALE_STEPS
|
||||
} FRAME_SCALE_LEVEL;
|
||||
|
||||
typedef enum {
|
||||
NO_RESIZE = 0,
|
||||
DOWN_THREEFOUR = 1, // From orig to 3/4.
|
||||
DOWN_ONEHALF = 2, // From orig or 3/4 to 1/2.
|
||||
UP_THREEFOUR = -1, // From 1/2 to 3/4.
|
||||
UP_ORIG = -2, // From 1/2 or 3/4 to orig.
|
||||
} RESIZE_ACTION;
|
||||
|
||||
typedef enum { ORIG = 0, THREE_QUARTER = 1, ONE_HALF = 2 } RESIZE_STATE;
|
||||
|
||||
// Frame dimensions multiplier wrt the native frame size, in 1/16ths,
|
||||
// specified for the scale-up case.
|
||||
// e.g. 24 => 16/24 = 2/3 of native size. The restriction to 1/16th is
|
||||
// intended to match the capabilities of the normative scaling filters,
|
||||
// giving precedence to the up-scaling accuracy.
|
||||
static const int frame_scale_factor[FRAME_SCALE_STEPS] = { 16, 24 };
|
||||
|
||||
// Multiplier of the target rate to be used as threshold for triggering scaling.
|
||||
static const double rate_thresh_mult[FRAME_SCALE_STEPS] = { 1.0, 2.0 };
|
||||
|
||||
// Scale dependent Rate Correction Factor multipliers. Compensates for the
|
||||
// greater number of bits per pixel generated in down-scaled frames.
|
||||
static const double rcf_mult[FRAME_SCALE_STEPS] = { 1.0, 2.0 };
|
||||
|
||||
typedef struct {
|
||||
// Rate targetting variables
|
||||
int base_frame_target; // A baseline frame target before adjustment
|
||||
// for previous under or over shoot.
|
||||
int this_frame_target; // Actual frame target after rc adjustment.
|
||||
int projected_frame_size;
|
||||
int sb64_target_rate;
|
||||
int last_q[FRAME_TYPES]; // Separate values for Intra/Inter
|
||||
int last_boosted_qindex; // Last boosted GF/KF/ARF q
|
||||
int last_kf_qindex; // Q index of the last key frame coded.
|
||||
|
||||
int gfu_boost;
|
||||
int last_boost;
|
||||
int kf_boost;
|
||||
|
||||
double rate_correction_factors[RATE_FACTOR_LEVELS];
|
||||
|
||||
int frames_since_golden;
|
||||
int frames_till_gf_update_due;
|
||||
int min_gf_interval;
|
||||
int max_gf_interval;
|
||||
int static_scene_max_gf_interval;
|
||||
int baseline_gf_interval;
|
||||
int constrained_gf_group;
|
||||
int frames_to_key;
|
||||
int frames_since_key;
|
||||
int this_key_frame_forced;
|
||||
int next_key_frame_forced;
|
||||
int source_alt_ref_pending;
|
||||
int source_alt_ref_active;
|
||||
int is_src_frame_alt_ref;
|
||||
|
||||
int avg_frame_bandwidth; // Average frame size target for clip
|
||||
int min_frame_bandwidth; // Minimum allocation used for any frame
|
||||
int max_frame_bandwidth; // Maximum burst rate allowed for a frame.
|
||||
|
||||
int ni_av_qi;
|
||||
int ni_tot_qi;
|
||||
int ni_frames;
|
||||
int avg_frame_qindex[FRAME_TYPES];
|
||||
double tot_q;
|
||||
double avg_q;
|
||||
|
||||
int64_t buffer_level;
|
||||
int64_t bits_off_target;
|
||||
int64_t vbr_bits_off_target;
|
||||
int64_t vbr_bits_off_target_fast;
|
||||
|
||||
int decimation_factor;
|
||||
int decimation_count;
|
||||
|
||||
int rolling_target_bits;
|
||||
int rolling_actual_bits;
|
||||
|
||||
int long_rolling_target_bits;
|
||||
int long_rolling_actual_bits;
|
||||
|
||||
int rate_error_estimate;
|
||||
|
||||
int64_t total_actual_bits;
|
||||
int64_t total_target_bits;
|
||||
int64_t total_target_vs_actual;
|
||||
|
||||
int worst_quality;
|
||||
int best_quality;
|
||||
|
||||
int64_t starting_buffer_level;
|
||||
int64_t optimal_buffer_level;
|
||||
int64_t maximum_buffer_size;
|
||||
|
||||
// rate control history for last frame(1) and the frame before(2).
|
||||
// -1: undershot
|
||||
// 1: overshoot
|
||||
// 0: not initialized.
|
||||
int rc_1_frame;
|
||||
int rc_2_frame;
|
||||
int q_1_frame;
|
||||
int q_2_frame;
|
||||
// Keep track of the last target average frame bandwidth.
|
||||
int last_avg_frame_bandwidth;
|
||||
|
||||
// Auto frame-scaling variables.
|
||||
FRAME_SCALE_LEVEL frame_size_selector;
|
||||
FRAME_SCALE_LEVEL next_frame_size_selector;
|
||||
int frame_width[FRAME_SCALE_STEPS];
|
||||
int frame_height[FRAME_SCALE_STEPS];
|
||||
int rf_level_maxq[RATE_FACTOR_LEVELS];
|
||||
|
||||
int fac_active_worst_inter;
|
||||
int fac_active_worst_gf;
|
||||
uint64_t avg_source_sad[MAX_LAG_BUFFERS];
|
||||
uint64_t prev_avg_source_sad_lag;
|
||||
int high_source_sad_lagindex;
|
||||
int high_num_blocks_with_motion;
|
||||
int alt_ref_gf_group;
|
||||
int last_frame_is_src_altref;
|
||||
int high_source_sad;
|
||||
int count_last_scene_change;
|
||||
int hybrid_intra_scene_change;
|
||||
int re_encode_maxq_scene_change;
|
||||
int avg_frame_low_motion;
|
||||
int af_ratio_onepass_vbr;
|
||||
int force_qpmin;
|
||||
int reset_high_source_sad;
|
||||
double perc_arf_usage;
|
||||
int force_max_q;
|
||||
// Last frame was dropped post encode on scene change.
|
||||
int last_post_encode_dropped_scene_change;
|
||||
// Enable post encode frame dropping for screen content. Only enabled when
|
||||
// ext_use_post_encode_drop is enabled by user.
|
||||
int use_post_encode_drop;
|
||||
// External flag to enable post encode frame dropping, controlled by user.
|
||||
int ext_use_post_encode_drop;
|
||||
|
||||
int damped_adjustment[RATE_FACTOR_LEVELS];
|
||||
double arf_active_best_quality_adjustment_factor;
|
||||
int arf_increase_active_best_quality;
|
||||
|
||||
int preserve_arf_as_gld;
|
||||
int preserve_next_arf_as_gld;
|
||||
int show_arf_as_gld;
|
||||
} RATE_CONTROL;
|
||||
|
||||
struct VP9_COMP;
|
||||
struct VP9EncoderConfig;
|
||||
|
||||
void vp9_rc_init(const struct VP9EncoderConfig *oxcf, int pass,
|
||||
RATE_CONTROL *rc);
|
||||
|
||||
int vp9_estimate_bits_at_q(FRAME_TYPE frame_type, int q, int mbs,
|
||||
double correction_factor, vpx_bit_depth_t bit_depth);
|
||||
|
||||
double vp9_convert_qindex_to_q(int qindex, vpx_bit_depth_t bit_depth);
|
||||
|
||||
int vp9_convert_q_to_qindex(double q_val, vpx_bit_depth_t bit_depth);
|
||||
|
||||
void vp9_rc_init_minq_luts(void);
|
||||
|
||||
int vp9_rc_get_default_min_gf_interval(int width, int height, double framerate);
|
||||
// Note vp9_rc_get_default_max_gf_interval() requires the min_gf_interval to
|
||||
// be passed in to ensure that the max_gf_interval returned is at least as big
|
||||
// as that.
|
||||
int vp9_rc_get_default_max_gf_interval(double framerate, int min_gf_interval);
|
||||
|
||||
// Generally at the high level, the following flow is expected
|
||||
// to be enforced for rate control:
|
||||
// First call per frame, one of:
|
||||
// vp9_rc_get_one_pass_vbr_params()
|
||||
// vp9_rc_get_one_pass_cbr_params()
|
||||
// vp9_rc_get_svc_params()
|
||||
// vp9_rc_get_first_pass_params()
|
||||
// vp9_rc_get_second_pass_params()
|
||||
// depending on the usage to set the rate control encode parameters desired.
|
||||
//
|
||||
// Then, call encode_frame_to_data_rate() to perform the
|
||||
// actual encode. This function will in turn call encode_frame()
|
||||
// one or more times, followed by one of:
|
||||
// vp9_rc_postencode_update()
|
||||
// vp9_rc_postencode_update_drop_frame()
|
||||
//
|
||||
// The majority of rate control parameters are only expected
|
||||
// to be set in the vp9_rc_get_..._params() functions and
|
||||
// updated during the vp9_rc_postencode_update...() functions.
|
||||
// The only exceptions are vp9_rc_drop_frame() and
|
||||
// vp9_rc_update_rate_correction_factors() functions.
|
||||
|
||||
// Functions to set parameters for encoding before the actual
|
||||
// encode_frame_to_data_rate() function.
|
||||
void vp9_rc_get_one_pass_vbr_params(struct VP9_COMP *cpi);
|
||||
void vp9_rc_get_one_pass_cbr_params(struct VP9_COMP *cpi);
|
||||
void vp9_rc_get_svc_params(struct VP9_COMP *cpi);
|
||||
|
||||
// Post encode update of the rate control parameters based
|
||||
// on bytes used
|
||||
void vp9_rc_postencode_update(struct VP9_COMP *cpi, uint64_t bytes_used);
|
||||
// Post encode update of the rate control parameters for dropped frames
|
||||
void vp9_rc_postencode_update_drop_frame(struct VP9_COMP *cpi);
|
||||
|
||||
// Updates rate correction factors
|
||||
// Changes only the rate correction factors in the rate control structure.
|
||||
void vp9_rc_update_rate_correction_factors(struct VP9_COMP *cpi);
|
||||
|
||||
// Post encode drop for CBR mode.
|
||||
int post_encode_drop_cbr(struct VP9_COMP *cpi, size_t *size);
|
||||
|
||||
int vp9_test_drop(struct VP9_COMP *cpi);
|
||||
|
||||
// Decide if we should drop this frame: For 1-pass CBR.
|
||||
// Changes only the decimation count in the rate control structure
|
||||
int vp9_rc_drop_frame(struct VP9_COMP *cpi);
|
||||
|
||||
// Computes frame size bounds.
|
||||
void vp9_rc_compute_frame_size_bounds(const struct VP9_COMP *cpi,
|
||||
int frame_target,
|
||||
int *frame_under_shoot_limit,
|
||||
int *frame_over_shoot_limit);
|
||||
|
||||
// Picks q and q bounds given the target for bits
|
||||
int vp9_rc_pick_q_and_bounds(const struct VP9_COMP *cpi, int *bottom_index,
|
||||
int *top_index);
|
||||
|
||||
// Estimates q to achieve a target bits per frame
|
||||
int vp9_rc_regulate_q(const struct VP9_COMP *cpi, int target_bits_per_frame,
|
||||
int active_best_quality, int active_worst_quality);
|
||||
|
||||
// Estimates bits per mb for a given qindex and correction factor.
|
||||
int vp9_rc_bits_per_mb(FRAME_TYPE frame_type, int qindex,
|
||||
double correction_factor, vpx_bit_depth_t bit_depth);
|
||||
|
||||
// Clamping utilities for bitrate targets for iframes and pframes.
|
||||
int vp9_rc_clamp_iframe_target_size(const struct VP9_COMP *const cpi,
|
||||
int target);
|
||||
int vp9_rc_clamp_pframe_target_size(const struct VP9_COMP *const cpi,
|
||||
int target);
|
||||
// Utility to set frame_target into the RATE_CONTROL structure
|
||||
// This function is called only from the vp9_rc_get_..._params() functions.
|
||||
void vp9_rc_set_frame_target(struct VP9_COMP *cpi, int target);
|
||||
|
||||
// Computes a q delta (in "q index" terms) to get from a starting q value
|
||||
// to a target q value
|
||||
int vp9_compute_qdelta(const RATE_CONTROL *rc, double qstart, double qtarget,
|
||||
vpx_bit_depth_t bit_depth);
|
||||
|
||||
// Computes a q delta (in "q index" terms) to get from a starting q value
|
||||
// to a value that should equate to the given rate ratio.
|
||||
int vp9_compute_qdelta_by_rate(const RATE_CONTROL *rc, FRAME_TYPE frame_type,
|
||||
int qindex, double rate_target_ratio,
|
||||
vpx_bit_depth_t bit_depth);
|
||||
|
||||
int vp9_frame_type_qdelta(const struct VP9_COMP *cpi, int rf_level, int q);
|
||||
|
||||
void vp9_rc_update_framerate(struct VP9_COMP *cpi);
|
||||
|
||||
void vp9_rc_set_gf_interval_range(const struct VP9_COMP *const cpi,
|
||||
RATE_CONTROL *const rc);
|
||||
|
||||
void vp9_set_target_rate(struct VP9_COMP *cpi);
|
||||
|
||||
int vp9_resize_one_pass_cbr(struct VP9_COMP *cpi);
|
||||
|
||||
void vp9_scene_detection_onepass(struct VP9_COMP *cpi);
|
||||
|
||||
int vp9_encodedframe_overshoot(struct VP9_COMP *cpi, int frame_size, int *q);
|
||||
|
||||
void vp9_configure_buffer_updates(struct VP9_COMP *cpi, int gf_group_index);
|
||||
|
||||
void vp9_estimate_qp_gop(struct VP9_COMP *cpi);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_ENCODER_VP9_RATECTRL_H_
|
||||
@@ -0,0 +1,775 @@
|
||||
/*
|
||||
* Copyright (c) 2010 The WebM project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "./vp9_rtcd.h"
|
||||
|
||||
#include "vpx_dsp/vpx_dsp_common.h"
|
||||
#include "vpx_mem/vpx_mem.h"
|
||||
#include "vpx_ports/bitops.h"
|
||||
#include "vpx_ports/mem.h"
|
||||
#include "vpx_ports/system_state.h"
|
||||
|
||||
#include "vp9/common/vp9_common.h"
|
||||
#include "vp9/common/vp9_entropy.h"
|
||||
#include "vp9/common/vp9_entropymode.h"
|
||||
#include "vp9/common/vp9_mvref_common.h"
|
||||
#include "vp9/common/vp9_pred_common.h"
|
||||
#include "vp9/common/vp9_quant_common.h"
|
||||
#include "vp9/common/vp9_reconinter.h"
|
||||
#include "vp9/common/vp9_reconintra.h"
|
||||
#include "vp9/common/vp9_seg_common.h"
|
||||
|
||||
#include "vp9/encoder/vp9_cost.h"
|
||||
#include "vp9/encoder/vp9_encodemb.h"
|
||||
#include "vp9/encoder/vp9_encodemv.h"
|
||||
#include "vp9/encoder/vp9_encoder.h"
|
||||
#include "vp9/encoder/vp9_mcomp.h"
|
||||
#include "vp9/encoder/vp9_quantize.h"
|
||||
#include "vp9/encoder/vp9_ratectrl.h"
|
||||
#include "vp9/encoder/vp9_rd.h"
|
||||
#include "vp9/encoder/vp9_tokenize.h"
|
||||
|
||||
#define RD_THRESH_POW 1.25
|
||||
|
||||
// Factor to weigh the rate for switchable interp filters.
|
||||
#define SWITCHABLE_INTERP_RATE_FACTOR 1
|
||||
|
||||
void vp9_rd_cost_reset(RD_COST *rd_cost) {
|
||||
rd_cost->rate = INT_MAX;
|
||||
rd_cost->dist = INT64_MAX;
|
||||
rd_cost->rdcost = INT64_MAX;
|
||||
}
|
||||
|
||||
void vp9_rd_cost_init(RD_COST *rd_cost) {
|
||||
rd_cost->rate = 0;
|
||||
rd_cost->dist = 0;
|
||||
rd_cost->rdcost = 0;
|
||||
}
|
||||
|
||||
int64_t vp9_calculate_rd_cost(int mult, int div, int rate, int64_t dist) {
|
||||
assert(mult >= 0);
|
||||
assert(div > 0);
|
||||
if (rate >= 0 && dist >= 0) {
|
||||
return RDCOST(mult, div, rate, dist);
|
||||
}
|
||||
if (rate >= 0 && dist < 0) {
|
||||
return RDCOST_NEG_D(mult, div, rate, -dist);
|
||||
}
|
||||
if (rate < 0 && dist >= 0) {
|
||||
return RDCOST_NEG_R(mult, div, -rate, dist);
|
||||
}
|
||||
return -RDCOST(mult, div, -rate, -dist);
|
||||
}
|
||||
|
||||
void vp9_rd_cost_update(int mult, int div, RD_COST *rd_cost) {
|
||||
if (rd_cost->rate < INT_MAX && rd_cost->dist < INT64_MAX) {
|
||||
rd_cost->rdcost =
|
||||
vp9_calculate_rd_cost(mult, div, rd_cost->rate, rd_cost->dist);
|
||||
} else {
|
||||
vp9_rd_cost_reset(rd_cost);
|
||||
}
|
||||
}
|
||||
|
||||
// The baseline rd thresholds for breaking out of the rd loop for
|
||||
// certain modes are assumed to be based on 8x8 blocks.
|
||||
// This table is used to correct for block size.
|
||||
// The factors here are << 2 (2 = x0.5, 32 = x8 etc).
|
||||
static const uint8_t rd_thresh_block_size_factor[BLOCK_SIZES] = {
|
||||
2, 3, 3, 4, 6, 6, 8, 12, 12, 16, 24, 24, 32
|
||||
};
|
||||
|
||||
static void fill_mode_costs(VP9_COMP *cpi) {
|
||||
const FRAME_CONTEXT *const fc = cpi->common.fc;
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < INTRA_MODES; ++i) {
|
||||
for (j = 0; j < INTRA_MODES; ++j) {
|
||||
vp9_cost_tokens(cpi->y_mode_costs[i][j], vp9_kf_y_mode_prob[i][j],
|
||||
vp9_intra_mode_tree);
|
||||
}
|
||||
}
|
||||
|
||||
vp9_cost_tokens(cpi->mbmode_cost, fc->y_mode_prob[1], vp9_intra_mode_tree);
|
||||
for (i = 0; i < INTRA_MODES; ++i) {
|
||||
vp9_cost_tokens(cpi->intra_uv_mode_cost[KEY_FRAME][i],
|
||||
vp9_kf_uv_mode_prob[i], vp9_intra_mode_tree);
|
||||
vp9_cost_tokens(cpi->intra_uv_mode_cost[INTER_FRAME][i],
|
||||
fc->uv_mode_prob[i], vp9_intra_mode_tree);
|
||||
}
|
||||
|
||||
for (i = 0; i < SWITCHABLE_FILTER_CONTEXTS; ++i) {
|
||||
vp9_cost_tokens(cpi->switchable_interp_costs[i],
|
||||
fc->switchable_interp_prob[i], vp9_switchable_interp_tree);
|
||||
}
|
||||
|
||||
for (i = TX_8X8; i < TX_SIZES; ++i) {
|
||||
for (j = 0; j < TX_SIZE_CONTEXTS; ++j) {
|
||||
const vpx_prob *tx_probs = get_tx_probs(i, j, &fc->tx_probs);
|
||||
int k;
|
||||
for (k = 0; k <= i; ++k) {
|
||||
int cost = 0;
|
||||
int m;
|
||||
for (m = 0; m <= k - (k == i); ++m) {
|
||||
if (m == k)
|
||||
cost += vp9_cost_zero(tx_probs[m]);
|
||||
else
|
||||
cost += vp9_cost_one(tx_probs[m]);
|
||||
}
|
||||
cpi->tx_size_cost[i - 1][j][k] = cost;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void fill_token_costs(vp9_coeff_cost *c,
|
||||
vp9_coeff_probs_model (*p)[PLANE_TYPES]) {
|
||||
int i, j, k, l;
|
||||
TX_SIZE t;
|
||||
for (t = TX_4X4; t <= TX_32X32; ++t)
|
||||
for (i = 0; i < PLANE_TYPES; ++i)
|
||||
for (j = 0; j < REF_TYPES; ++j)
|
||||
for (k = 0; k < COEF_BANDS; ++k)
|
||||
for (l = 0; l < BAND_COEFF_CONTEXTS(k); ++l) {
|
||||
vpx_prob probs[ENTROPY_NODES];
|
||||
vp9_model_to_full_probs(p[t][i][j][k][l], probs);
|
||||
vp9_cost_tokens((int *)c[t][i][j][k][0][l], probs, vp9_coef_tree);
|
||||
vp9_cost_tokens_skip((int *)c[t][i][j][k][1][l], probs,
|
||||
vp9_coef_tree);
|
||||
assert(c[t][i][j][k][0][l][EOB_TOKEN] ==
|
||||
c[t][i][j][k][1][l][EOB_TOKEN]);
|
||||
}
|
||||
}
|
||||
|
||||
// Values are now correlated to quantizer.
|
||||
static int sad_per_bit16lut_8[QINDEX_RANGE];
|
||||
static int sad_per_bit4lut_8[QINDEX_RANGE];
|
||||
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
static int sad_per_bit16lut_10[QINDEX_RANGE];
|
||||
static int sad_per_bit4lut_10[QINDEX_RANGE];
|
||||
static int sad_per_bit16lut_12[QINDEX_RANGE];
|
||||
static int sad_per_bit4lut_12[QINDEX_RANGE];
|
||||
#endif
|
||||
|
||||
static void init_me_luts_bd(int *bit16lut, int *bit4lut, int range,
|
||||
vpx_bit_depth_t bit_depth) {
|
||||
int i;
|
||||
// Initialize the sad lut tables using a formulaic calculation for now.
|
||||
// This is to make it easier to resolve the impact of experimental changes
|
||||
// to the quantizer tables.
|
||||
for (i = 0; i < range; i++) {
|
||||
const double q = vp9_convert_qindex_to_q(i, bit_depth);
|
||||
bit16lut[i] = (int)(0.0418 * q + 2.4107);
|
||||
bit4lut[i] = (int)(0.063 * q + 2.742);
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_init_me_luts(void) {
|
||||
init_me_luts_bd(sad_per_bit16lut_8, sad_per_bit4lut_8, QINDEX_RANGE,
|
||||
VPX_BITS_8);
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
init_me_luts_bd(sad_per_bit16lut_10, sad_per_bit4lut_10, QINDEX_RANGE,
|
||||
VPX_BITS_10);
|
||||
init_me_luts_bd(sad_per_bit16lut_12, sad_per_bit4lut_12, QINDEX_RANGE,
|
||||
VPX_BITS_12);
|
||||
#endif
|
||||
}
|
||||
|
||||
static const int rd_boost_factor[16] = { 64, 32, 32, 32, 24, 16, 12, 12,
|
||||
8, 8, 4, 4, 2, 2, 1, 0 };
|
||||
|
||||
// Note that the element below for frame type "USE_BUF_FRAME", which indicates
|
||||
// that the show frame flag is set, should not be used as no real frame
|
||||
// is encoded so we should not reach here. However, a dummy value
|
||||
// is inserted here to make sure the data structure has the right number
|
||||
// of values assigned.
|
||||
static const int rd_frame_type_factor[FRAME_UPDATE_TYPES] = { 128, 144, 128,
|
||||
128, 144, 144 };
|
||||
|
||||
int vp9_compute_rd_mult_based_on_qindex(const VP9_COMP *cpi, int qindex) {
|
||||
// largest dc_quant is 21387, therefore rdmult should always fit in int32_t
|
||||
const int q = vp9_dc_quant(qindex, 0, cpi->common.bit_depth);
|
||||
uint32_t rdmult = q * q;
|
||||
|
||||
if (cpi->common.frame_type != KEY_FRAME) {
|
||||
if (qindex < 128)
|
||||
rdmult = rdmult * 4;
|
||||
else if (qindex < 190)
|
||||
rdmult = rdmult * 4 + rdmult / 2;
|
||||
else
|
||||
rdmult = rdmult * 3;
|
||||
} else {
|
||||
if (qindex < 64)
|
||||
rdmult = rdmult * 4;
|
||||
else if (qindex <= 128)
|
||||
rdmult = rdmult * 3 + rdmult / 2;
|
||||
else if (qindex < 190)
|
||||
rdmult = rdmult * 4 + rdmult / 2;
|
||||
else
|
||||
rdmult = rdmult * 7 + rdmult / 2;
|
||||
}
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
switch (cpi->common.bit_depth) {
|
||||
case VPX_BITS_10: rdmult = ROUND_POWER_OF_TWO(rdmult, 4); break;
|
||||
case VPX_BITS_12: rdmult = ROUND_POWER_OF_TWO(rdmult, 8); break;
|
||||
default: break;
|
||||
}
|
||||
#endif // CONFIG_VP9_HIGHBITDEPTH
|
||||
return rdmult > 0 ? rdmult : 1;
|
||||
}
|
||||
|
||||
static int modulate_rdmult(const VP9_COMP *cpi, int rdmult) {
|
||||
int64_t rdmult_64 = rdmult;
|
||||
if (cpi->oxcf.pass == 2 && (cpi->common.frame_type != KEY_FRAME)) {
|
||||
const GF_GROUP *const gf_group = &cpi->twopass.gf_group;
|
||||
const FRAME_UPDATE_TYPE frame_type = gf_group->update_type[gf_group->index];
|
||||
const int gfu_boost = cpi->multi_layer_arf
|
||||
? gf_group->gfu_boost[gf_group->index]
|
||||
: cpi->rc.gfu_boost;
|
||||
const int boost_index = VPXMIN(15, (gfu_boost / 100));
|
||||
|
||||
rdmult_64 = (rdmult_64 * rd_frame_type_factor[frame_type]) >> 7;
|
||||
rdmult_64 += ((rdmult_64 * rd_boost_factor[boost_index]) >> 7);
|
||||
}
|
||||
return (int)rdmult_64;
|
||||
}
|
||||
|
||||
int vp9_compute_rd_mult(const VP9_COMP *cpi, int qindex) {
|
||||
int rdmult = vp9_compute_rd_mult_based_on_qindex(cpi, qindex);
|
||||
return modulate_rdmult(cpi, rdmult);
|
||||
}
|
||||
|
||||
int vp9_get_adaptive_rdmult(const VP9_COMP *cpi, double beta) {
|
||||
int rdmult =
|
||||
vp9_compute_rd_mult_based_on_qindex(cpi, cpi->common.base_qindex);
|
||||
rdmult = (int)((double)rdmult / beta);
|
||||
rdmult = rdmult > 0 ? rdmult : 1;
|
||||
return modulate_rdmult(cpi, rdmult);
|
||||
}
|
||||
|
||||
static int compute_rd_thresh_factor(int qindex, vpx_bit_depth_t bit_depth) {
|
||||
double q;
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
switch (bit_depth) {
|
||||
case VPX_BITS_8: q = vp9_dc_quant(qindex, 0, VPX_BITS_8) / 4.0; break;
|
||||
case VPX_BITS_10: q = vp9_dc_quant(qindex, 0, VPX_BITS_10) / 16.0; break;
|
||||
default:
|
||||
assert(bit_depth == VPX_BITS_12);
|
||||
q = vp9_dc_quant(qindex, 0, VPX_BITS_12) / 64.0;
|
||||
break;
|
||||
}
|
||||
#else
|
||||
(void)bit_depth;
|
||||
q = vp9_dc_quant(qindex, 0, VPX_BITS_8) / 4.0;
|
||||
#endif // CONFIG_VP9_HIGHBITDEPTH
|
||||
// TODO(debargha): Adjust the function below.
|
||||
return VPXMAX((int)(pow(q, RD_THRESH_POW) * 5.12), 8);
|
||||
}
|
||||
|
||||
void vp9_initialize_me_consts(VP9_COMP *cpi, MACROBLOCK *x, int qindex) {
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
switch (cpi->common.bit_depth) {
|
||||
case VPX_BITS_8:
|
||||
x->sadperbit16 = sad_per_bit16lut_8[qindex];
|
||||
x->sadperbit4 = sad_per_bit4lut_8[qindex];
|
||||
break;
|
||||
case VPX_BITS_10:
|
||||
x->sadperbit16 = sad_per_bit16lut_10[qindex];
|
||||
x->sadperbit4 = sad_per_bit4lut_10[qindex];
|
||||
break;
|
||||
default:
|
||||
assert(cpi->common.bit_depth == VPX_BITS_12);
|
||||
x->sadperbit16 = sad_per_bit16lut_12[qindex];
|
||||
x->sadperbit4 = sad_per_bit4lut_12[qindex];
|
||||
break;
|
||||
}
|
||||
#else
|
||||
(void)cpi;
|
||||
x->sadperbit16 = sad_per_bit16lut_8[qindex];
|
||||
x->sadperbit4 = sad_per_bit4lut_8[qindex];
|
||||
#endif // CONFIG_VP9_HIGHBITDEPTH
|
||||
}
|
||||
|
||||
static void set_block_thresholds(const VP9_COMMON *cm, RD_OPT *rd) {
|
||||
int i, bsize, segment_id;
|
||||
|
||||
for (segment_id = 0; segment_id < MAX_SEGMENTS; ++segment_id) {
|
||||
const int qindex =
|
||||
clamp(vp9_get_qindex(&cm->seg, segment_id, cm->base_qindex) +
|
||||
cm->y_dc_delta_q,
|
||||
0, MAXQ);
|
||||
const int q = compute_rd_thresh_factor(qindex, cm->bit_depth);
|
||||
|
||||
for (bsize = 0; bsize < BLOCK_SIZES; ++bsize) {
|
||||
// Threshold here seems unnecessarily harsh but fine given actual
|
||||
// range of values used for cpi->sf.thresh_mult[].
|
||||
const int t = q * rd_thresh_block_size_factor[bsize];
|
||||
const int thresh_max = INT_MAX / t;
|
||||
|
||||
if (bsize >= BLOCK_8X8) {
|
||||
for (i = 0; i < MAX_MODES; ++i)
|
||||
rd->threshes[segment_id][bsize][i] = rd->thresh_mult[i] < thresh_max
|
||||
? rd->thresh_mult[i] * t / 4
|
||||
: INT_MAX;
|
||||
} else {
|
||||
for (i = 0; i < MAX_REFS; ++i)
|
||||
rd->threshes[segment_id][bsize][i] =
|
||||
rd->thresh_mult_sub8x8[i] < thresh_max
|
||||
? rd->thresh_mult_sub8x8[i] * t / 4
|
||||
: INT_MAX;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_build_inter_mode_cost(VP9_COMP *cpi) {
|
||||
const VP9_COMMON *const cm = &cpi->common;
|
||||
int i;
|
||||
for (i = 0; i < INTER_MODE_CONTEXTS; ++i) {
|
||||
vp9_cost_tokens((int *)cpi->inter_mode_cost[i], cm->fc->inter_mode_probs[i],
|
||||
vp9_inter_mode_tree);
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_initialize_rd_consts(VP9_COMP *cpi) {
|
||||
VP9_COMMON *const cm = &cpi->common;
|
||||
MACROBLOCK *const x = &cpi->td.mb;
|
||||
MACROBLOCKD *const xd = &cpi->td.mb.e_mbd;
|
||||
RD_OPT *const rd = &cpi->rd;
|
||||
int i;
|
||||
|
||||
vpx_clear_system_state();
|
||||
|
||||
rd->RDDIV = RDDIV_BITS; // In bits (to multiply D by 128).
|
||||
rd->RDMULT = vp9_compute_rd_mult(cpi, cm->base_qindex + cm->y_dc_delta_q);
|
||||
|
||||
set_error_per_bit(x, rd->RDMULT);
|
||||
|
||||
x->select_tx_size = (cpi->sf.tx_size_search_method == USE_LARGESTALL &&
|
||||
cm->frame_type != KEY_FRAME)
|
||||
? 0
|
||||
: 1;
|
||||
|
||||
set_block_thresholds(cm, rd);
|
||||
set_partition_probs(cm, xd);
|
||||
|
||||
if (cpi->oxcf.pass == 1) {
|
||||
if (!frame_is_intra_only(cm))
|
||||
vp9_build_nmv_cost_table(
|
||||
x->nmvjointcost,
|
||||
cm->allow_high_precision_mv ? x->nmvcost_hp : x->nmvcost,
|
||||
&cm->fc->nmvc, cm->allow_high_precision_mv);
|
||||
} else {
|
||||
if (!cpi->sf.use_nonrd_pick_mode || cm->frame_type == KEY_FRAME)
|
||||
fill_token_costs(x->token_costs, cm->fc->coef_probs);
|
||||
|
||||
if (cpi->sf.partition_search_type != VAR_BASED_PARTITION ||
|
||||
cm->frame_type == KEY_FRAME) {
|
||||
for (i = 0; i < PARTITION_CONTEXTS; ++i)
|
||||
vp9_cost_tokens(cpi->partition_cost[i], get_partition_probs(xd, i),
|
||||
vp9_partition_tree);
|
||||
}
|
||||
|
||||
if (!cpi->sf.use_nonrd_pick_mode || (cm->current_video_frame & 0x07) == 1 ||
|
||||
cm->frame_type == KEY_FRAME) {
|
||||
fill_mode_costs(cpi);
|
||||
|
||||
if (!frame_is_intra_only(cm)) {
|
||||
vp9_build_nmv_cost_table(
|
||||
x->nmvjointcost,
|
||||
cm->allow_high_precision_mv ? x->nmvcost_hp : x->nmvcost,
|
||||
&cm->fc->nmvc, cm->allow_high_precision_mv);
|
||||
vp9_build_inter_mode_cost(cpi);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: The tables below must be of the same size.
|
||||
|
||||
// The functions described below are sampled at the four most significant
|
||||
// bits of x^2 + 8 / 256.
|
||||
|
||||
// Normalized rate:
|
||||
// This table models the rate for a Laplacian source with given variance
|
||||
// when quantized with a uniform quantizer with given stepsize. The
|
||||
// closed form expression is:
|
||||
// Rn(x) = H(sqrt(r)) + sqrt(r)*[1 + H(r)/(1 - r)],
|
||||
// where r = exp(-sqrt(2) * x) and x = qpstep / sqrt(variance),
|
||||
// and H(x) is the binary entropy function.
|
||||
static const int rate_tab_q10[] = {
|
||||
65536, 6086, 5574, 5275, 5063, 4899, 4764, 4651, 4553, 4389, 4255, 4142, 4044,
|
||||
3958, 3881, 3811, 3748, 3635, 3538, 3453, 3376, 3307, 3244, 3186, 3133, 3037,
|
||||
2952, 2877, 2809, 2747, 2690, 2638, 2589, 2501, 2423, 2353, 2290, 2232, 2179,
|
||||
2130, 2084, 2001, 1928, 1862, 1802, 1748, 1698, 1651, 1608, 1530, 1460, 1398,
|
||||
1342, 1290, 1243, 1199, 1159, 1086, 1021, 963, 911, 864, 821, 781, 745,
|
||||
680, 623, 574, 530, 490, 455, 424, 395, 345, 304, 269, 239, 213,
|
||||
190, 171, 154, 126, 104, 87, 73, 61, 52, 44, 38, 28, 21,
|
||||
16, 12, 10, 8, 6, 5, 3, 2, 1, 1, 1, 0, 0,
|
||||
};
|
||||
|
||||
// Normalized distortion:
|
||||
// This table models the normalized distortion for a Laplacian source
|
||||
// with given variance when quantized with a uniform quantizer
|
||||
// with given stepsize. The closed form expression is:
|
||||
// Dn(x) = 1 - 1/sqrt(2) * x / sinh(x/sqrt(2))
|
||||
// where x = qpstep / sqrt(variance).
|
||||
// Note the actual distortion is Dn * variance.
|
||||
static const int dist_tab_q10[] = {
|
||||
0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 4, 5, 5,
|
||||
6, 7, 7, 8, 9, 11, 12, 13, 15, 16, 17, 18, 21,
|
||||
24, 26, 29, 31, 34, 36, 39, 44, 49, 54, 59, 64, 69,
|
||||
73, 78, 88, 97, 106, 115, 124, 133, 142, 151, 167, 184, 200,
|
||||
215, 231, 245, 260, 274, 301, 327, 351, 375, 397, 418, 439, 458,
|
||||
495, 528, 559, 587, 613, 637, 659, 680, 717, 749, 777, 801, 823,
|
||||
842, 859, 874, 899, 919, 936, 949, 960, 969, 977, 983, 994, 1001,
|
||||
1006, 1010, 1013, 1015, 1017, 1018, 1020, 1022, 1022, 1023, 1023, 1023, 1024,
|
||||
};
|
||||
static const int xsq_iq_q10[] = {
|
||||
0, 4, 8, 12, 16, 20, 24, 28, 32,
|
||||
40, 48, 56, 64, 72, 80, 88, 96, 112,
|
||||
128, 144, 160, 176, 192, 208, 224, 256, 288,
|
||||
320, 352, 384, 416, 448, 480, 544, 608, 672,
|
||||
736, 800, 864, 928, 992, 1120, 1248, 1376, 1504,
|
||||
1632, 1760, 1888, 2016, 2272, 2528, 2784, 3040, 3296,
|
||||
3552, 3808, 4064, 4576, 5088, 5600, 6112, 6624, 7136,
|
||||
7648, 8160, 9184, 10208, 11232, 12256, 13280, 14304, 15328,
|
||||
16352, 18400, 20448, 22496, 24544, 26592, 28640, 30688, 32736,
|
||||
36832, 40928, 45024, 49120, 53216, 57312, 61408, 65504, 73696,
|
||||
81888, 90080, 98272, 106464, 114656, 122848, 131040, 147424, 163808,
|
||||
180192, 196576, 212960, 229344, 245728,
|
||||
};
|
||||
|
||||
static void model_rd_norm(int xsq_q10, int *r_q10, int *d_q10) {
|
||||
const int tmp = (xsq_q10 >> 2) + 8;
|
||||
const int k = get_msb(tmp) - 3;
|
||||
const int xq = (k << 3) + ((tmp >> k) & 0x7);
|
||||
const int one_q10 = 1 << 10;
|
||||
const int a_q10 = ((xsq_q10 - xsq_iq_q10[xq]) << 10) >> (2 + k);
|
||||
const int b_q10 = one_q10 - a_q10;
|
||||
*r_q10 = (rate_tab_q10[xq] * b_q10 + rate_tab_q10[xq + 1] * a_q10) >> 10;
|
||||
*d_q10 = (dist_tab_q10[xq] * b_q10 + dist_tab_q10[xq + 1] * a_q10) >> 10;
|
||||
}
|
||||
|
||||
static void model_rd_norm_vec(int xsq_q10[MAX_MB_PLANE],
|
||||
int r_q10[MAX_MB_PLANE],
|
||||
int d_q10[MAX_MB_PLANE]) {
|
||||
int i;
|
||||
const int one_q10 = 1 << 10;
|
||||
for (i = 0; i < MAX_MB_PLANE; ++i) {
|
||||
const int tmp = (xsq_q10[i] >> 2) + 8;
|
||||
const int k = get_msb(tmp) - 3;
|
||||
const int xq = (k << 3) + ((tmp >> k) & 0x7);
|
||||
const int a_q10 = ((xsq_q10[i] - xsq_iq_q10[xq]) << 10) >> (2 + k);
|
||||
const int b_q10 = one_q10 - a_q10;
|
||||
r_q10[i] = (rate_tab_q10[xq] * b_q10 + rate_tab_q10[xq + 1] * a_q10) >> 10;
|
||||
d_q10[i] = (dist_tab_q10[xq] * b_q10 + dist_tab_q10[xq + 1] * a_q10) >> 10;
|
||||
}
|
||||
}
|
||||
|
||||
static const uint32_t MAX_XSQ_Q10 = 245727;
|
||||
|
||||
void vp9_model_rd_from_var_lapndz(unsigned int var, unsigned int n_log2,
|
||||
unsigned int qstep, int *rate,
|
||||
int64_t *dist) {
|
||||
// This function models the rate and distortion for a Laplacian
|
||||
// source with given variance when quantized with a uniform quantizer
|
||||
// with given stepsize. The closed form expressions are in:
|
||||
// Hang and Chen, "Source Model for transform video coder and its
|
||||
// application - Part I: Fundamental Theory", IEEE Trans. Circ.
|
||||
// Sys. for Video Tech., April 1997.
|
||||
if (var == 0) {
|
||||
*rate = 0;
|
||||
*dist = 0;
|
||||
} else {
|
||||
int d_q10, r_q10;
|
||||
const uint64_t xsq_q10_64 =
|
||||
(((uint64_t)qstep * qstep << (n_log2 + 10)) + (var >> 1)) / var;
|
||||
const int xsq_q10 = (int)VPXMIN(xsq_q10_64, MAX_XSQ_Q10);
|
||||
model_rd_norm(xsq_q10, &r_q10, &d_q10);
|
||||
*rate = ROUND_POWER_OF_TWO(r_q10 << n_log2, 10 - VP9_PROB_COST_SHIFT);
|
||||
*dist = (var * (int64_t)d_q10 + 512) >> 10;
|
||||
}
|
||||
}
|
||||
|
||||
// Implements a fixed length vector form of vp9_model_rd_from_var_lapndz where
|
||||
// vectors are of length MAX_MB_PLANE and all elements of var are non-zero.
|
||||
void vp9_model_rd_from_var_lapndz_vec(unsigned int var[MAX_MB_PLANE],
|
||||
unsigned int n_log2[MAX_MB_PLANE],
|
||||
unsigned int qstep[MAX_MB_PLANE],
|
||||
int64_t *rate_sum, int64_t *dist_sum) {
|
||||
int i;
|
||||
int xsq_q10[MAX_MB_PLANE], d_q10[MAX_MB_PLANE], r_q10[MAX_MB_PLANE];
|
||||
for (i = 0; i < MAX_MB_PLANE; ++i) {
|
||||
const uint64_t xsq_q10_64 =
|
||||
(((uint64_t)qstep[i] * qstep[i] << (n_log2[i] + 10)) + (var[i] >> 1)) /
|
||||
var[i];
|
||||
xsq_q10[i] = (int)VPXMIN(xsq_q10_64, MAX_XSQ_Q10);
|
||||
}
|
||||
model_rd_norm_vec(xsq_q10, r_q10, d_q10);
|
||||
for (i = 0; i < MAX_MB_PLANE; ++i) {
|
||||
int rate =
|
||||
ROUND_POWER_OF_TWO(r_q10[i] << n_log2[i], 10 - VP9_PROB_COST_SHIFT);
|
||||
int64_t dist = (var[i] * (int64_t)d_q10[i] + 512) >> 10;
|
||||
*rate_sum += rate;
|
||||
*dist_sum += dist;
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_get_entropy_contexts(BLOCK_SIZE bsize, TX_SIZE tx_size,
|
||||
const struct macroblockd_plane *pd,
|
||||
ENTROPY_CONTEXT t_above[16],
|
||||
ENTROPY_CONTEXT t_left[16]) {
|
||||
const BLOCK_SIZE plane_bsize = get_plane_block_size(bsize, pd);
|
||||
const int num_4x4_w = num_4x4_blocks_wide_lookup[plane_bsize];
|
||||
const int num_4x4_h = num_4x4_blocks_high_lookup[plane_bsize];
|
||||
const ENTROPY_CONTEXT *const above = pd->above_context;
|
||||
const ENTROPY_CONTEXT *const left = pd->left_context;
|
||||
|
||||
int i;
|
||||
switch (tx_size) {
|
||||
case TX_4X4:
|
||||
memcpy(t_above, above, sizeof(ENTROPY_CONTEXT) * num_4x4_w);
|
||||
memcpy(t_left, left, sizeof(ENTROPY_CONTEXT) * num_4x4_h);
|
||||
break;
|
||||
case TX_8X8:
|
||||
for (i = 0; i < num_4x4_w; i += 2)
|
||||
t_above[i] = !!*(const uint16_t *)&above[i];
|
||||
for (i = 0; i < num_4x4_h; i += 2)
|
||||
t_left[i] = !!*(const uint16_t *)&left[i];
|
||||
break;
|
||||
case TX_16X16:
|
||||
for (i = 0; i < num_4x4_w; i += 4)
|
||||
t_above[i] = !!*(const uint32_t *)&above[i];
|
||||
for (i = 0; i < num_4x4_h; i += 4)
|
||||
t_left[i] = !!*(const uint32_t *)&left[i];
|
||||
break;
|
||||
default:
|
||||
assert(tx_size == TX_32X32);
|
||||
for (i = 0; i < num_4x4_w; i += 8)
|
||||
t_above[i] = !!*(const uint64_t *)&above[i];
|
||||
for (i = 0; i < num_4x4_h; i += 8)
|
||||
t_left[i] = !!*(const uint64_t *)&left[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_mv_pred(VP9_COMP *cpi, MACROBLOCK *x, uint8_t *ref_y_buffer,
|
||||
int ref_y_stride, int ref_frame, BLOCK_SIZE block_size) {
|
||||
int i;
|
||||
int zero_seen = 0;
|
||||
int best_index = 0;
|
||||
int best_sad = INT_MAX;
|
||||
int this_sad = INT_MAX;
|
||||
int max_mv = 0;
|
||||
int near_same_nearest;
|
||||
uint8_t *src_y_ptr = x->plane[0].src.buf;
|
||||
uint8_t *ref_y_ptr;
|
||||
const int num_mv_refs =
|
||||
MAX_MV_REF_CANDIDATES + (block_size < x->max_partition_size);
|
||||
|
||||
MV pred_mv[3];
|
||||
pred_mv[0] = x->mbmi_ext->ref_mvs[ref_frame][0].as_mv;
|
||||
pred_mv[1] = x->mbmi_ext->ref_mvs[ref_frame][1].as_mv;
|
||||
pred_mv[2] = x->pred_mv[ref_frame];
|
||||
assert(num_mv_refs <= (int)(sizeof(pred_mv) / sizeof(pred_mv[0])));
|
||||
|
||||
near_same_nearest = x->mbmi_ext->ref_mvs[ref_frame][0].as_int ==
|
||||
x->mbmi_ext->ref_mvs[ref_frame][1].as_int;
|
||||
|
||||
// Get the sad for each candidate reference mv.
|
||||
for (i = 0; i < num_mv_refs; ++i) {
|
||||
const MV *this_mv = &pred_mv[i];
|
||||
int fp_row, fp_col;
|
||||
if (this_mv->row == INT16_MAX || this_mv->col == INT16_MAX) continue;
|
||||
if (i == 1 && near_same_nearest) continue;
|
||||
fp_row = (this_mv->row + 3 + (this_mv->row >= 0)) >> 3;
|
||||
fp_col = (this_mv->col + 3 + (this_mv->col >= 0)) >> 3;
|
||||
max_mv = VPXMAX(max_mv, VPXMAX(abs(this_mv->row), abs(this_mv->col)) >> 3);
|
||||
|
||||
if (fp_row == 0 && fp_col == 0 && zero_seen) continue;
|
||||
zero_seen |= (fp_row == 0 && fp_col == 0);
|
||||
|
||||
ref_y_ptr = &ref_y_buffer[ref_y_stride * fp_row + fp_col];
|
||||
// Find sad for current vector.
|
||||
this_sad = cpi->fn_ptr[block_size].sdf(src_y_ptr, x->plane[0].src.stride,
|
||||
ref_y_ptr, ref_y_stride);
|
||||
// Note if it is the best so far.
|
||||
if (this_sad < best_sad) {
|
||||
best_sad = this_sad;
|
||||
best_index = i;
|
||||
}
|
||||
}
|
||||
|
||||
// Note the index of the mv that worked best in the reference list.
|
||||
x->mv_best_ref_index[ref_frame] = best_index;
|
||||
x->max_mv_context[ref_frame] = max_mv;
|
||||
x->pred_mv_sad[ref_frame] = best_sad;
|
||||
}
|
||||
|
||||
void vp9_setup_pred_block(const MACROBLOCKD *xd,
|
||||
struct buf_2d dst[MAX_MB_PLANE],
|
||||
const YV12_BUFFER_CONFIG *src, int mi_row, int mi_col,
|
||||
const struct scale_factors *scale,
|
||||
const struct scale_factors *scale_uv) {
|
||||
int i;
|
||||
|
||||
dst[0].buf = src->y_buffer;
|
||||
dst[0].stride = src->y_stride;
|
||||
dst[1].buf = src->u_buffer;
|
||||
dst[2].buf = src->v_buffer;
|
||||
dst[1].stride = dst[2].stride = src->uv_stride;
|
||||
|
||||
for (i = 0; i < MAX_MB_PLANE; ++i) {
|
||||
setup_pred_plane(dst + i, dst[i].buf, dst[i].stride, mi_row, mi_col,
|
||||
i ? scale_uv : scale, xd->plane[i].subsampling_x,
|
||||
xd->plane[i].subsampling_y);
|
||||
}
|
||||
}
|
||||
|
||||
int vp9_raster_block_offset(BLOCK_SIZE plane_bsize, int raster_block,
|
||||
int stride) {
|
||||
const int bw = b_width_log2_lookup[plane_bsize];
|
||||
const int y = 4 * (raster_block >> bw);
|
||||
const int x = 4 * (raster_block & ((1 << bw) - 1));
|
||||
return y * stride + x;
|
||||
}
|
||||
|
||||
int16_t *vp9_raster_block_offset_int16(BLOCK_SIZE plane_bsize, int raster_block,
|
||||
int16_t *base) {
|
||||
const int stride = 4 * num_4x4_blocks_wide_lookup[plane_bsize];
|
||||
return base + vp9_raster_block_offset(plane_bsize, raster_block, stride);
|
||||
}
|
||||
|
||||
YV12_BUFFER_CONFIG *vp9_get_scaled_ref_frame(const VP9_COMP *cpi,
|
||||
int ref_frame) {
|
||||
const VP9_COMMON *const cm = &cpi->common;
|
||||
const int scaled_idx = cpi->scaled_ref_idx[ref_frame - 1];
|
||||
const int ref_idx = get_ref_frame_buf_idx(cpi, ref_frame);
|
||||
assert(ref_frame >= LAST_FRAME && ref_frame <= ALTREF_FRAME);
|
||||
return (scaled_idx != ref_idx && scaled_idx != INVALID_IDX)
|
||||
? &cm->buffer_pool->frame_bufs[scaled_idx].buf
|
||||
: NULL;
|
||||
}
|
||||
|
||||
int vp9_get_switchable_rate(const VP9_COMP *cpi, const MACROBLOCKD *const xd) {
|
||||
const MODE_INFO *const mi = xd->mi[0];
|
||||
const int ctx = get_pred_context_switchable_interp(xd);
|
||||
return SWITCHABLE_INTERP_RATE_FACTOR *
|
||||
cpi->switchable_interp_costs[ctx][mi->interp_filter];
|
||||
}
|
||||
|
||||
void vp9_set_rd_speed_thresholds(VP9_COMP *cpi) {
|
||||
int i;
|
||||
RD_OPT *const rd = &cpi->rd;
|
||||
SPEED_FEATURES *const sf = &cpi->sf;
|
||||
|
||||
// Set baseline threshold values.
|
||||
for (i = 0; i < MAX_MODES; ++i)
|
||||
rd->thresh_mult[i] = cpi->oxcf.mode == BEST ? -500 : 0;
|
||||
|
||||
if (sf->adaptive_rd_thresh) {
|
||||
rd->thresh_mult[THR_NEARESTMV] = 300;
|
||||
rd->thresh_mult[THR_NEARESTG] = 300;
|
||||
rd->thresh_mult[THR_NEARESTA] = 300;
|
||||
} else {
|
||||
rd->thresh_mult[THR_NEARESTMV] = 0;
|
||||
rd->thresh_mult[THR_NEARESTG] = 0;
|
||||
rd->thresh_mult[THR_NEARESTA] = 0;
|
||||
}
|
||||
|
||||
rd->thresh_mult[THR_DC] += 1000;
|
||||
|
||||
rd->thresh_mult[THR_NEWMV] += 1000;
|
||||
rd->thresh_mult[THR_NEWA] += 1000;
|
||||
rd->thresh_mult[THR_NEWG] += 1000;
|
||||
|
||||
rd->thresh_mult[THR_NEARMV] += 1000;
|
||||
rd->thresh_mult[THR_NEARA] += 1000;
|
||||
rd->thresh_mult[THR_COMP_NEARESTLA] += 1000;
|
||||
rd->thresh_mult[THR_COMP_NEARESTGA] += 1000;
|
||||
|
||||
rd->thresh_mult[THR_TM] += 1000;
|
||||
|
||||
rd->thresh_mult[THR_COMP_NEARLA] += 1500;
|
||||
rd->thresh_mult[THR_COMP_NEWLA] += 2000;
|
||||
rd->thresh_mult[THR_NEARG] += 1000;
|
||||
rd->thresh_mult[THR_COMP_NEARGA] += 1500;
|
||||
rd->thresh_mult[THR_COMP_NEWGA] += 2000;
|
||||
|
||||
rd->thresh_mult[THR_ZEROMV] += 2000;
|
||||
rd->thresh_mult[THR_ZEROG] += 2000;
|
||||
rd->thresh_mult[THR_ZEROA] += 2000;
|
||||
rd->thresh_mult[THR_COMP_ZEROLA] += 2500;
|
||||
rd->thresh_mult[THR_COMP_ZEROGA] += 2500;
|
||||
|
||||
rd->thresh_mult[THR_H_PRED] += 2000;
|
||||
rd->thresh_mult[THR_V_PRED] += 2000;
|
||||
rd->thresh_mult[THR_D45_PRED] += 2500;
|
||||
rd->thresh_mult[THR_D135_PRED] += 2500;
|
||||
rd->thresh_mult[THR_D117_PRED] += 2500;
|
||||
rd->thresh_mult[THR_D153_PRED] += 2500;
|
||||
rd->thresh_mult[THR_D207_PRED] += 2500;
|
||||
rd->thresh_mult[THR_D63_PRED] += 2500;
|
||||
}
|
||||
|
||||
void vp9_set_rd_speed_thresholds_sub8x8(VP9_COMP *cpi) {
|
||||
static const int thresh_mult[2][MAX_REFS] = {
|
||||
{ 2500, 2500, 2500, 4500, 4500, 2500 },
|
||||
{ 2000, 2000, 2000, 4000, 4000, 2000 }
|
||||
};
|
||||
RD_OPT *const rd = &cpi->rd;
|
||||
const int idx = cpi->oxcf.mode == BEST;
|
||||
memcpy(rd->thresh_mult_sub8x8, thresh_mult[idx], sizeof(thresh_mult[idx]));
|
||||
}
|
||||
|
||||
void vp9_update_rd_thresh_fact(int (*factor_buf)[MAX_MODES], int rd_thresh,
|
||||
int bsize, int best_mode_index) {
|
||||
if (rd_thresh > 0) {
|
||||
const int top_mode = bsize < BLOCK_8X8 ? MAX_REFS : MAX_MODES;
|
||||
int mode;
|
||||
for (mode = 0; mode < top_mode; ++mode) {
|
||||
const BLOCK_SIZE min_size = VPXMAX(bsize - 1, BLOCK_4X4);
|
||||
const BLOCK_SIZE max_size = VPXMIN(bsize + 2, BLOCK_64X64);
|
||||
BLOCK_SIZE bs;
|
||||
for (bs = min_size; bs <= max_size; ++bs) {
|
||||
int *const fact = &factor_buf[bs][mode];
|
||||
if (mode == best_mode_index) {
|
||||
*fact -= (*fact >> 4);
|
||||
} else {
|
||||
*fact = VPXMIN(*fact + RD_THRESH_INC, rd_thresh * RD_THRESH_MAX_FACT);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int vp9_get_intra_cost_penalty(const VP9_COMP *const cpi, BLOCK_SIZE bsize,
|
||||
int qindex, int qdelta) {
|
||||
// Reduce the intra cost penalty for small blocks (<=16x16).
|
||||
int reduction_fac =
|
||||
(bsize <= BLOCK_16X16) ? ((bsize <= BLOCK_8X8) ? 4 : 2) : 0;
|
||||
|
||||
if (cpi->noise_estimate.enabled && cpi->noise_estimate.level == kHigh)
|
||||
// Don't reduce intra cost penalty if estimated noise level is high.
|
||||
reduction_fac = 0;
|
||||
|
||||
// Always use VPX_BITS_8 as input here because the penalty is applied
|
||||
// to rate not distortion so we want a consistent penalty for all bit
|
||||
// depths. If the actual bit depth were passed in here then the value
|
||||
// retured by vp9_dc_quant() would scale with the bit depth and we would
|
||||
// then need to apply inverse scaling to correct back to a bit depth
|
||||
// independent rate penalty.
|
||||
return (20 * vp9_dc_quant(qindex, qdelta, VPX_BITS_8)) >> reduction_fac;
|
||||
}
|
||||
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
* 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_ENCODER_VP9_RD_H_
|
||||
#define VPX_VP9_ENCODER_VP9_RD_H_
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include "vp9/common/vp9_blockd.h"
|
||||
|
||||
#include "vp9/encoder/vp9_block.h"
|
||||
#include "vp9/encoder/vp9_context_tree.h"
|
||||
#include "vp9/encoder/vp9_cost.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define RDDIV_BITS 7
|
||||
#define RD_EPB_SHIFT 6
|
||||
|
||||
#define RDCOST(RM, DM, R, D) \
|
||||
ROUND_POWER_OF_TWO(((int64_t)(R)) * (RM), VP9_PROB_COST_SHIFT) + ((D) << (DM))
|
||||
#define RDCOST_NEG_R(RM, DM, R, D) \
|
||||
((D) << (DM)) - ROUND_POWER_OF_TWO(((int64_t)(R)) * (RM), VP9_PROB_COST_SHIFT)
|
||||
#define RDCOST_NEG_D(RM, DM, R, D) \
|
||||
ROUND_POWER_OF_TWO(((int64_t)(R)) * (RM), VP9_PROB_COST_SHIFT) - ((D) << (DM))
|
||||
|
||||
#define QIDX_SKIP_THRESH 115
|
||||
|
||||
#define MV_COST_WEIGHT 108
|
||||
#define MV_COST_WEIGHT_SUB 120
|
||||
|
||||
#define MAX_MODES 30
|
||||
#define MAX_REFS 6
|
||||
|
||||
#define RD_THRESH_INIT_FACT 32
|
||||
#define RD_THRESH_MAX_FACT 64
|
||||
#define RD_THRESH_INC 1
|
||||
|
||||
#define VP9_DIST_SCALE_LOG2 4
|
||||
#define VP9_DIST_SCALE (1 << VP9_DIST_SCALE_LOG2)
|
||||
|
||||
// This enumerator type needs to be kept aligned with the mode order in
|
||||
// const MODE_DEFINITION vp9_mode_order[MAX_MODES] used in the rd code.
|
||||
typedef enum {
|
||||
THR_NEARESTMV,
|
||||
THR_NEARESTA,
|
||||
THR_NEARESTG,
|
||||
|
||||
THR_DC,
|
||||
|
||||
THR_NEWMV,
|
||||
THR_NEWA,
|
||||
THR_NEWG,
|
||||
|
||||
THR_NEARMV,
|
||||
THR_NEARA,
|
||||
THR_NEARG,
|
||||
|
||||
THR_ZEROMV,
|
||||
THR_ZEROG,
|
||||
THR_ZEROA,
|
||||
|
||||
THR_COMP_NEARESTLA,
|
||||
THR_COMP_NEARESTGA,
|
||||
|
||||
THR_TM,
|
||||
|
||||
THR_COMP_NEARLA,
|
||||
THR_COMP_NEWLA,
|
||||
THR_COMP_NEARGA,
|
||||
THR_COMP_NEWGA,
|
||||
|
||||
THR_COMP_ZEROLA,
|
||||
THR_COMP_ZEROGA,
|
||||
|
||||
THR_H_PRED,
|
||||
THR_V_PRED,
|
||||
THR_D135_PRED,
|
||||
THR_D207_PRED,
|
||||
THR_D153_PRED,
|
||||
THR_D63_PRED,
|
||||
THR_D117_PRED,
|
||||
THR_D45_PRED,
|
||||
} THR_MODES;
|
||||
|
||||
typedef enum {
|
||||
THR_LAST,
|
||||
THR_GOLD,
|
||||
THR_ALTR,
|
||||
THR_COMP_LA,
|
||||
THR_COMP_GA,
|
||||
THR_INTRA,
|
||||
} THR_MODES_SUB8X8;
|
||||
|
||||
typedef struct RD_OPT {
|
||||
// Thresh_mult is used to set a threshold for the rd score. A higher value
|
||||
// means that we will accept the best mode so far more often. This number
|
||||
// is used in combination with the current block size, and thresh_freq_fact to
|
||||
// pick a threshold.
|
||||
int thresh_mult[MAX_MODES];
|
||||
int thresh_mult_sub8x8[MAX_REFS];
|
||||
|
||||
int threshes[MAX_SEGMENTS][BLOCK_SIZES][MAX_MODES];
|
||||
|
||||
int64_t prediction_type_threshes[MAX_REF_FRAMES][REFERENCE_MODES];
|
||||
|
||||
int64_t filter_threshes[MAX_REF_FRAMES][SWITCHABLE_FILTER_CONTEXTS];
|
||||
#if CONFIG_CONSISTENT_RECODE
|
||||
int64_t prediction_type_threshes_prev[MAX_REF_FRAMES][REFERENCE_MODES];
|
||||
|
||||
int64_t filter_threshes_prev[MAX_REF_FRAMES][SWITCHABLE_FILTER_CONTEXTS];
|
||||
#endif
|
||||
int RDMULT;
|
||||
int RDDIV;
|
||||
double r0;
|
||||
} RD_OPT;
|
||||
|
||||
typedef struct RD_COST {
|
||||
int rate;
|
||||
int64_t dist;
|
||||
int64_t rdcost;
|
||||
} RD_COST;
|
||||
|
||||
// Reset the rate distortion cost values to maximum (invalid) value.
|
||||
void vp9_rd_cost_reset(RD_COST *rd_cost);
|
||||
// Initialize the rate distortion cost values to zero.
|
||||
void vp9_rd_cost_init(RD_COST *rd_cost);
|
||||
// It supports negative rate and dist, which is different from RDCOST().
|
||||
int64_t vp9_calculate_rd_cost(int mult, int div, int rate, int64_t dist);
|
||||
// Update the cost value based on its rate and distortion.
|
||||
void vp9_rd_cost_update(int mult, int div, RD_COST *rd_cost);
|
||||
|
||||
struct TileInfo;
|
||||
struct TileDataEnc;
|
||||
struct VP9_COMP;
|
||||
struct macroblock;
|
||||
|
||||
int vp9_compute_rd_mult_based_on_qindex(const struct VP9_COMP *cpi, int qindex);
|
||||
|
||||
int vp9_compute_rd_mult(const struct VP9_COMP *cpi, int qindex);
|
||||
|
||||
int vp9_get_adaptive_rdmult(const struct VP9_COMP *cpi, double beta);
|
||||
|
||||
void vp9_initialize_rd_consts(struct VP9_COMP *cpi);
|
||||
|
||||
void vp9_initialize_me_consts(struct VP9_COMP *cpi, MACROBLOCK *x, int qindex);
|
||||
|
||||
void vp9_model_rd_from_var_lapndz(unsigned int var, unsigned int n_log2,
|
||||
unsigned int qstep, int *rate, int64_t *dist);
|
||||
|
||||
void vp9_model_rd_from_var_lapndz_vec(unsigned int var[MAX_MB_PLANE],
|
||||
unsigned int n_log2[MAX_MB_PLANE],
|
||||
unsigned int qstep[MAX_MB_PLANE],
|
||||
int64_t *rate_sum, int64_t *dist_sum);
|
||||
|
||||
int vp9_get_switchable_rate(const struct VP9_COMP *cpi,
|
||||
const MACROBLOCKD *const xd);
|
||||
|
||||
int vp9_raster_block_offset(BLOCK_SIZE plane_bsize, int raster_block,
|
||||
int stride);
|
||||
|
||||
int16_t *vp9_raster_block_offset_int16(BLOCK_SIZE plane_bsize, int raster_block,
|
||||
int16_t *base);
|
||||
|
||||
YV12_BUFFER_CONFIG *vp9_get_scaled_ref_frame(const struct VP9_COMP *cpi,
|
||||
int ref_frame);
|
||||
|
||||
void vp9_init_me_luts(void);
|
||||
|
||||
void vp9_get_entropy_contexts(BLOCK_SIZE bsize, TX_SIZE tx_size,
|
||||
const struct macroblockd_plane *pd,
|
||||
ENTROPY_CONTEXT t_above[16],
|
||||
ENTROPY_CONTEXT t_left[16]);
|
||||
|
||||
void vp9_set_rd_speed_thresholds(struct VP9_COMP *cpi);
|
||||
|
||||
void vp9_set_rd_speed_thresholds_sub8x8(struct VP9_COMP *cpi);
|
||||
|
||||
void vp9_update_rd_thresh_fact(int (*factor_buf)[MAX_MODES], int rd_thresh,
|
||||
int bsize, int best_mode_index);
|
||||
|
||||
static INLINE int rd_less_than_thresh(int64_t best_rd, int thresh,
|
||||
const int *const thresh_fact) {
|
||||
return best_rd < ((int64_t)thresh * (*thresh_fact) >> 5) || thresh == INT_MAX;
|
||||
}
|
||||
|
||||
static INLINE void set_error_per_bit(MACROBLOCK *x, int rdmult) {
|
||||
x->errorperbit = rdmult >> RD_EPB_SHIFT;
|
||||
x->errorperbit += (x->errorperbit == 0);
|
||||
}
|
||||
|
||||
void vp9_mv_pred(struct VP9_COMP *cpi, MACROBLOCK *x, uint8_t *ref_y_buffer,
|
||||
int ref_y_stride, int ref_frame, BLOCK_SIZE block_size);
|
||||
|
||||
void vp9_setup_pred_block(const MACROBLOCKD *xd,
|
||||
struct buf_2d dst[MAX_MB_PLANE],
|
||||
const YV12_BUFFER_CONFIG *src, int mi_row, int mi_col,
|
||||
const struct scale_factors *scale,
|
||||
const struct scale_factors *scale_uv);
|
||||
|
||||
int vp9_get_intra_cost_penalty(const struct VP9_COMP *const cpi,
|
||||
BLOCK_SIZE bsize, int qindex, int qdelta);
|
||||
|
||||
unsigned int vp9_get_sby_variance(struct VP9_COMP *cpi,
|
||||
const struct buf_2d *ref, BLOCK_SIZE bs);
|
||||
unsigned int vp9_get_sby_perpixel_variance(struct VP9_COMP *cpi,
|
||||
const struct buf_2d *ref,
|
||||
BLOCK_SIZE bs);
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
unsigned int vp9_high_get_sby_variance(struct VP9_COMP *cpi,
|
||||
const struct buf_2d *ref, BLOCK_SIZE bs,
|
||||
int bd);
|
||||
unsigned int vp9_high_get_sby_perpixel_variance(struct VP9_COMP *cpi,
|
||||
const struct buf_2d *ref,
|
||||
BLOCK_SIZE bs, int bd);
|
||||
#endif
|
||||
|
||||
void vp9_build_inter_mode_cost(struct VP9_COMP *cpi);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_ENCODER_VP9_RD_H_
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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_ENCODER_VP9_RDOPT_H_
|
||||
#define VPX_VP9_ENCODER_VP9_RDOPT_H_
|
||||
|
||||
#include "vp9/common/vp9_blockd.h"
|
||||
|
||||
#include "vp9/encoder/vp9_block.h"
|
||||
#include "vp9/encoder/vp9_context_tree.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct TileInfo;
|
||||
struct VP9_COMP;
|
||||
struct macroblock;
|
||||
struct RD_COST;
|
||||
|
||||
void vp9_rd_pick_intra_mode_sb(struct VP9_COMP *cpi, struct macroblock *x,
|
||||
struct RD_COST *rd_cost, BLOCK_SIZE bsize,
|
||||
PICK_MODE_CONTEXT *ctx, int64_t best_rd);
|
||||
|
||||
#if !CONFIG_REALTIME_ONLY
|
||||
void vp9_rd_pick_inter_mode_sb(struct VP9_COMP *cpi,
|
||||
struct TileDataEnc *tile_data,
|
||||
struct macroblock *x, int mi_row, int mi_col,
|
||||
struct RD_COST *rd_cost, BLOCK_SIZE bsize,
|
||||
PICK_MODE_CONTEXT *ctx, int64_t best_rd_so_far);
|
||||
|
||||
void vp9_rd_pick_inter_mode_sb_seg_skip(
|
||||
struct VP9_COMP *cpi, struct TileDataEnc *tile_data, struct macroblock *x,
|
||||
struct RD_COST *rd_cost, BLOCK_SIZE bsize, PICK_MODE_CONTEXT *ctx,
|
||||
int64_t best_rd_so_far);
|
||||
#endif
|
||||
|
||||
int vp9_internal_image_edge(struct VP9_COMP *cpi);
|
||||
int vp9_active_h_edge(struct VP9_COMP *cpi, int mi_row, int mi_step);
|
||||
int vp9_active_v_edge(struct VP9_COMP *cpi, int mi_col, int mi_step);
|
||||
int vp9_active_edge_sb(struct VP9_COMP *cpi, int mi_row, int mi_col);
|
||||
|
||||
#if !CONFIG_REALTIME_ONLY
|
||||
void vp9_rd_pick_inter_mode_sub8x8(struct VP9_COMP *cpi,
|
||||
struct TileDataEnc *tile_data,
|
||||
struct macroblock *x, int mi_row, int mi_col,
|
||||
struct RD_COST *rd_cost, BLOCK_SIZE bsize,
|
||||
PICK_MODE_CONTEXT *ctx,
|
||||
int64_t best_rd_so_far);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_ENCODER_VP9_RDOPT_H_
|
||||
@@ -0,0 +1,826 @@
|
||||
/*
|
||||
* Copyright (c) 2014 The WebM project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "./vpx_config.h"
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
#include "vpx_dsp/vpx_dsp_common.h"
|
||||
#endif // CONFIG_VP9_HIGHBITDEPTH
|
||||
#include "vpx_ports/mem.h"
|
||||
#include "vp9/common/vp9_common.h"
|
||||
#include "vp9/encoder/vp9_resize.h"
|
||||
|
||||
#define FILTER_BITS 7
|
||||
|
||||
#define INTERP_TAPS 8
|
||||
#define SUBPEL_BITS 5
|
||||
#define SUBPEL_MASK ((1 << SUBPEL_BITS) - 1)
|
||||
#define INTERP_PRECISION_BITS 32
|
||||
|
||||
typedef int16_t interp_kernel[INTERP_TAPS];
|
||||
|
||||
// Filters for interpolation (0.5-band) - note this also filters integer pels.
|
||||
static const interp_kernel filteredinterp_filters500[(1 << SUBPEL_BITS)] = {
|
||||
{ -3, 0, 35, 64, 35, 0, -3, 0 }, { -3, -1, 34, 64, 36, 1, -3, 0 },
|
||||
{ -3, -1, 32, 64, 38, 1, -3, 0 }, { -2, -2, 31, 63, 39, 2, -3, 0 },
|
||||
{ -2, -2, 29, 63, 41, 2, -3, 0 }, { -2, -2, 28, 63, 42, 3, -4, 0 },
|
||||
{ -2, -3, 27, 63, 43, 4, -4, 0 }, { -2, -3, 25, 62, 45, 5, -4, 0 },
|
||||
{ -2, -3, 24, 62, 46, 5, -4, 0 }, { -2, -3, 23, 61, 47, 6, -4, 0 },
|
||||
{ -2, -3, 21, 60, 49, 7, -4, 0 }, { -1, -4, 20, 60, 50, 8, -4, -1 },
|
||||
{ -1, -4, 19, 59, 51, 9, -4, -1 }, { -1, -4, 17, 58, 52, 10, -4, 0 },
|
||||
{ -1, -4, 16, 57, 53, 12, -4, -1 }, { -1, -4, 15, 56, 54, 13, -4, -1 },
|
||||
{ -1, -4, 14, 55, 55, 14, -4, -1 }, { -1, -4, 13, 54, 56, 15, -4, -1 },
|
||||
{ -1, -4, 12, 53, 57, 16, -4, -1 }, { 0, -4, 10, 52, 58, 17, -4, -1 },
|
||||
{ -1, -4, 9, 51, 59, 19, -4, -1 }, { -1, -4, 8, 50, 60, 20, -4, -1 },
|
||||
{ 0, -4, 7, 49, 60, 21, -3, -2 }, { 0, -4, 6, 47, 61, 23, -3, -2 },
|
||||
{ 0, -4, 5, 46, 62, 24, -3, -2 }, { 0, -4, 5, 45, 62, 25, -3, -2 },
|
||||
{ 0, -4, 4, 43, 63, 27, -3, -2 }, { 0, -4, 3, 42, 63, 28, -2, -2 },
|
||||
{ 0, -3, 2, 41, 63, 29, -2, -2 }, { 0, -3, 2, 39, 63, 31, -2, -2 },
|
||||
{ 0, -3, 1, 38, 64, 32, -1, -3 }, { 0, -3, 1, 36, 64, 34, -1, -3 }
|
||||
};
|
||||
|
||||
// Filters for interpolation (0.625-band) - note this also filters integer pels.
|
||||
static const interp_kernel filteredinterp_filters625[(1 << SUBPEL_BITS)] = {
|
||||
{ -1, -8, 33, 80, 33, -8, -1, 0 }, { -1, -8, 30, 80, 35, -8, -1, 1 },
|
||||
{ -1, -8, 28, 80, 37, -7, -2, 1 }, { 0, -8, 26, 79, 39, -7, -2, 1 },
|
||||
{ 0, -8, 24, 79, 41, -7, -2, 1 }, { 0, -8, 22, 78, 43, -6, -2, 1 },
|
||||
{ 0, -8, 20, 78, 45, -5, -3, 1 }, { 0, -8, 18, 77, 48, -5, -3, 1 },
|
||||
{ 0, -8, 16, 76, 50, -4, -3, 1 }, { 0, -8, 15, 75, 52, -3, -4, 1 },
|
||||
{ 0, -7, 13, 74, 54, -3, -4, 1 }, { 0, -7, 11, 73, 56, -2, -4, 1 },
|
||||
{ 0, -7, 10, 71, 58, -1, -4, 1 }, { 1, -7, 8, 70, 60, 0, -5, 1 },
|
||||
{ 1, -6, 6, 68, 62, 1, -5, 1 }, { 1, -6, 5, 67, 63, 2, -5, 1 },
|
||||
{ 1, -6, 4, 65, 65, 4, -6, 1 }, { 1, -5, 2, 63, 67, 5, -6, 1 },
|
||||
{ 1, -5, 1, 62, 68, 6, -6, 1 }, { 1, -5, 0, 60, 70, 8, -7, 1 },
|
||||
{ 1, -4, -1, 58, 71, 10, -7, 0 }, { 1, -4, -2, 56, 73, 11, -7, 0 },
|
||||
{ 1, -4, -3, 54, 74, 13, -7, 0 }, { 1, -4, -3, 52, 75, 15, -8, 0 },
|
||||
{ 1, -3, -4, 50, 76, 16, -8, 0 }, { 1, -3, -5, 48, 77, 18, -8, 0 },
|
||||
{ 1, -3, -5, 45, 78, 20, -8, 0 }, { 1, -2, -6, 43, 78, 22, -8, 0 },
|
||||
{ 1, -2, -7, 41, 79, 24, -8, 0 }, { 1, -2, -7, 39, 79, 26, -8, 0 },
|
||||
{ 1, -2, -7, 37, 80, 28, -8, -1 }, { 1, -1, -8, 35, 80, 30, -8, -1 },
|
||||
};
|
||||
|
||||
// Filters for interpolation (0.75-band) - note this also filters integer pels.
|
||||
static const interp_kernel filteredinterp_filters750[(1 << SUBPEL_BITS)] = {
|
||||
{ 2, -11, 25, 96, 25, -11, 2, 0 }, { 2, -11, 22, 96, 28, -11, 2, 0 },
|
||||
{ 2, -10, 19, 95, 31, -11, 2, 0 }, { 2, -10, 17, 95, 34, -12, 2, 0 },
|
||||
{ 2, -9, 14, 94, 37, -12, 2, 0 }, { 2, -8, 12, 93, 40, -12, 1, 0 },
|
||||
{ 2, -8, 9, 92, 43, -12, 1, 1 }, { 2, -7, 7, 91, 46, -12, 1, 0 },
|
||||
{ 2, -7, 5, 90, 49, -12, 1, 0 }, { 2, -6, 3, 88, 52, -12, 0, 1 },
|
||||
{ 2, -5, 1, 86, 55, -12, 0, 1 }, { 2, -5, -1, 84, 58, -11, 0, 1 },
|
||||
{ 2, -4, -2, 82, 61, -11, -1, 1 }, { 2, -4, -4, 80, 64, -10, -1, 1 },
|
||||
{ 1, -3, -5, 77, 67, -9, -1, 1 }, { 1, -3, -6, 75, 70, -8, -2, 1 },
|
||||
{ 1, -2, -7, 72, 72, -7, -2, 1 }, { 1, -2, -8, 70, 75, -6, -3, 1 },
|
||||
{ 1, -1, -9, 67, 77, -5, -3, 1 }, { 1, -1, -10, 64, 80, -4, -4, 2 },
|
||||
{ 1, -1, -11, 61, 82, -2, -4, 2 }, { 1, 0, -11, 58, 84, -1, -5, 2 },
|
||||
{ 1, 0, -12, 55, 86, 1, -5, 2 }, { 1, 0, -12, 52, 88, 3, -6, 2 },
|
||||
{ 0, 1, -12, 49, 90, 5, -7, 2 }, { 0, 1, -12, 46, 91, 7, -7, 2 },
|
||||
{ 1, 1, -12, 43, 92, 9, -8, 2 }, { 0, 1, -12, 40, 93, 12, -8, 2 },
|
||||
{ 0, 2, -12, 37, 94, 14, -9, 2 }, { 0, 2, -12, 34, 95, 17, -10, 2 },
|
||||
{ 0, 2, -11, 31, 95, 19, -10, 2 }, { 0, 2, -11, 28, 96, 22, -11, 2 }
|
||||
};
|
||||
|
||||
// Filters for interpolation (0.875-band) - note this also filters integer pels.
|
||||
static const interp_kernel filteredinterp_filters875[(1 << SUBPEL_BITS)] = {
|
||||
{ 3, -8, 13, 112, 13, -8, 3, 0 }, { 3, -7, 10, 112, 17, -9, 3, -1 },
|
||||
{ 2, -6, 7, 111, 21, -9, 3, -1 }, { 2, -5, 4, 111, 24, -10, 3, -1 },
|
||||
{ 2, -4, 1, 110, 28, -11, 3, -1 }, { 1, -3, -1, 108, 32, -12, 4, -1 },
|
||||
{ 1, -2, -3, 106, 36, -13, 4, -1 }, { 1, -1, -6, 105, 40, -14, 4, -1 },
|
||||
{ 1, -1, -7, 102, 44, -14, 4, -1 }, { 1, 0, -9, 100, 48, -15, 4, -1 },
|
||||
{ 1, 1, -11, 97, 53, -16, 4, -1 }, { 0, 1, -12, 95, 57, -16, 4, -1 },
|
||||
{ 0, 2, -13, 91, 61, -16, 4, -1 }, { 0, 2, -14, 88, 65, -16, 4, -1 },
|
||||
{ 0, 3, -15, 84, 69, -17, 4, 0 }, { 0, 3, -16, 81, 73, -16, 3, 0 },
|
||||
{ 0, 3, -16, 77, 77, -16, 3, 0 }, { 0, 3, -16, 73, 81, -16, 3, 0 },
|
||||
{ 0, 4, -17, 69, 84, -15, 3, 0 }, { -1, 4, -16, 65, 88, -14, 2, 0 },
|
||||
{ -1, 4, -16, 61, 91, -13, 2, 0 }, { -1, 4, -16, 57, 95, -12, 1, 0 },
|
||||
{ -1, 4, -16, 53, 97, -11, 1, 1 }, { -1, 4, -15, 48, 100, -9, 0, 1 },
|
||||
{ -1, 4, -14, 44, 102, -7, -1, 1 }, { -1, 4, -14, 40, 105, -6, -1, 1 },
|
||||
{ -1, 4, -13, 36, 106, -3, -2, 1 }, { -1, 4, -12, 32, 108, -1, -3, 1 },
|
||||
{ -1, 3, -11, 28, 110, 1, -4, 2 }, { -1, 3, -10, 24, 111, 4, -5, 2 },
|
||||
{ -1, 3, -9, 21, 111, 7, -6, 2 }, { -1, 3, -9, 17, 112, 10, -7, 3 }
|
||||
};
|
||||
|
||||
// Filters for interpolation (full-band) - no filtering for integer pixels
|
||||
static const interp_kernel filteredinterp_filters1000[(1 << SUBPEL_BITS)] = {
|
||||
{ 0, 0, 0, 128, 0, 0, 0, 0 }, { 0, 1, -3, 128, 3, -1, 0, 0 },
|
||||
{ -1, 2, -6, 127, 7, -2, 1, 0 }, { -1, 3, -9, 126, 12, -4, 1, 0 },
|
||||
{ -1, 4, -12, 125, 16, -5, 1, 0 }, { -1, 4, -14, 123, 20, -6, 2, 0 },
|
||||
{ -1, 5, -15, 120, 25, -8, 2, 0 }, { -1, 5, -17, 118, 30, -9, 3, -1 },
|
||||
{ -1, 6, -18, 114, 35, -10, 3, -1 }, { -1, 6, -19, 111, 41, -12, 3, -1 },
|
||||
{ -1, 6, -20, 107, 46, -13, 4, -1 }, { -1, 6, -21, 103, 52, -14, 4, -1 },
|
||||
{ -1, 6, -21, 99, 57, -16, 5, -1 }, { -1, 6, -21, 94, 63, -17, 5, -1 },
|
||||
{ -1, 6, -20, 89, 68, -18, 5, -1 }, { -1, 6, -20, 84, 73, -19, 6, -1 },
|
||||
{ -1, 6, -20, 79, 79, -20, 6, -1 }, { -1, 6, -19, 73, 84, -20, 6, -1 },
|
||||
{ -1, 5, -18, 68, 89, -20, 6, -1 }, { -1, 5, -17, 63, 94, -21, 6, -1 },
|
||||
{ -1, 5, -16, 57, 99, -21, 6, -1 }, { -1, 4, -14, 52, 103, -21, 6, -1 },
|
||||
{ -1, 4, -13, 46, 107, -20, 6, -1 }, { -1, 3, -12, 41, 111, -19, 6, -1 },
|
||||
{ -1, 3, -10, 35, 114, -18, 6, -1 }, { -1, 3, -9, 30, 118, -17, 5, -1 },
|
||||
{ 0, 2, -8, 25, 120, -15, 5, -1 }, { 0, 2, -6, 20, 123, -14, 4, -1 },
|
||||
{ 0, 1, -5, 16, 125, -12, 4, -1 }, { 0, 1, -4, 12, 126, -9, 3, -1 },
|
||||
{ 0, 1, -2, 7, 127, -6, 2, -1 }, { 0, 0, -1, 3, 128, -3, 1, 0 }
|
||||
};
|
||||
|
||||
// Filters for factor of 2 downsampling.
|
||||
static const int16_t vp9_down2_symeven_half_filter[] = { 56, 12, -3, -1 };
|
||||
static const int16_t vp9_down2_symodd_half_filter[] = { 64, 35, 0, -3 };
|
||||
|
||||
static const interp_kernel *choose_interp_filter(int inlength, int outlength) {
|
||||
int outlength16 = outlength * 16;
|
||||
if (outlength16 >= inlength * 16)
|
||||
return filteredinterp_filters1000;
|
||||
else if (outlength16 >= inlength * 13)
|
||||
return filteredinterp_filters875;
|
||||
else if (outlength16 >= inlength * 11)
|
||||
return filteredinterp_filters750;
|
||||
else if (outlength16 >= inlength * 9)
|
||||
return filteredinterp_filters625;
|
||||
else
|
||||
return filteredinterp_filters500;
|
||||
}
|
||||
|
||||
static void interpolate(const uint8_t *const input, int inlength,
|
||||
uint8_t *output, int outlength) {
|
||||
const int64_t delta =
|
||||
(((uint64_t)inlength << 32) + outlength / 2) / outlength;
|
||||
const int64_t offset =
|
||||
inlength > outlength
|
||||
? (((int64_t)(inlength - outlength) << 31) + outlength / 2) /
|
||||
outlength
|
||||
: -(((int64_t)(outlength - inlength) << 31) + outlength / 2) /
|
||||
outlength;
|
||||
uint8_t *optr = output;
|
||||
int x, x1, x2, sum, k, int_pel, sub_pel;
|
||||
int64_t y;
|
||||
|
||||
const interp_kernel *interp_filters =
|
||||
choose_interp_filter(inlength, outlength);
|
||||
|
||||
x = 0;
|
||||
y = offset;
|
||||
while ((y >> INTERP_PRECISION_BITS) < (INTERP_TAPS / 2 - 1)) {
|
||||
x++;
|
||||
y += delta;
|
||||
}
|
||||
x1 = x;
|
||||
x = outlength - 1;
|
||||
y = delta * x + offset;
|
||||
while ((y >> INTERP_PRECISION_BITS) + (int64_t)(INTERP_TAPS / 2) >=
|
||||
inlength) {
|
||||
x--;
|
||||
y -= delta;
|
||||
}
|
||||
x2 = x;
|
||||
if (x1 > x2) {
|
||||
for (x = 0, y = offset; x < outlength; ++x, y += delta) {
|
||||
const int16_t *filter;
|
||||
int_pel = y >> INTERP_PRECISION_BITS;
|
||||
sub_pel = (y >> (INTERP_PRECISION_BITS - SUBPEL_BITS)) & SUBPEL_MASK;
|
||||
filter = interp_filters[sub_pel];
|
||||
sum = 0;
|
||||
for (k = 0; k < INTERP_TAPS; ++k) {
|
||||
const int pk = int_pel - INTERP_TAPS / 2 + 1 + k;
|
||||
sum += filter[k] *
|
||||
input[(pk < 0 ? 0 : (pk >= inlength ? inlength - 1 : pk))];
|
||||
}
|
||||
*optr++ = clip_pixel(ROUND_POWER_OF_TWO(sum, FILTER_BITS));
|
||||
}
|
||||
} else {
|
||||
// Initial part.
|
||||
for (x = 0, y = offset; x < x1; ++x, y += delta) {
|
||||
const int16_t *filter;
|
||||
int_pel = y >> INTERP_PRECISION_BITS;
|
||||
sub_pel = (y >> (INTERP_PRECISION_BITS - SUBPEL_BITS)) & SUBPEL_MASK;
|
||||
filter = interp_filters[sub_pel];
|
||||
sum = 0;
|
||||
for (k = 0; k < INTERP_TAPS; ++k)
|
||||
sum += filter[k] * input[(int_pel - INTERP_TAPS / 2 + 1 + k < 0
|
||||
? 0
|
||||
: int_pel - INTERP_TAPS / 2 + 1 + k)];
|
||||
*optr++ = clip_pixel(ROUND_POWER_OF_TWO(sum, FILTER_BITS));
|
||||
}
|
||||
// Middle part.
|
||||
for (; x <= x2; ++x, y += delta) {
|
||||
const int16_t *filter;
|
||||
int_pel = y >> INTERP_PRECISION_BITS;
|
||||
sub_pel = (y >> (INTERP_PRECISION_BITS - SUBPEL_BITS)) & SUBPEL_MASK;
|
||||
filter = interp_filters[sub_pel];
|
||||
sum = 0;
|
||||
for (k = 0; k < INTERP_TAPS; ++k)
|
||||
sum += filter[k] * input[int_pel - INTERP_TAPS / 2 + 1 + k];
|
||||
*optr++ = clip_pixel(ROUND_POWER_OF_TWO(sum, FILTER_BITS));
|
||||
}
|
||||
// End part.
|
||||
for (; x < outlength; ++x, y += delta) {
|
||||
const int16_t *filter;
|
||||
int_pel = y >> INTERP_PRECISION_BITS;
|
||||
sub_pel = (y >> (INTERP_PRECISION_BITS - SUBPEL_BITS)) & SUBPEL_MASK;
|
||||
filter = interp_filters[sub_pel];
|
||||
sum = 0;
|
||||
for (k = 0; k < INTERP_TAPS; ++k)
|
||||
sum += filter[k] * input[(int_pel - INTERP_TAPS / 2 + 1 + k >= inlength
|
||||
? inlength - 1
|
||||
: int_pel - INTERP_TAPS / 2 + 1 + k)];
|
||||
*optr++ = clip_pixel(ROUND_POWER_OF_TWO(sum, FILTER_BITS));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void down2_symeven(const uint8_t *const input, int length,
|
||||
uint8_t *output) {
|
||||
// Actual filter len = 2 * filter_len_half.
|
||||
const int16_t *filter = vp9_down2_symeven_half_filter;
|
||||
const int filter_len_half = sizeof(vp9_down2_symeven_half_filter) / 2;
|
||||
int i, j;
|
||||
uint8_t *optr = output;
|
||||
int l1 = filter_len_half;
|
||||
int l2 = (length - filter_len_half);
|
||||
l1 += (l1 & 1);
|
||||
l2 += (l2 & 1);
|
||||
if (l1 > l2) {
|
||||
// Short input length.
|
||||
for (i = 0; i < length; i += 2) {
|
||||
int sum = (1 << (FILTER_BITS - 1));
|
||||
for (j = 0; j < filter_len_half; ++j) {
|
||||
sum += (input[(i - j < 0 ? 0 : i - j)] +
|
||||
input[(i + 1 + j >= length ? length - 1 : i + 1 + j)]) *
|
||||
filter[j];
|
||||
}
|
||||
sum >>= FILTER_BITS;
|
||||
*optr++ = clip_pixel(sum);
|
||||
}
|
||||
} else {
|
||||
// Initial part.
|
||||
for (i = 0; i < l1; i += 2) {
|
||||
int sum = (1 << (FILTER_BITS - 1));
|
||||
for (j = 0; j < filter_len_half; ++j) {
|
||||
sum += (input[(i - j < 0 ? 0 : i - j)] + input[i + 1 + j]) * filter[j];
|
||||
}
|
||||
sum >>= FILTER_BITS;
|
||||
*optr++ = clip_pixel(sum);
|
||||
}
|
||||
// Middle part.
|
||||
for (; i < l2; i += 2) {
|
||||
int sum = (1 << (FILTER_BITS - 1));
|
||||
for (j = 0; j < filter_len_half; ++j) {
|
||||
sum += (input[i - j] + input[i + 1 + j]) * filter[j];
|
||||
}
|
||||
sum >>= FILTER_BITS;
|
||||
*optr++ = clip_pixel(sum);
|
||||
}
|
||||
// End part.
|
||||
for (; i < length; i += 2) {
|
||||
int sum = (1 << (FILTER_BITS - 1));
|
||||
for (j = 0; j < filter_len_half; ++j) {
|
||||
sum += (input[i - j] +
|
||||
input[(i + 1 + j >= length ? length - 1 : i + 1 + j)]) *
|
||||
filter[j];
|
||||
}
|
||||
sum >>= FILTER_BITS;
|
||||
*optr++ = clip_pixel(sum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void down2_symodd(const uint8_t *const input, int length,
|
||||
uint8_t *output) {
|
||||
// Actual filter len = 2 * filter_len_half - 1.
|
||||
const int16_t *filter = vp9_down2_symodd_half_filter;
|
||||
const int filter_len_half = sizeof(vp9_down2_symodd_half_filter) / 2;
|
||||
int i, j;
|
||||
uint8_t *optr = output;
|
||||
int l1 = filter_len_half - 1;
|
||||
int l2 = (length - filter_len_half + 1);
|
||||
l1 += (l1 & 1);
|
||||
l2 += (l2 & 1);
|
||||
if (l1 > l2) {
|
||||
// Short input length.
|
||||
for (i = 0; i < length; i += 2) {
|
||||
int sum = (1 << (FILTER_BITS - 1)) + input[i] * filter[0];
|
||||
for (j = 1; j < filter_len_half; ++j) {
|
||||
sum += (input[(i - j < 0 ? 0 : i - j)] +
|
||||
input[(i + j >= length ? length - 1 : i + j)]) *
|
||||
filter[j];
|
||||
}
|
||||
sum >>= FILTER_BITS;
|
||||
*optr++ = clip_pixel(sum);
|
||||
}
|
||||
} else {
|
||||
// Initial part.
|
||||
for (i = 0; i < l1; i += 2) {
|
||||
int sum = (1 << (FILTER_BITS - 1)) + input[i] * filter[0];
|
||||
for (j = 1; j < filter_len_half; ++j) {
|
||||
sum += (input[(i - j < 0 ? 0 : i - j)] + input[i + j]) * filter[j];
|
||||
}
|
||||
sum >>= FILTER_BITS;
|
||||
*optr++ = clip_pixel(sum);
|
||||
}
|
||||
// Middle part.
|
||||
for (; i < l2; i += 2) {
|
||||
int sum = (1 << (FILTER_BITS - 1)) + input[i] * filter[0];
|
||||
for (j = 1; j < filter_len_half; ++j) {
|
||||
sum += (input[i - j] + input[i + j]) * filter[j];
|
||||
}
|
||||
sum >>= FILTER_BITS;
|
||||
*optr++ = clip_pixel(sum);
|
||||
}
|
||||
// End part.
|
||||
for (; i < length; i += 2) {
|
||||
int sum = (1 << (FILTER_BITS - 1)) + input[i] * filter[0];
|
||||
for (j = 1; j < filter_len_half; ++j) {
|
||||
sum += (input[i - j] + input[(i + j >= length ? length - 1 : i + j)]) *
|
||||
filter[j];
|
||||
}
|
||||
sum >>= FILTER_BITS;
|
||||
*optr++ = clip_pixel(sum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int get_down2_length(int length, int steps) {
|
||||
int s;
|
||||
for (s = 0; s < steps; ++s) length = (length + 1) >> 1;
|
||||
return length;
|
||||
}
|
||||
|
||||
static int get_down2_steps(int in_length, int out_length) {
|
||||
int steps = 0;
|
||||
int proj_in_length;
|
||||
while ((proj_in_length = get_down2_length(in_length, 1)) >= out_length) {
|
||||
++steps;
|
||||
in_length = proj_in_length;
|
||||
}
|
||||
return steps;
|
||||
}
|
||||
|
||||
static void resize_multistep(const uint8_t *const input, int length,
|
||||
uint8_t *output, int olength, uint8_t *otmp) {
|
||||
int steps;
|
||||
if (length == olength) {
|
||||
memcpy(output, input, sizeof(output[0]) * length);
|
||||
return;
|
||||
}
|
||||
steps = get_down2_steps(length, olength);
|
||||
|
||||
if (steps > 0) {
|
||||
int s;
|
||||
uint8_t *out = NULL;
|
||||
uint8_t *otmp2;
|
||||
int filteredlength = length;
|
||||
|
||||
assert(otmp != NULL);
|
||||
otmp2 = otmp + get_down2_length(length, 1);
|
||||
for (s = 0; s < steps; ++s) {
|
||||
const int proj_filteredlength = get_down2_length(filteredlength, 1);
|
||||
const uint8_t *const in = (s == 0 ? input : out);
|
||||
if (s == steps - 1 && proj_filteredlength == olength)
|
||||
out = output;
|
||||
else
|
||||
out = (s & 1 ? otmp2 : otmp);
|
||||
if (filteredlength & 1)
|
||||
down2_symodd(in, filteredlength, out);
|
||||
else
|
||||
down2_symeven(in, filteredlength, out);
|
||||
filteredlength = proj_filteredlength;
|
||||
}
|
||||
if (filteredlength != olength) {
|
||||
interpolate(out, filteredlength, output, olength);
|
||||
}
|
||||
} else {
|
||||
interpolate(input, length, output, olength);
|
||||
}
|
||||
}
|
||||
|
||||
static void fill_col_to_arr(uint8_t *img, int stride, int len, uint8_t *arr) {
|
||||
int i;
|
||||
uint8_t *iptr = img;
|
||||
uint8_t *aptr = arr;
|
||||
for (i = 0; i < len; ++i, iptr += stride) {
|
||||
*aptr++ = *iptr;
|
||||
}
|
||||
}
|
||||
|
||||
static void fill_arr_to_col(uint8_t *img, int stride, int len, uint8_t *arr) {
|
||||
int i;
|
||||
uint8_t *iptr = img;
|
||||
uint8_t *aptr = arr;
|
||||
for (i = 0; i < len; ++i, iptr += stride) {
|
||||
*iptr = *aptr++;
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_resize_plane(const uint8_t *const input, int height, int width,
|
||||
int in_stride, uint8_t *output, int height2, int width2,
|
||||
int out_stride) {
|
||||
int i;
|
||||
uint8_t *intbuf = (uint8_t *)calloc(width2 * height, sizeof(*intbuf));
|
||||
uint8_t *tmpbuf =
|
||||
(uint8_t *)calloc(width < height ? height : width, sizeof(*tmpbuf));
|
||||
uint8_t *arrbuf = (uint8_t *)calloc(height, sizeof(*arrbuf));
|
||||
uint8_t *arrbuf2 = (uint8_t *)calloc(height2, sizeof(*arrbuf2));
|
||||
if (intbuf == NULL || tmpbuf == NULL || arrbuf == NULL || arrbuf2 == NULL)
|
||||
goto Error;
|
||||
assert(width > 0);
|
||||
assert(height > 0);
|
||||
assert(width2 > 0);
|
||||
assert(height2 > 0);
|
||||
for (i = 0; i < height; ++i)
|
||||
resize_multistep(input + in_stride * i, width, intbuf + width2 * i, width2,
|
||||
tmpbuf);
|
||||
for (i = 0; i < width2; ++i) {
|
||||
fill_col_to_arr(intbuf + i, width2, height, arrbuf);
|
||||
resize_multistep(arrbuf, height, arrbuf2, height2, tmpbuf);
|
||||
fill_arr_to_col(output + i, out_stride, height2, arrbuf2);
|
||||
}
|
||||
|
||||
Error:
|
||||
free(intbuf);
|
||||
free(tmpbuf);
|
||||
free(arrbuf);
|
||||
free(arrbuf2);
|
||||
}
|
||||
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
static void highbd_interpolate(const uint16_t *const input, int inlength,
|
||||
uint16_t *output, int outlength, int bd) {
|
||||
const int64_t delta =
|
||||
(((uint64_t)inlength << 32) + outlength / 2) / outlength;
|
||||
const int64_t offset =
|
||||
inlength > outlength
|
||||
? (((int64_t)(inlength - outlength) << 31) + outlength / 2) /
|
||||
outlength
|
||||
: -(((int64_t)(outlength - inlength) << 31) + outlength / 2) /
|
||||
outlength;
|
||||
uint16_t *optr = output;
|
||||
int x, x1, x2, sum, k, int_pel, sub_pel;
|
||||
int64_t y;
|
||||
|
||||
const interp_kernel *interp_filters =
|
||||
choose_interp_filter(inlength, outlength);
|
||||
|
||||
x = 0;
|
||||
y = offset;
|
||||
while ((y >> INTERP_PRECISION_BITS) < (INTERP_TAPS / 2 - 1)) {
|
||||
x++;
|
||||
y += delta;
|
||||
}
|
||||
x1 = x;
|
||||
x = outlength - 1;
|
||||
y = delta * x + offset;
|
||||
while ((y >> INTERP_PRECISION_BITS) + (int64_t)(INTERP_TAPS / 2) >=
|
||||
inlength) {
|
||||
x--;
|
||||
y -= delta;
|
||||
}
|
||||
x2 = x;
|
||||
if (x1 > x2) {
|
||||
for (x = 0, y = offset; x < outlength; ++x, y += delta) {
|
||||
const int16_t *filter;
|
||||
int_pel = y >> INTERP_PRECISION_BITS;
|
||||
sub_pel = (y >> (INTERP_PRECISION_BITS - SUBPEL_BITS)) & SUBPEL_MASK;
|
||||
filter = interp_filters[sub_pel];
|
||||
sum = 0;
|
||||
for (k = 0; k < INTERP_TAPS; ++k) {
|
||||
const int pk = int_pel - INTERP_TAPS / 2 + 1 + k;
|
||||
sum += filter[k] *
|
||||
input[(pk < 0 ? 0 : (pk >= inlength ? inlength - 1 : pk))];
|
||||
}
|
||||
*optr++ = clip_pixel_highbd(ROUND_POWER_OF_TWO(sum, FILTER_BITS), bd);
|
||||
}
|
||||
} else {
|
||||
// Initial part.
|
||||
for (x = 0, y = offset; x < x1; ++x, y += delta) {
|
||||
const int16_t *filter;
|
||||
int_pel = y >> INTERP_PRECISION_BITS;
|
||||
sub_pel = (y >> (INTERP_PRECISION_BITS - SUBPEL_BITS)) & SUBPEL_MASK;
|
||||
filter = interp_filters[sub_pel];
|
||||
sum = 0;
|
||||
for (k = 0; k < INTERP_TAPS; ++k) {
|
||||
assert(int_pel - INTERP_TAPS / 2 + 1 + k < inlength);
|
||||
sum += filter[k] * input[(int_pel - INTERP_TAPS / 2 + 1 + k < 0
|
||||
? 0
|
||||
: int_pel - INTERP_TAPS / 2 + 1 + k)];
|
||||
}
|
||||
*optr++ = clip_pixel_highbd(ROUND_POWER_OF_TWO(sum, FILTER_BITS), bd);
|
||||
}
|
||||
// Middle part.
|
||||
for (; x <= x2; ++x, y += delta) {
|
||||
const int16_t *filter;
|
||||
int_pel = y >> INTERP_PRECISION_BITS;
|
||||
sub_pel = (y >> (INTERP_PRECISION_BITS - SUBPEL_BITS)) & SUBPEL_MASK;
|
||||
filter = interp_filters[sub_pel];
|
||||
sum = 0;
|
||||
for (k = 0; k < INTERP_TAPS; ++k)
|
||||
sum += filter[k] * input[int_pel - INTERP_TAPS / 2 + 1 + k];
|
||||
*optr++ = clip_pixel_highbd(ROUND_POWER_OF_TWO(sum, FILTER_BITS), bd);
|
||||
}
|
||||
// End part.
|
||||
for (; x < outlength; ++x, y += delta) {
|
||||
const int16_t *filter;
|
||||
int_pel = y >> INTERP_PRECISION_BITS;
|
||||
sub_pel = (y >> (INTERP_PRECISION_BITS - SUBPEL_BITS)) & SUBPEL_MASK;
|
||||
filter = interp_filters[sub_pel];
|
||||
sum = 0;
|
||||
for (k = 0; k < INTERP_TAPS; ++k)
|
||||
sum += filter[k] * input[(int_pel - INTERP_TAPS / 2 + 1 + k >= inlength
|
||||
? inlength - 1
|
||||
: int_pel - INTERP_TAPS / 2 + 1 + k)];
|
||||
*optr++ = clip_pixel_highbd(ROUND_POWER_OF_TWO(sum, FILTER_BITS), bd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void highbd_down2_symeven(const uint16_t *const input, int length,
|
||||
uint16_t *output, int bd) {
|
||||
// Actual filter len = 2 * filter_len_half.
|
||||
static const int16_t *filter = vp9_down2_symeven_half_filter;
|
||||
const int filter_len_half = sizeof(vp9_down2_symeven_half_filter) / 2;
|
||||
int i, j;
|
||||
uint16_t *optr = output;
|
||||
int l1 = filter_len_half;
|
||||
int l2 = (length - filter_len_half);
|
||||
l1 += (l1 & 1);
|
||||
l2 += (l2 & 1);
|
||||
if (l1 > l2) {
|
||||
// Short input length.
|
||||
for (i = 0; i < length; i += 2) {
|
||||
int sum = (1 << (FILTER_BITS - 1));
|
||||
for (j = 0; j < filter_len_half; ++j) {
|
||||
sum += (input[(i - j < 0 ? 0 : i - j)] +
|
||||
input[(i + 1 + j >= length ? length - 1 : i + 1 + j)]) *
|
||||
filter[j];
|
||||
}
|
||||
sum >>= FILTER_BITS;
|
||||
*optr++ = clip_pixel_highbd(sum, bd);
|
||||
}
|
||||
} else {
|
||||
// Initial part.
|
||||
for (i = 0; i < l1; i += 2) {
|
||||
int sum = (1 << (FILTER_BITS - 1));
|
||||
for (j = 0; j < filter_len_half; ++j) {
|
||||
sum += (input[(i - j < 0 ? 0 : i - j)] + input[i + 1 + j]) * filter[j];
|
||||
}
|
||||
sum >>= FILTER_BITS;
|
||||
*optr++ = clip_pixel_highbd(sum, bd);
|
||||
}
|
||||
// Middle part.
|
||||
for (; i < l2; i += 2) {
|
||||
int sum = (1 << (FILTER_BITS - 1));
|
||||
for (j = 0; j < filter_len_half; ++j) {
|
||||
sum += (input[i - j] + input[i + 1 + j]) * filter[j];
|
||||
}
|
||||
sum >>= FILTER_BITS;
|
||||
*optr++ = clip_pixel_highbd(sum, bd);
|
||||
}
|
||||
// End part.
|
||||
for (; i < length; i += 2) {
|
||||
int sum = (1 << (FILTER_BITS - 1));
|
||||
for (j = 0; j < filter_len_half; ++j) {
|
||||
sum += (input[i - j] +
|
||||
input[(i + 1 + j >= length ? length - 1 : i + 1 + j)]) *
|
||||
filter[j];
|
||||
}
|
||||
sum >>= FILTER_BITS;
|
||||
*optr++ = clip_pixel_highbd(sum, bd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void highbd_down2_symodd(const uint16_t *const input, int length,
|
||||
uint16_t *output, int bd) {
|
||||
// Actual filter len = 2 * filter_len_half - 1.
|
||||
static const int16_t *filter = vp9_down2_symodd_half_filter;
|
||||
const int filter_len_half = sizeof(vp9_down2_symodd_half_filter) / 2;
|
||||
int i, j;
|
||||
uint16_t *optr = output;
|
||||
int l1 = filter_len_half - 1;
|
||||
int l2 = (length - filter_len_half + 1);
|
||||
l1 += (l1 & 1);
|
||||
l2 += (l2 & 1);
|
||||
if (l1 > l2) {
|
||||
// Short input length.
|
||||
for (i = 0; i < length; i += 2) {
|
||||
int sum = (1 << (FILTER_BITS - 1)) + input[i] * filter[0];
|
||||
for (j = 1; j < filter_len_half; ++j) {
|
||||
sum += (input[(i - j < 0 ? 0 : i - j)] +
|
||||
input[(i + j >= length ? length - 1 : i + j)]) *
|
||||
filter[j];
|
||||
}
|
||||
sum >>= FILTER_BITS;
|
||||
*optr++ = clip_pixel_highbd(sum, bd);
|
||||
}
|
||||
} else {
|
||||
// Initial part.
|
||||
for (i = 0; i < l1; i += 2) {
|
||||
int sum = (1 << (FILTER_BITS - 1)) + input[i] * filter[0];
|
||||
for (j = 1; j < filter_len_half; ++j) {
|
||||
sum += (input[(i - j < 0 ? 0 : i - j)] + input[i + j]) * filter[j];
|
||||
}
|
||||
sum >>= FILTER_BITS;
|
||||
*optr++ = clip_pixel_highbd(sum, bd);
|
||||
}
|
||||
// Middle part.
|
||||
for (; i < l2; i += 2) {
|
||||
int sum = (1 << (FILTER_BITS - 1)) + input[i] * filter[0];
|
||||
for (j = 1; j < filter_len_half; ++j) {
|
||||
sum += (input[i - j] + input[i + j]) * filter[j];
|
||||
}
|
||||
sum >>= FILTER_BITS;
|
||||
*optr++ = clip_pixel_highbd(sum, bd);
|
||||
}
|
||||
// End part.
|
||||
for (; i < length; i += 2) {
|
||||
int sum = (1 << (FILTER_BITS - 1)) + input[i] * filter[0];
|
||||
for (j = 1; j < filter_len_half; ++j) {
|
||||
sum += (input[i - j] + input[(i + j >= length ? length - 1 : i + j)]) *
|
||||
filter[j];
|
||||
}
|
||||
sum >>= FILTER_BITS;
|
||||
*optr++ = clip_pixel_highbd(sum, bd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void highbd_resize_multistep(const uint16_t *const input, int length,
|
||||
uint16_t *output, int olength,
|
||||
uint16_t *otmp, int bd) {
|
||||
int steps;
|
||||
if (length == olength) {
|
||||
memcpy(output, input, sizeof(output[0]) * length);
|
||||
return;
|
||||
}
|
||||
steps = get_down2_steps(length, olength);
|
||||
|
||||
if (steps > 0) {
|
||||
int s;
|
||||
uint16_t *out = NULL;
|
||||
uint16_t *otmp2;
|
||||
int filteredlength = length;
|
||||
|
||||
assert(otmp != NULL);
|
||||
otmp2 = otmp + get_down2_length(length, 1);
|
||||
for (s = 0; s < steps; ++s) {
|
||||
const int proj_filteredlength = get_down2_length(filteredlength, 1);
|
||||
const uint16_t *const in = (s == 0 ? input : out);
|
||||
if (s == steps - 1 && proj_filteredlength == olength)
|
||||
out = output;
|
||||
else
|
||||
out = (s & 1 ? otmp2 : otmp);
|
||||
if (filteredlength & 1)
|
||||
highbd_down2_symodd(in, filteredlength, out, bd);
|
||||
else
|
||||
highbd_down2_symeven(in, filteredlength, out, bd);
|
||||
filteredlength = proj_filteredlength;
|
||||
}
|
||||
if (filteredlength != olength) {
|
||||
highbd_interpolate(out, filteredlength, output, olength, bd);
|
||||
}
|
||||
} else {
|
||||
highbd_interpolate(input, length, output, olength, bd);
|
||||
}
|
||||
}
|
||||
|
||||
static void highbd_fill_col_to_arr(uint16_t *img, int stride, int len,
|
||||
uint16_t *arr) {
|
||||
int i;
|
||||
uint16_t *iptr = img;
|
||||
uint16_t *aptr = arr;
|
||||
for (i = 0; i < len; ++i, iptr += stride) {
|
||||
*aptr++ = *iptr;
|
||||
}
|
||||
}
|
||||
|
||||
static void highbd_fill_arr_to_col(uint16_t *img, int stride, int len,
|
||||
uint16_t *arr) {
|
||||
int i;
|
||||
uint16_t *iptr = img;
|
||||
uint16_t *aptr = arr;
|
||||
for (i = 0; i < len; ++i, iptr += stride) {
|
||||
*iptr = *aptr++;
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_highbd_resize_plane(const uint8_t *const input, int height, int width,
|
||||
int in_stride, uint8_t *output, int height2,
|
||||
int width2, int out_stride, int bd) {
|
||||
int i;
|
||||
uint16_t *intbuf = (uint16_t *)malloc(sizeof(uint16_t) * width2 * height);
|
||||
uint16_t *tmpbuf =
|
||||
(uint16_t *)malloc(sizeof(uint16_t) * (width < height ? height : width));
|
||||
uint16_t *arrbuf = (uint16_t *)malloc(sizeof(uint16_t) * height);
|
||||
uint16_t *arrbuf2 = (uint16_t *)malloc(sizeof(uint16_t) * height2);
|
||||
if (intbuf == NULL || tmpbuf == NULL || arrbuf == NULL || arrbuf2 == NULL)
|
||||
goto Error;
|
||||
assert(width > 0);
|
||||
assert(height > 0);
|
||||
assert(width2 > 0);
|
||||
assert(height2 > 0);
|
||||
for (i = 0; i < height; ++i) {
|
||||
highbd_resize_multistep(CONVERT_TO_SHORTPTR(input + in_stride * i), width,
|
||||
intbuf + width2 * i, width2, tmpbuf, bd);
|
||||
}
|
||||
for (i = 0; i < width2; ++i) {
|
||||
highbd_fill_col_to_arr(intbuf + i, width2, height, arrbuf);
|
||||
highbd_resize_multistep(arrbuf, height, arrbuf2, height2, tmpbuf, bd);
|
||||
highbd_fill_arr_to_col(CONVERT_TO_SHORTPTR(output + i), out_stride, height2,
|
||||
arrbuf2);
|
||||
}
|
||||
|
||||
Error:
|
||||
free(intbuf);
|
||||
free(tmpbuf);
|
||||
free(arrbuf);
|
||||
free(arrbuf2);
|
||||
}
|
||||
#endif // CONFIG_VP9_HIGHBITDEPTH
|
||||
|
||||
void vp9_resize_frame420(const uint8_t *const y, int y_stride,
|
||||
const uint8_t *const u, const uint8_t *const v,
|
||||
int uv_stride, int height, int width, uint8_t *oy,
|
||||
int oy_stride, uint8_t *ou, uint8_t *ov,
|
||||
int ouv_stride, int oheight, int owidth) {
|
||||
vp9_resize_plane(y, height, width, y_stride, oy, oheight, owidth, oy_stride);
|
||||
vp9_resize_plane(u, height / 2, width / 2, uv_stride, ou, oheight / 2,
|
||||
owidth / 2, ouv_stride);
|
||||
vp9_resize_plane(v, height / 2, width / 2, uv_stride, ov, oheight / 2,
|
||||
owidth / 2, ouv_stride);
|
||||
}
|
||||
|
||||
void vp9_resize_frame422(const uint8_t *const y, int y_stride,
|
||||
const uint8_t *const u, const uint8_t *const v,
|
||||
int uv_stride, int height, int width, uint8_t *oy,
|
||||
int oy_stride, uint8_t *ou, uint8_t *ov,
|
||||
int ouv_stride, int oheight, int owidth) {
|
||||
vp9_resize_plane(y, height, width, y_stride, oy, oheight, owidth, oy_stride);
|
||||
vp9_resize_plane(u, height, width / 2, uv_stride, ou, oheight, owidth / 2,
|
||||
ouv_stride);
|
||||
vp9_resize_plane(v, height, width / 2, uv_stride, ov, oheight, owidth / 2,
|
||||
ouv_stride);
|
||||
}
|
||||
|
||||
void vp9_resize_frame444(const uint8_t *const y, int y_stride,
|
||||
const uint8_t *const u, const uint8_t *const v,
|
||||
int uv_stride, int height, int width, uint8_t *oy,
|
||||
int oy_stride, uint8_t *ou, uint8_t *ov,
|
||||
int ouv_stride, int oheight, int owidth) {
|
||||
vp9_resize_plane(y, height, width, y_stride, oy, oheight, owidth, oy_stride);
|
||||
vp9_resize_plane(u, height, width, uv_stride, ou, oheight, owidth,
|
||||
ouv_stride);
|
||||
vp9_resize_plane(v, height, width, uv_stride, ov, oheight, owidth,
|
||||
ouv_stride);
|
||||
}
|
||||
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
void vp9_highbd_resize_frame420(const uint8_t *const y, int y_stride,
|
||||
const uint8_t *const u, const uint8_t *const v,
|
||||
int uv_stride, int height, int width,
|
||||
uint8_t *oy, int oy_stride, uint8_t *ou,
|
||||
uint8_t *ov, int ouv_stride, int oheight,
|
||||
int owidth, int bd) {
|
||||
vp9_highbd_resize_plane(y, height, width, y_stride, oy, oheight, owidth,
|
||||
oy_stride, bd);
|
||||
vp9_highbd_resize_plane(u, height / 2, width / 2, uv_stride, ou, oheight / 2,
|
||||
owidth / 2, ouv_stride, bd);
|
||||
vp9_highbd_resize_plane(v, height / 2, width / 2, uv_stride, ov, oheight / 2,
|
||||
owidth / 2, ouv_stride, bd);
|
||||
}
|
||||
|
||||
void vp9_highbd_resize_frame422(const uint8_t *const y, int y_stride,
|
||||
const uint8_t *const u, const uint8_t *const v,
|
||||
int uv_stride, int height, int width,
|
||||
uint8_t *oy, int oy_stride, uint8_t *ou,
|
||||
uint8_t *ov, int ouv_stride, int oheight,
|
||||
int owidth, int bd) {
|
||||
vp9_highbd_resize_plane(y, height, width, y_stride, oy, oheight, owidth,
|
||||
oy_stride, bd);
|
||||
vp9_highbd_resize_plane(u, height, width / 2, uv_stride, ou, oheight,
|
||||
owidth / 2, ouv_stride, bd);
|
||||
vp9_highbd_resize_plane(v, height, width / 2, uv_stride, ov, oheight,
|
||||
owidth / 2, ouv_stride, bd);
|
||||
}
|
||||
|
||||
void vp9_highbd_resize_frame444(const uint8_t *const y, int y_stride,
|
||||
const uint8_t *const u, const uint8_t *const v,
|
||||
int uv_stride, int height, int width,
|
||||
uint8_t *oy, int oy_stride, uint8_t *ou,
|
||||
uint8_t *ov, int ouv_stride, int oheight,
|
||||
int owidth, int bd) {
|
||||
vp9_highbd_resize_plane(y, height, width, y_stride, oy, oheight, owidth,
|
||||
oy_stride, bd);
|
||||
vp9_highbd_resize_plane(u, height, width, uv_stride, ou, oheight, owidth,
|
||||
ouv_stride, bd);
|
||||
vp9_highbd_resize_plane(v, height, width, uv_stride, ov, oheight, owidth,
|
||||
ouv_stride, bd);
|
||||
}
|
||||
#endif // CONFIG_VP9_HIGHBITDEPTH
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
#ifndef VPX_VP9_ENCODER_VP9_RESIZE_H_
|
||||
#define VPX_VP9_ENCODER_VP9_RESIZE_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include "vpx/vpx_integer.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void vp9_resize_plane(const uint8_t *const input, int height, int width,
|
||||
int in_stride, uint8_t *output, int height2, int width2,
|
||||
int out_stride);
|
||||
void vp9_resize_frame420(const uint8_t *const y, int y_stride,
|
||||
const uint8_t *const u, const uint8_t *const v,
|
||||
int uv_stride, int height, int width, uint8_t *oy,
|
||||
int oy_stride, uint8_t *ou, uint8_t *ov,
|
||||
int ouv_stride, int oheight, int owidth);
|
||||
void vp9_resize_frame422(const uint8_t *const y, int y_stride,
|
||||
const uint8_t *const u, const uint8_t *const v,
|
||||
int uv_stride, int height, int width, uint8_t *oy,
|
||||
int oy_stride, uint8_t *ou, uint8_t *ov,
|
||||
int ouv_stride, int oheight, int owidth);
|
||||
void vp9_resize_frame444(const uint8_t *const y, int y_stride,
|
||||
const uint8_t *const u, const uint8_t *const v,
|
||||
int uv_stride, int height, int width, uint8_t *oy,
|
||||
int oy_stride, uint8_t *ou, uint8_t *ov,
|
||||
int ouv_stride, int oheight, int owidth);
|
||||
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
void vp9_highbd_resize_plane(const uint8_t *const input, int height, int width,
|
||||
int in_stride, uint8_t *output, int height2,
|
||||
int width2, int out_stride, int bd);
|
||||
void vp9_highbd_resize_frame420(const uint8_t *const y, int y_stride,
|
||||
const uint8_t *const u, const uint8_t *const v,
|
||||
int uv_stride, int height, int width,
|
||||
uint8_t *oy, int oy_stride, uint8_t *ou,
|
||||
uint8_t *ov, int ouv_stride, int oheight,
|
||||
int owidth, int bd);
|
||||
void vp9_highbd_resize_frame422(const uint8_t *const y, int y_stride,
|
||||
const uint8_t *const u, const uint8_t *const v,
|
||||
int uv_stride, int height, int width,
|
||||
uint8_t *oy, int oy_stride, uint8_t *ou,
|
||||
uint8_t *ov, int ouv_stride, int oheight,
|
||||
int owidth, int bd);
|
||||
void vp9_highbd_resize_frame444(const uint8_t *const y, int y_stride,
|
||||
const uint8_t *const u, const uint8_t *const v,
|
||||
int uv_stride, int height, int width,
|
||||
uint8_t *oy, int oy_stride, uint8_t *ou,
|
||||
uint8_t *ov, int ouv_stride, int oheight,
|
||||
int owidth, int bd);
|
||||
#endif // CONFIG_VP9_HIGHBITDEPTH
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_ENCODER_VP9_RESIZE_H_
|
||||
@@ -0,0 +1,325 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebM project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "vpx_mem/vpx_mem.h"
|
||||
|
||||
#include "vp9/common/vp9_pred_common.h"
|
||||
#include "vp9/common/vp9_tile_common.h"
|
||||
|
||||
#include "vp9/encoder/vp9_cost.h"
|
||||
#include "vp9/encoder/vp9_segmentation.h"
|
||||
|
||||
void vp9_enable_segmentation(struct segmentation *seg) {
|
||||
seg->enabled = 1;
|
||||
seg->update_map = 1;
|
||||
seg->update_data = 1;
|
||||
}
|
||||
|
||||
void vp9_disable_segmentation(struct segmentation *seg) {
|
||||
seg->enabled = 0;
|
||||
seg->update_map = 0;
|
||||
seg->update_data = 0;
|
||||
}
|
||||
|
||||
void vp9_set_segment_data(struct segmentation *seg, signed char *feature_data,
|
||||
unsigned char abs_delta) {
|
||||
seg->abs_delta = abs_delta;
|
||||
|
||||
memcpy(seg->feature_data, feature_data, sizeof(seg->feature_data));
|
||||
}
|
||||
void vp9_disable_segfeature(struct segmentation *seg, int segment_id,
|
||||
SEG_LVL_FEATURES feature_id) {
|
||||
seg->feature_mask[segment_id] &= ~(1 << feature_id);
|
||||
}
|
||||
|
||||
void vp9_clear_segdata(struct segmentation *seg, int segment_id,
|
||||
SEG_LVL_FEATURES feature_id) {
|
||||
seg->feature_data[segment_id][feature_id] = 0;
|
||||
}
|
||||
|
||||
void vp9_psnr_aq_mode_setup(struct segmentation *seg) {
|
||||
int i;
|
||||
|
||||
vp9_enable_segmentation(seg);
|
||||
vp9_clearall_segfeatures(seg);
|
||||
seg->abs_delta = SEGMENT_DELTADATA;
|
||||
|
||||
for (i = 0; i < MAX_SEGMENTS; ++i) {
|
||||
vp9_set_segdata(seg, i, SEG_LVL_ALT_Q, 2 * (i - (MAX_SEGMENTS / 2)));
|
||||
vp9_enable_segfeature(seg, i, SEG_LVL_ALT_Q);
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_perceptual_aq_mode_setup(struct VP9_COMP *cpi,
|
||||
struct segmentation *seg) {
|
||||
const VP9_COMMON *cm = &cpi->common;
|
||||
const int seg_counts = cpi->kmeans_ctr_num;
|
||||
const int base_qindex = cm->base_qindex;
|
||||
const double base_qstep = vp9_convert_qindex_to_q(base_qindex, cm->bit_depth);
|
||||
const double mid_ctr = cpi->kmeans_ctr_ls[seg_counts / 2];
|
||||
const double var_diff_scale = 4.0;
|
||||
int i;
|
||||
|
||||
assert(seg_counts <= MAX_SEGMENTS);
|
||||
|
||||
vp9_enable_segmentation(seg);
|
||||
vp9_clearall_segfeatures(seg);
|
||||
seg->abs_delta = SEGMENT_DELTADATA;
|
||||
|
||||
for (i = 0; i < seg_counts / 2; ++i) {
|
||||
double wiener_var_diff = mid_ctr - cpi->kmeans_ctr_ls[i];
|
||||
double target_qstep = base_qstep / (1.0 + wiener_var_diff / var_diff_scale);
|
||||
int target_qindex = vp9_convert_q_to_qindex(target_qstep, cm->bit_depth);
|
||||
assert(wiener_var_diff >= 0.0);
|
||||
|
||||
vp9_set_segdata(seg, i, SEG_LVL_ALT_Q, target_qindex - base_qindex);
|
||||
vp9_enable_segfeature(seg, i, SEG_LVL_ALT_Q);
|
||||
}
|
||||
|
||||
vp9_set_segdata(seg, i, SEG_LVL_ALT_Q, 0);
|
||||
vp9_enable_segfeature(seg, i, SEG_LVL_ALT_Q);
|
||||
|
||||
for (; i < seg_counts; ++i) {
|
||||
double wiener_var_diff = cpi->kmeans_ctr_ls[i] - mid_ctr;
|
||||
double target_qstep = base_qstep * (1.0 + wiener_var_diff / var_diff_scale);
|
||||
int target_qindex = vp9_convert_q_to_qindex(target_qstep, cm->bit_depth);
|
||||
assert(wiener_var_diff >= 0.0);
|
||||
|
||||
vp9_set_segdata(seg, i, SEG_LVL_ALT_Q, target_qindex - base_qindex);
|
||||
vp9_enable_segfeature(seg, i, SEG_LVL_ALT_Q);
|
||||
}
|
||||
}
|
||||
|
||||
// Based on set of segment counts calculate a probability tree
|
||||
static void calc_segtree_probs(int *segcounts, vpx_prob *segment_tree_probs) {
|
||||
// Work out probabilities of each segment
|
||||
const int c01 = segcounts[0] + segcounts[1];
|
||||
const int c23 = segcounts[2] + segcounts[3];
|
||||
const int c45 = segcounts[4] + segcounts[5];
|
||||
const int c67 = segcounts[6] + segcounts[7];
|
||||
|
||||
segment_tree_probs[0] = get_binary_prob(c01 + c23, c45 + c67);
|
||||
segment_tree_probs[1] = get_binary_prob(c01, c23);
|
||||
segment_tree_probs[2] = get_binary_prob(c45, c67);
|
||||
segment_tree_probs[3] = get_binary_prob(segcounts[0], segcounts[1]);
|
||||
segment_tree_probs[4] = get_binary_prob(segcounts[2], segcounts[3]);
|
||||
segment_tree_probs[5] = get_binary_prob(segcounts[4], segcounts[5]);
|
||||
segment_tree_probs[6] = get_binary_prob(segcounts[6], segcounts[7]);
|
||||
}
|
||||
|
||||
// Based on set of segment counts and probabilities calculate a cost estimate
|
||||
static int cost_segmap(int *segcounts, vpx_prob *probs) {
|
||||
const int c01 = segcounts[0] + segcounts[1];
|
||||
const int c23 = segcounts[2] + segcounts[3];
|
||||
const int c45 = segcounts[4] + segcounts[5];
|
||||
const int c67 = segcounts[6] + segcounts[7];
|
||||
const int c0123 = c01 + c23;
|
||||
const int c4567 = c45 + c67;
|
||||
|
||||
// Cost the top node of the tree
|
||||
int cost = c0123 * vp9_cost_zero(probs[0]) + c4567 * vp9_cost_one(probs[0]);
|
||||
|
||||
// Cost subsequent levels
|
||||
if (c0123 > 0) {
|
||||
cost += c01 * vp9_cost_zero(probs[1]) + c23 * vp9_cost_one(probs[1]);
|
||||
|
||||
if (c01 > 0)
|
||||
cost += segcounts[0] * vp9_cost_zero(probs[3]) +
|
||||
segcounts[1] * vp9_cost_one(probs[3]);
|
||||
if (c23 > 0)
|
||||
cost += segcounts[2] * vp9_cost_zero(probs[4]) +
|
||||
segcounts[3] * vp9_cost_one(probs[4]);
|
||||
}
|
||||
|
||||
if (c4567 > 0) {
|
||||
cost += c45 * vp9_cost_zero(probs[2]) + c67 * vp9_cost_one(probs[2]);
|
||||
|
||||
if (c45 > 0)
|
||||
cost += segcounts[4] * vp9_cost_zero(probs[5]) +
|
||||
segcounts[5] * vp9_cost_one(probs[5]);
|
||||
if (c67 > 0)
|
||||
cost += segcounts[6] * vp9_cost_zero(probs[6]) +
|
||||
segcounts[7] * vp9_cost_one(probs[6]);
|
||||
}
|
||||
|
||||
return cost;
|
||||
}
|
||||
|
||||
static void count_segs(const VP9_COMMON *cm, MACROBLOCKD *xd,
|
||||
const TileInfo *tile, MODE_INFO **mi,
|
||||
int *no_pred_segcounts,
|
||||
int (*temporal_predictor_count)[2],
|
||||
int *t_unpred_seg_counts, int bw, int bh, int mi_row,
|
||||
int mi_col) {
|
||||
int segment_id;
|
||||
|
||||
if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols) return;
|
||||
|
||||
xd->mi = mi;
|
||||
segment_id = xd->mi[0]->segment_id;
|
||||
|
||||
set_mi_row_col(xd, tile, mi_row, bh, mi_col, bw, cm->mi_rows, cm->mi_cols);
|
||||
|
||||
// Count the number of hits on each segment with no prediction
|
||||
no_pred_segcounts[segment_id]++;
|
||||
|
||||
// Temporal prediction not allowed on key frames
|
||||
if (cm->frame_type != KEY_FRAME) {
|
||||
const BLOCK_SIZE bsize = xd->mi[0]->sb_type;
|
||||
// Test to see if the segment id matches the predicted value.
|
||||
const int pred_segment_id =
|
||||
get_segment_id(cm, cm->last_frame_seg_map, bsize, mi_row, mi_col);
|
||||
const int pred_flag = pred_segment_id == segment_id;
|
||||
const int pred_context = vp9_get_pred_context_seg_id(xd);
|
||||
|
||||
// Store the prediction status for this mb and update counts
|
||||
// as appropriate
|
||||
xd->mi[0]->seg_id_predicted = pred_flag;
|
||||
temporal_predictor_count[pred_context][pred_flag]++;
|
||||
|
||||
// Update the "unpredicted" segment count
|
||||
if (!pred_flag) t_unpred_seg_counts[segment_id]++;
|
||||
}
|
||||
}
|
||||
|
||||
static void count_segs_sb(const VP9_COMMON *cm, MACROBLOCKD *xd,
|
||||
const TileInfo *tile, MODE_INFO **mi,
|
||||
int *no_pred_segcounts,
|
||||
int (*temporal_predictor_count)[2],
|
||||
int *t_unpred_seg_counts, int mi_row, int mi_col,
|
||||
BLOCK_SIZE bsize) {
|
||||
const int mis = cm->mi_stride;
|
||||
int bw, bh;
|
||||
const int bs = num_8x8_blocks_wide_lookup[bsize], hbs = bs / 2;
|
||||
|
||||
if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols) return;
|
||||
|
||||
bw = num_8x8_blocks_wide_lookup[mi[0]->sb_type];
|
||||
bh = num_8x8_blocks_high_lookup[mi[0]->sb_type];
|
||||
|
||||
if (bw == bs && bh == bs) {
|
||||
count_segs(cm, xd, tile, mi, no_pred_segcounts, temporal_predictor_count,
|
||||
t_unpred_seg_counts, bs, bs, mi_row, mi_col);
|
||||
} else if (bw == bs && bh < bs) {
|
||||
count_segs(cm, xd, tile, mi, no_pred_segcounts, temporal_predictor_count,
|
||||
t_unpred_seg_counts, bs, hbs, mi_row, mi_col);
|
||||
count_segs(cm, xd, tile, mi + hbs * mis, no_pred_segcounts,
|
||||
temporal_predictor_count, t_unpred_seg_counts, bs, hbs,
|
||||
mi_row + hbs, mi_col);
|
||||
} else if (bw < bs && bh == bs) {
|
||||
count_segs(cm, xd, tile, mi, no_pred_segcounts, temporal_predictor_count,
|
||||
t_unpred_seg_counts, hbs, bs, mi_row, mi_col);
|
||||
count_segs(cm, xd, tile, mi + hbs, no_pred_segcounts,
|
||||
temporal_predictor_count, t_unpred_seg_counts, hbs, bs, mi_row,
|
||||
mi_col + hbs);
|
||||
} else {
|
||||
const BLOCK_SIZE subsize = subsize_lookup[PARTITION_SPLIT][bsize];
|
||||
int n;
|
||||
|
||||
assert(bw < bs && bh < bs);
|
||||
|
||||
for (n = 0; n < 4; n++) {
|
||||
const int mi_dc = hbs * (n & 1);
|
||||
const int mi_dr = hbs * (n >> 1);
|
||||
|
||||
count_segs_sb(cm, xd, tile, &mi[mi_dr * mis + mi_dc], no_pred_segcounts,
|
||||
temporal_predictor_count, t_unpred_seg_counts,
|
||||
mi_row + mi_dr, mi_col + mi_dc, subsize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_choose_segmap_coding_method(VP9_COMMON *cm, MACROBLOCKD *xd) {
|
||||
struct segmentation *seg = &cm->seg;
|
||||
|
||||
int no_pred_cost;
|
||||
int t_pred_cost = INT_MAX;
|
||||
|
||||
int i, tile_col, mi_row, mi_col;
|
||||
|
||||
int temporal_predictor_count[PREDICTION_PROBS][2] = { { 0 } };
|
||||
int no_pred_segcounts[MAX_SEGMENTS] = { 0 };
|
||||
int t_unpred_seg_counts[MAX_SEGMENTS] = { 0 };
|
||||
|
||||
vpx_prob no_pred_tree[SEG_TREE_PROBS];
|
||||
vpx_prob t_pred_tree[SEG_TREE_PROBS];
|
||||
vpx_prob t_nopred_prob[PREDICTION_PROBS];
|
||||
|
||||
// Set default state for the segment tree probabilities and the
|
||||
// temporal coding probabilities
|
||||
memset(seg->tree_probs, 255, sizeof(seg->tree_probs));
|
||||
memset(seg->pred_probs, 255, sizeof(seg->pred_probs));
|
||||
|
||||
// First of all generate stats regarding how well the last segment map
|
||||
// predicts this one
|
||||
for (tile_col = 0; tile_col < 1 << cm->log2_tile_cols; tile_col++) {
|
||||
TileInfo tile;
|
||||
MODE_INFO **mi_ptr;
|
||||
vp9_tile_init(&tile, cm, 0, tile_col);
|
||||
|
||||
mi_ptr = cm->mi_grid_visible + tile.mi_col_start;
|
||||
for (mi_row = 0; mi_row < cm->mi_rows;
|
||||
mi_row += 8, mi_ptr += 8 * cm->mi_stride) {
|
||||
MODE_INFO **mi = mi_ptr;
|
||||
for (mi_col = tile.mi_col_start; mi_col < tile.mi_col_end;
|
||||
mi_col += 8, mi += 8)
|
||||
count_segs_sb(cm, xd, &tile, mi, no_pred_segcounts,
|
||||
temporal_predictor_count, t_unpred_seg_counts, mi_row,
|
||||
mi_col, BLOCK_64X64);
|
||||
}
|
||||
}
|
||||
|
||||
// Work out probability tree for coding segments without prediction
|
||||
// and the cost.
|
||||
calc_segtree_probs(no_pred_segcounts, no_pred_tree);
|
||||
no_pred_cost = cost_segmap(no_pred_segcounts, no_pred_tree);
|
||||
|
||||
// Key frames cannot use temporal prediction
|
||||
if (!frame_is_intra_only(cm)) {
|
||||
// Work out probability tree for coding those segments not
|
||||
// predicted using the temporal method and the cost.
|
||||
calc_segtree_probs(t_unpred_seg_counts, t_pred_tree);
|
||||
t_pred_cost = cost_segmap(t_unpred_seg_counts, t_pred_tree);
|
||||
|
||||
// Add in the cost of the signaling for each prediction context.
|
||||
for (i = 0; i < PREDICTION_PROBS; i++) {
|
||||
const int count0 = temporal_predictor_count[i][0];
|
||||
const int count1 = temporal_predictor_count[i][1];
|
||||
|
||||
t_nopred_prob[i] = get_binary_prob(count0, count1);
|
||||
|
||||
// Add in the predictor signaling cost
|
||||
t_pred_cost += count0 * vp9_cost_zero(t_nopred_prob[i]) +
|
||||
count1 * vp9_cost_one(t_nopred_prob[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Now choose which coding method to use.
|
||||
if (t_pred_cost < no_pred_cost) {
|
||||
seg->temporal_update = 1;
|
||||
memcpy(seg->tree_probs, t_pred_tree, sizeof(t_pred_tree));
|
||||
memcpy(seg->pred_probs, t_nopred_prob, sizeof(t_nopred_prob));
|
||||
} else {
|
||||
seg->temporal_update = 0;
|
||||
memcpy(seg->tree_probs, no_pred_tree, sizeof(no_pred_tree));
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_reset_segment_features(struct segmentation *seg) {
|
||||
// Set up default state for MB feature flags
|
||||
seg->enabled = 0;
|
||||
seg->update_map = 0;
|
||||
seg->update_data = 0;
|
||||
memset(seg->tree_probs, 255, sizeof(seg->tree_probs));
|
||||
vp9_clearall_segfeatures(seg);
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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_ENCODER_VP9_SEGMENTATION_H_
|
||||
#define VPX_VP9_ENCODER_VP9_SEGMENTATION_H_
|
||||
|
||||
#include "vp9/common/vp9_blockd.h"
|
||||
#include "vp9/encoder/vp9_encoder.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void vp9_enable_segmentation(struct segmentation *seg);
|
||||
void vp9_disable_segmentation(struct segmentation *seg);
|
||||
|
||||
void vp9_disable_segfeature(struct segmentation *seg, int segment_id,
|
||||
SEG_LVL_FEATURES feature_id);
|
||||
void vp9_clear_segdata(struct segmentation *seg, int segment_id,
|
||||
SEG_LVL_FEATURES feature_id);
|
||||
|
||||
void vp9_psnr_aq_mode_setup(struct segmentation *seg);
|
||||
|
||||
void vp9_perceptual_aq_mode_setup(struct VP9_COMP *cpi,
|
||||
struct segmentation *seg);
|
||||
|
||||
// The values given for each segment can be either deltas (from the default
|
||||
// value chosen for the frame) or absolute values.
|
||||
//
|
||||
// Valid range for abs values is (0-127 for MB_LVL_ALT_Q), (0-63 for
|
||||
// SEGMENT_ALT_LF)
|
||||
// Valid range for delta values are (+/-127 for MB_LVL_ALT_Q), (+/-63 for
|
||||
// SEGMENT_ALT_LF)
|
||||
//
|
||||
// abs_delta = SEGMENT_DELTADATA (deltas) abs_delta = SEGMENT_ABSDATA (use
|
||||
// the absolute values given).
|
||||
void vp9_set_segment_data(struct segmentation *seg, signed char *feature_data,
|
||||
unsigned char abs_delta);
|
||||
|
||||
void vp9_choose_segmap_coding_method(VP9_COMMON *cm, MACROBLOCKD *xd);
|
||||
|
||||
void vp9_reset_segment_features(struct segmentation *seg);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_ENCODER_VP9_SEGMENTATION_H_
|
||||
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Copyright (c) 2015 The WebM project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "vp9/common/vp9_blockd.h"
|
||||
#include "vp9/encoder/vp9_encoder.h"
|
||||
#include "vp9/encoder/vp9_skin_detection.h"
|
||||
|
||||
int vp9_compute_skin_block(const uint8_t *y, const uint8_t *u, const uint8_t *v,
|
||||
int stride, int strideuv, int bsize,
|
||||
int consec_zeromv, int curr_motion_magn) {
|
||||
// No skin if block has been zero/small motion for long consecutive time.
|
||||
if (consec_zeromv > 60 && curr_motion_magn == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
int motion = 1;
|
||||
// Take center pixel in block to determine is_skin.
|
||||
const int y_width_shift = (4 << b_width_log2_lookup[bsize]) >> 1;
|
||||
const int y_height_shift = (4 << b_height_log2_lookup[bsize]) >> 1;
|
||||
const int uv_width_shift = y_width_shift >> 1;
|
||||
const int uv_height_shift = y_height_shift >> 1;
|
||||
const uint8_t ysource = y[y_height_shift * stride + y_width_shift];
|
||||
const uint8_t usource = u[uv_height_shift * strideuv + uv_width_shift];
|
||||
const uint8_t vsource = v[uv_height_shift * strideuv + uv_width_shift];
|
||||
|
||||
if (consec_zeromv > 25 && curr_motion_magn == 0) motion = 0;
|
||||
return vpx_skin_pixel(ysource, usource, vsource, motion);
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_compute_skin_sb(VP9_COMP *const cpi, BLOCK_SIZE bsize, int mi_row,
|
||||
int mi_col) {
|
||||
int i, j, num_bl;
|
||||
VP9_COMMON *const cm = &cpi->common;
|
||||
const uint8_t *src_y = cpi->Source->y_buffer;
|
||||
const uint8_t *src_u = cpi->Source->u_buffer;
|
||||
const uint8_t *src_v = cpi->Source->v_buffer;
|
||||
const int src_ystride = cpi->Source->y_stride;
|
||||
const int src_uvstride = cpi->Source->uv_stride;
|
||||
const int y_bsize = 4 << b_width_log2_lookup[bsize];
|
||||
const int uv_bsize = y_bsize >> 1;
|
||||
const int shy = (y_bsize == 8) ? 3 : 4;
|
||||
const int shuv = shy - 1;
|
||||
const int fac = y_bsize / 8;
|
||||
const int y_shift = src_ystride * (mi_row << 3) + (mi_col << 3);
|
||||
const int uv_shift = src_uvstride * (mi_row << 2) + (mi_col << 2);
|
||||
const int mi_row_limit = VPXMIN(mi_row + 8, cm->mi_rows - 2);
|
||||
const int mi_col_limit = VPXMIN(mi_col + 8, cm->mi_cols - 2);
|
||||
src_y += y_shift;
|
||||
src_u += uv_shift;
|
||||
src_v += uv_shift;
|
||||
|
||||
for (i = mi_row; i < mi_row_limit; i += fac) {
|
||||
num_bl = 0;
|
||||
for (j = mi_col; j < mi_col_limit; j += fac) {
|
||||
int consec_zeromv = 0;
|
||||
int bl_index = i * cm->mi_cols + j;
|
||||
int bl_index1 = bl_index + 1;
|
||||
int bl_index2 = bl_index + cm->mi_cols;
|
||||
int bl_index3 = bl_index2 + 1;
|
||||
// Don't detect skin on the boundary.
|
||||
if (i == 0 || j == 0) continue;
|
||||
if (bsize == BLOCK_8X8)
|
||||
consec_zeromv = cpi->consec_zero_mv[bl_index];
|
||||
else
|
||||
consec_zeromv = VPXMIN(cpi->consec_zero_mv[bl_index],
|
||||
VPXMIN(cpi->consec_zero_mv[bl_index1],
|
||||
VPXMIN(cpi->consec_zero_mv[bl_index2],
|
||||
cpi->consec_zero_mv[bl_index3])));
|
||||
cpi->skin_map[bl_index] =
|
||||
vp9_compute_skin_block(src_y, src_u, src_v, src_ystride, src_uvstride,
|
||||
bsize, consec_zeromv, 0);
|
||||
num_bl++;
|
||||
src_y += y_bsize;
|
||||
src_u += uv_bsize;
|
||||
src_v += uv_bsize;
|
||||
}
|
||||
src_y += (src_ystride << shy) - (num_bl << shy);
|
||||
src_u += (src_uvstride << shuv) - (num_bl << shuv);
|
||||
src_v += (src_uvstride << shuv) - (num_bl << shuv);
|
||||
}
|
||||
|
||||
// Remove isolated skin blocks (none of its neighbors are skin) and isolated
|
||||
// non-skin blocks (all of its neighbors are skin).
|
||||
// Skip 4 corner blocks which have only 3 neighbors to remove isolated skin
|
||||
// blocks. Skip superblock borders to remove isolated non-skin blocks.
|
||||
for (i = mi_row; i < mi_row_limit; i += fac) {
|
||||
for (j = mi_col; j < mi_col_limit; j += fac) {
|
||||
int bl_index = i * cm->mi_cols + j;
|
||||
int num_neighbor = 0;
|
||||
int mi, mj;
|
||||
int non_skin_threshold = 8;
|
||||
// Skip 4 corners.
|
||||
if ((i == mi_row && (j == mi_col || j == mi_col_limit - fac)) ||
|
||||
(i == mi_row_limit - fac && (j == mi_col || j == mi_col_limit - fac)))
|
||||
continue;
|
||||
// There are only 5 neighbors for non-skin blocks on the border.
|
||||
if (i == mi_row || i == mi_row_limit - fac || j == mi_col ||
|
||||
j == mi_col_limit - fac)
|
||||
non_skin_threshold = 5;
|
||||
|
||||
for (mi = -fac; mi <= fac; mi += fac) {
|
||||
for (mj = -fac; mj <= fac; mj += fac) {
|
||||
if (i + mi >= mi_row && i + mi < mi_row_limit && j + mj >= mi_col &&
|
||||
j + mj < mi_col_limit) {
|
||||
int bl_neighbor_index = (i + mi) * cm->mi_cols + j + mj;
|
||||
if (cpi->skin_map[bl_neighbor_index]) num_neighbor++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cpi->skin_map[bl_index] && num_neighbor < 2)
|
||||
cpi->skin_map[bl_index] = 0;
|
||||
if (!cpi->skin_map[bl_index] && num_neighbor == non_skin_threshold)
|
||||
cpi->skin_map[bl_index] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef OUTPUT_YUV_SKINMAP
|
||||
// For viewing skin map on input source.
|
||||
void vp9_output_skin_map(VP9_COMP *const cpi, FILE *yuv_skinmap_file) {
|
||||
int i, j, mi_row, mi_col, num_bl;
|
||||
VP9_COMMON *const cm = &cpi->common;
|
||||
uint8_t *y;
|
||||
const uint8_t *src_y = cpi->Source->y_buffer;
|
||||
const int src_ystride = cpi->Source->y_stride;
|
||||
const int y_bsize = 16; // Use 8x8 or 16x16.
|
||||
const int shy = (y_bsize == 8) ? 3 : 4;
|
||||
const int fac = y_bsize / 8;
|
||||
|
||||
YV12_BUFFER_CONFIG skinmap;
|
||||
memset(&skinmap, 0, sizeof(YV12_BUFFER_CONFIG));
|
||||
if (vpx_alloc_frame_buffer(&skinmap, cm->width, cm->height, cm->subsampling_x,
|
||||
cm->subsampling_y, VP9_ENC_BORDER_IN_PIXELS,
|
||||
cm->byte_alignment)) {
|
||||
vpx_free_frame_buffer(&skinmap);
|
||||
return;
|
||||
}
|
||||
memset(skinmap.buffer_alloc, 128, skinmap.frame_size);
|
||||
y = skinmap.y_buffer;
|
||||
// Loop through blocks and set skin map based on center pixel of block.
|
||||
// Set y to white for skin block, otherwise set to source with gray scale.
|
||||
// Ignore rightmost/bottom boundary blocks.
|
||||
for (mi_row = 0; mi_row < cm->mi_rows - 1; mi_row += fac) {
|
||||
num_bl = 0;
|
||||
for (mi_col = 0; mi_col < cm->mi_cols - 1; mi_col += fac) {
|
||||
const int block_index = mi_row * cm->mi_cols + mi_col;
|
||||
const int is_skin = cpi->skin_map[block_index];
|
||||
for (i = 0; i < y_bsize; i++) {
|
||||
for (j = 0; j < y_bsize; j++) {
|
||||
y[i * src_ystride + j] = is_skin ? 255 : src_y[i * src_ystride + j];
|
||||
}
|
||||
}
|
||||
num_bl++;
|
||||
y += y_bsize;
|
||||
src_y += y_bsize;
|
||||
}
|
||||
y += (src_ystride << shy) - (num_bl << shy);
|
||||
src_y += (src_ystride << shy) - (num_bl << shy);
|
||||
}
|
||||
vpx_write_yuv_frame(yuv_skinmap_file, &skinmap);
|
||||
vpx_free_frame_buffer(&skinmap);
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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_VP9_SKIN_DETECTION_H_
|
||||
#define VPX_VP9_ENCODER_VP9_SKIN_DETECTION_H_
|
||||
|
||||
#include "vp9/common/vp9_blockd.h"
|
||||
#include "vpx_dsp/skin_detection.h"
|
||||
#include "vpx_util/vpx_write_yuv_frame.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct VP9_COMP;
|
||||
|
||||
int vp9_compute_skin_block(const uint8_t *y, const uint8_t *u, const uint8_t *v,
|
||||
int stride, int strideuv, int bsize,
|
||||
int consec_zeromv, int curr_motion_magn);
|
||||
|
||||
void vp9_compute_skin_sb(struct VP9_COMP *const cpi, BLOCK_SIZE bsize,
|
||||
int mi_row, int mi_col);
|
||||
|
||||
#ifdef OUTPUT_YUV_SKINMAP
|
||||
// For viewing skin map on input source.
|
||||
void vp9_output_skin_map(struct VP9_COMP *const cpi, FILE *yuv_skinmap_file);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_ENCODER_VP9_SKIN_DETECTION_H_
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,628 @@
|
||||
/*
|
||||
* 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_ENCODER_VP9_SPEED_FEATURES_H_
|
||||
#define VPX_VP9_ENCODER_VP9_SPEED_FEATURES_H_
|
||||
|
||||
#include "vp9/common/vp9_enums.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum {
|
||||
INTRA_ALL = (1 << DC_PRED) | (1 << V_PRED) | (1 << H_PRED) | (1 << D45_PRED) |
|
||||
(1 << D135_PRED) | (1 << D117_PRED) | (1 << D153_PRED) |
|
||||
(1 << D207_PRED) | (1 << D63_PRED) | (1 << TM_PRED),
|
||||
INTRA_DC = (1 << DC_PRED),
|
||||
INTRA_DC_TM = (1 << DC_PRED) | (1 << TM_PRED),
|
||||
INTRA_DC_H_V = (1 << DC_PRED) | (1 << V_PRED) | (1 << H_PRED),
|
||||
INTRA_DC_TM_H_V =
|
||||
(1 << DC_PRED) | (1 << TM_PRED) | (1 << V_PRED) | (1 << H_PRED)
|
||||
};
|
||||
|
||||
enum {
|
||||
INTER_ALL = (1 << NEARESTMV) | (1 << NEARMV) | (1 << ZEROMV) | (1 << NEWMV),
|
||||
INTER_NEAREST = (1 << NEARESTMV),
|
||||
INTER_NEAREST_NEW = (1 << NEARESTMV) | (1 << NEWMV),
|
||||
INTER_NEAREST_ZERO = (1 << NEARESTMV) | (1 << ZEROMV),
|
||||
INTER_NEAREST_NEW_ZERO = (1 << NEARESTMV) | (1 << ZEROMV) | (1 << NEWMV),
|
||||
INTER_NEAREST_NEAR_NEW = (1 << NEARESTMV) | (1 << NEARMV) | (1 << NEWMV),
|
||||
INTER_NEAREST_NEAR_ZERO = (1 << NEARESTMV) | (1 << NEARMV) | (1 << ZEROMV),
|
||||
};
|
||||
|
||||
enum {
|
||||
DISABLE_ALL_INTER_SPLIT = (1 << THR_COMP_GA) | (1 << THR_COMP_LA) |
|
||||
(1 << THR_ALTR) | (1 << THR_GOLD) | (1 << THR_LAST),
|
||||
|
||||
DISABLE_ALL_SPLIT = (1 << THR_INTRA) | DISABLE_ALL_INTER_SPLIT,
|
||||
|
||||
DISABLE_COMPOUND_SPLIT = (1 << THR_COMP_GA) | (1 << THR_COMP_LA),
|
||||
|
||||
LAST_AND_INTRA_SPLIT_ONLY = (1 << THR_COMP_GA) | (1 << THR_COMP_LA) |
|
||||
(1 << THR_ALTR) | (1 << THR_GOLD)
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
DIAMOND = 0,
|
||||
NSTEP = 1,
|
||||
HEX = 2,
|
||||
BIGDIA = 3,
|
||||
SQUARE = 4,
|
||||
FAST_HEX = 5,
|
||||
FAST_DIAMOND = 6,
|
||||
MESH = 7
|
||||
} SEARCH_METHODS;
|
||||
|
||||
typedef enum {
|
||||
// No recode.
|
||||
DISALLOW_RECODE = 0,
|
||||
// Allow recode for KF and exceeding maximum frame bandwidth.
|
||||
ALLOW_RECODE_KFMAXBW = 1,
|
||||
// Allow recode only for KF/ARF/GF frames.
|
||||
ALLOW_RECODE_KFARFGF = 2,
|
||||
// Allow recode for ARF/GF/KF and first normal frame in each group.
|
||||
ALLOW_RECODE_FIRST = 3,
|
||||
// Allow recode for all frames based on bitrate constraints.
|
||||
ALLOW_RECODE = 4,
|
||||
} RECODE_LOOP_TYPE;
|
||||
|
||||
typedef enum {
|
||||
SUBPEL_TREE = 0,
|
||||
SUBPEL_TREE_PRUNED = 1, // Prunes 1/2-pel searches
|
||||
SUBPEL_TREE_PRUNED_MORE = 2, // Prunes 1/2-pel searches more aggressively
|
||||
SUBPEL_TREE_PRUNED_EVENMORE = 3, // Prunes 1/2- and 1/4-pel searches
|
||||
// Other methods to come
|
||||
} SUBPEL_SEARCH_METHODS;
|
||||
|
||||
typedef enum {
|
||||
NO_MOTION_THRESHOLD = 0,
|
||||
LOW_MOTION_THRESHOLD = 7
|
||||
} MOTION_THRESHOLD;
|
||||
|
||||
typedef enum {
|
||||
USE_FULL_RD = 0,
|
||||
USE_LARGESTALL,
|
||||
USE_TX_8X8
|
||||
} TX_SIZE_SEARCH_METHOD;
|
||||
|
||||
typedef enum {
|
||||
NOT_IN_USE = 0,
|
||||
RELAXED_NEIGHBORING_MIN_MAX = 1,
|
||||
STRICT_NEIGHBORING_MIN_MAX = 2
|
||||
} AUTO_MIN_MAX_MODE;
|
||||
|
||||
typedef enum {
|
||||
// Try the full image with different values.
|
||||
LPF_PICK_FROM_FULL_IMAGE,
|
||||
// Try a small portion of the image with different values.
|
||||
LPF_PICK_FROM_SUBIMAGE,
|
||||
// Estimate the level based on quantizer and frame type
|
||||
LPF_PICK_FROM_Q,
|
||||
// Pick 0 to disable LPF if LPF was enabled last frame
|
||||
LPF_PICK_MINIMAL_LPF
|
||||
} LPF_PICK_METHOD;
|
||||
|
||||
typedef enum {
|
||||
// Terminate search early based on distortion so far compared to
|
||||
// qp step, distortion in the neighborhood of the frame, etc.
|
||||
FLAG_EARLY_TERMINATE = 1 << 0,
|
||||
|
||||
// Skips comp inter modes if the best so far is an intra mode.
|
||||
FLAG_SKIP_COMP_BESTINTRA = 1 << 1,
|
||||
|
||||
// Skips oblique intra modes if the best so far is an inter mode.
|
||||
FLAG_SKIP_INTRA_BESTINTER = 1 << 3,
|
||||
|
||||
// Skips oblique intra modes at angles 27, 63, 117, 153 if the best
|
||||
// intra so far is not one of the neighboring directions.
|
||||
FLAG_SKIP_INTRA_DIRMISMATCH = 1 << 4,
|
||||
|
||||
// Skips intra modes other than DC_PRED if the source variance is small
|
||||
FLAG_SKIP_INTRA_LOWVAR = 1 << 5,
|
||||
} MODE_SEARCH_SKIP_LOGIC;
|
||||
|
||||
typedef enum {
|
||||
FLAG_SKIP_EIGHTTAP = 1 << EIGHTTAP,
|
||||
FLAG_SKIP_EIGHTTAP_SMOOTH = 1 << EIGHTTAP_SMOOTH,
|
||||
FLAG_SKIP_EIGHTTAP_SHARP = 1 << EIGHTTAP_SHARP,
|
||||
} INTERP_FILTER_MASK;
|
||||
|
||||
typedef enum {
|
||||
// Search partitions using RD/NONRD criterion.
|
||||
SEARCH_PARTITION,
|
||||
|
||||
// Always use a fixed size partition.
|
||||
FIXED_PARTITION,
|
||||
|
||||
REFERENCE_PARTITION,
|
||||
|
||||
// Use an arbitrary partitioning scheme based on source variance within
|
||||
// a 64X64 SB.
|
||||
VAR_BASED_PARTITION,
|
||||
|
||||
// Use non-fixed partitions based on source variance.
|
||||
SOURCE_VAR_BASED_PARTITION,
|
||||
|
||||
// Make partition decisions with machine learning models.
|
||||
ML_BASED_PARTITION
|
||||
} PARTITION_SEARCH_TYPE;
|
||||
|
||||
typedef enum {
|
||||
// Does a dry run to see if any of the contexts need to be updated or not,
|
||||
// before the final run.
|
||||
TWO_LOOP = 0,
|
||||
|
||||
// No dry run, also only half the coef contexts and bands are updated.
|
||||
// The rest are not updated at all.
|
||||
ONE_LOOP_REDUCED = 1
|
||||
} FAST_COEFF_UPDATE;
|
||||
|
||||
typedef enum { EIGHTH_PEL, QUARTER_PEL, HALF_PEL, FULL_PEL } SUBPEL_FORCE_STOP;
|
||||
|
||||
typedef struct ADAPT_SUBPEL_FORCE_STOP {
|
||||
// Threshold for full pixel motion vector;
|
||||
int mv_thresh;
|
||||
|
||||
// subpel_force_stop if full pixel MV is below the threshold.
|
||||
SUBPEL_FORCE_STOP force_stop_below;
|
||||
|
||||
// subpel_force_stop if full pixel MV is equal to or above the threshold.
|
||||
SUBPEL_FORCE_STOP force_stop_above;
|
||||
} ADAPT_SUBPEL_FORCE_STOP;
|
||||
|
||||
typedef struct MV_SPEED_FEATURES {
|
||||
// Motion search method (Diamond, NSTEP, Hex, Big Diamond, Square, etc).
|
||||
SEARCH_METHODS search_method;
|
||||
|
||||
// This parameter controls which step in the n-step process we start at.
|
||||
// It's changed adaptively based on circumstances.
|
||||
int reduce_first_step_size;
|
||||
|
||||
// If this is set to 1, we limit the motion search range to 2 times the
|
||||
// largest motion vector found in the last frame.
|
||||
int auto_mv_step_size;
|
||||
|
||||
// Subpel_search_method can only be subpel_tree which does a subpixel
|
||||
// logarithmic search that keeps stepping at 1/2 pixel units until
|
||||
// you stop getting a gain, and then goes on to 1/4 and repeats
|
||||
// the same process. Along the way it skips many diagonals.
|
||||
SUBPEL_SEARCH_METHODS subpel_search_method;
|
||||
|
||||
// Subpel MV search level. Can take values 0 - 2. Higher values mean more
|
||||
// extensive subpel search.
|
||||
int subpel_search_level;
|
||||
|
||||
// When to stop subpel motion search.
|
||||
SUBPEL_FORCE_STOP subpel_force_stop;
|
||||
|
||||
// If it's enabled, different subpel_force_stop will be used for different MV.
|
||||
int enable_adaptive_subpel_force_stop;
|
||||
|
||||
ADAPT_SUBPEL_FORCE_STOP adapt_subpel_force_stop;
|
||||
|
||||
// This variable sets the step_param used in full pel motion search.
|
||||
int fullpel_search_step_param;
|
||||
} MV_SPEED_FEATURES;
|
||||
|
||||
typedef struct PARTITION_SEARCH_BREAKOUT_THR {
|
||||
int64_t dist;
|
||||
int rate;
|
||||
} PARTITION_SEARCH_BREAKOUT_THR;
|
||||
|
||||
#define MAX_MESH_STEP 4
|
||||
|
||||
typedef struct MESH_PATTERN {
|
||||
int range;
|
||||
int interval;
|
||||
} MESH_PATTERN;
|
||||
|
||||
typedef enum {
|
||||
// No reaction to rate control on a detected slide/scene change.
|
||||
NO_DETECTION = 0,
|
||||
|
||||
// Set to larger Q (max_q set by user) based only on the
|
||||
// detected slide/scene change and current/past Q.
|
||||
FAST_DETECTION_MAXQ = 1,
|
||||
|
||||
// Based on (first pass) encoded frame, if large frame size is detected
|
||||
// then set to higher Q for the second re-encode. This involves 2 pass
|
||||
// encoding on slide change, so slower than 1, but more accurate for
|
||||
// detecting overshoot.
|
||||
RE_ENCODE_MAXQ = 2
|
||||
} OVERSHOOT_DETECTION_CBR_RT;
|
||||
|
||||
typedef enum {
|
||||
USE_2_TAPS = 0,
|
||||
USE_4_TAPS,
|
||||
USE_8_TAPS,
|
||||
USE_8_TAPS_SHARP,
|
||||
} SUBPEL_SEARCH_TYPE;
|
||||
|
||||
typedef struct SPEED_FEATURES {
|
||||
MV_SPEED_FEATURES mv;
|
||||
|
||||
// Frame level coding parameter update
|
||||
int frame_parameter_update;
|
||||
|
||||
RECODE_LOOP_TYPE recode_loop;
|
||||
|
||||
// Trellis (dynamic programming) optimization of quantized values (+1, 0).
|
||||
int optimize_coefficients;
|
||||
|
||||
// Always set to 0. If on it enables 0 cost background transmission
|
||||
// (except for the initial transmission of the segmentation). The feature is
|
||||
// disabled because the addition of very large block sizes make the
|
||||
// backgrounds very to cheap to encode, and the segmentation we have
|
||||
// adds overhead.
|
||||
int static_segmentation;
|
||||
|
||||
// If 1 we iterate finding a best reference for 2 ref frames together - via
|
||||
// a log search that iterates 4 times (check around mv for last for best
|
||||
// error of combined predictor then check around mv for alt). If 0 we
|
||||
// we just use the best motion vector found for each frame by itself.
|
||||
BLOCK_SIZE comp_inter_joint_search_thresh;
|
||||
|
||||
// This variable is used to cap the maximum number of times we skip testing a
|
||||
// mode to be evaluated. A high value means we will be faster.
|
||||
// Turned off when (row_mt_bit_exact == 1 && adaptive_rd_thresh_row_mt == 0).
|
||||
int adaptive_rd_thresh;
|
||||
|
||||
// Flag to use adaptive_rd_thresh when row-mt it enabled, only for non-rd
|
||||
// pickmode.
|
||||
int adaptive_rd_thresh_row_mt;
|
||||
|
||||
// Enables skipping the reconstruction step (idct, recon) in the
|
||||
// intermediate steps assuming the last frame didn't have too many intra
|
||||
// blocks and the q is less than a threshold.
|
||||
int skip_encode_sb;
|
||||
int skip_encode_frame;
|
||||
// Speed feature to allow or disallow skipping of recode at block
|
||||
// level within a frame.
|
||||
int allow_skip_recode;
|
||||
|
||||
// Coefficient probability model approximation step size
|
||||
int coeff_prob_appx_step;
|
||||
|
||||
// Enable uniform quantizer followed by trellis coefficient optimization
|
||||
int allow_quant_coeff_opt;
|
||||
double quant_opt_thresh;
|
||||
|
||||
// Enable asymptotic closed-loop encoding decision for key frame and
|
||||
// alternate reference frames.
|
||||
int allow_acl;
|
||||
|
||||
// Temporal dependency model based encoding mode optimization
|
||||
int enable_tpl_model;
|
||||
|
||||
// Use transform domain distortion. Use pixel domain distortion in speed 0
|
||||
// and certain situations in higher speed to improve the RD model precision.
|
||||
int allow_txfm_domain_distortion;
|
||||
double tx_domain_thresh;
|
||||
|
||||
// The threshold is to determine how slow the motino is, it is used when
|
||||
// use_lastframe_partitioning is set to LAST_FRAME_PARTITION_LOW_MOTION
|
||||
MOTION_THRESHOLD lf_motion_threshold;
|
||||
|
||||
// Determine which method we use to determine transform size. We can choose
|
||||
// between options like full rd, largest for prediction size, largest
|
||||
// for intra and model coefs for the rest.
|
||||
TX_SIZE_SEARCH_METHOD tx_size_search_method;
|
||||
|
||||
// How many levels of tx size to search, starting from the largest.
|
||||
int tx_size_search_depth;
|
||||
|
||||
// Low precision 32x32 fdct keeps everything in 16 bits and thus is less
|
||||
// precise but significantly faster than the non lp version.
|
||||
int use_lp32x32fdct;
|
||||
|
||||
// After looking at the first set of modes (set by index here), skip
|
||||
// checking modes for reference frames that don't match the reference frame
|
||||
// of the best so far.
|
||||
int mode_skip_start;
|
||||
|
||||
// TODO(JBB): Remove this.
|
||||
int reference_masking;
|
||||
|
||||
PARTITION_SEARCH_TYPE partition_search_type;
|
||||
|
||||
// Used if partition_search_type = FIXED_SIZE_PARTITION
|
||||
BLOCK_SIZE always_this_block_size;
|
||||
|
||||
// Skip rectangular partition test when partition type none gives better
|
||||
// rd than partition type split.
|
||||
int less_rectangular_check;
|
||||
|
||||
// Disable testing non square partitions(eg 16x32) for block sizes larger than
|
||||
// use_square_only_thresh_high or smaller than use_square_only_thresh_low.
|
||||
int use_square_partition_only;
|
||||
BLOCK_SIZE use_square_only_thresh_high;
|
||||
BLOCK_SIZE use_square_only_thresh_low;
|
||||
|
||||
// Prune reference frames for rectangular partitions.
|
||||
int prune_ref_frame_for_rect_partitions;
|
||||
|
||||
// Sets min and max partition sizes for this 64x64 region based on the
|
||||
// same 64x64 in last encoded frame, and the left and above neighbor.
|
||||
AUTO_MIN_MAX_MODE auto_min_max_partition_size;
|
||||
// Ensures the rd based auto partition search will always
|
||||
// go down at least to the specified level.
|
||||
BLOCK_SIZE rd_auto_partition_min_limit;
|
||||
|
||||
// Min and max partition size we enable (block_size) as per auto
|
||||
// min max, but also used by adjust partitioning, and pick_partitioning.
|
||||
BLOCK_SIZE default_min_partition_size;
|
||||
BLOCK_SIZE default_max_partition_size;
|
||||
|
||||
// Whether or not we allow partitions one smaller or one greater than the last
|
||||
// frame's partitioning. Only used if use_lastframe_partitioning is set.
|
||||
int adjust_partitioning_from_last_frame;
|
||||
|
||||
// How frequently we re do the partitioning from scratch. Only used if
|
||||
// use_lastframe_partitioning is set.
|
||||
int last_partitioning_redo_frequency;
|
||||
|
||||
// Disables sub 8x8 blocksizes in different scenarios: Choices are to disable
|
||||
// it always, to allow it for only Last frame and Intra, disable it for all
|
||||
// inter modes or to enable it always.
|
||||
int disable_split_mask;
|
||||
|
||||
// TODO(jingning): combine the related motion search speed features
|
||||
// This allows us to use motion search at other sizes as a starting
|
||||
// point for this motion search and limits the search range around it.
|
||||
int adaptive_motion_search;
|
||||
|
||||
// Do extra full pixel motion search to obtain better motion vector.
|
||||
int enhanced_full_pixel_motion_search;
|
||||
|
||||
// Threshold for allowing exhaistive motion search.
|
||||
int exhaustive_searches_thresh;
|
||||
|
||||
// Pattern to be used for any exhaustive mesh searches.
|
||||
MESH_PATTERN mesh_patterns[MAX_MESH_STEP];
|
||||
|
||||
int schedule_mode_search;
|
||||
|
||||
// Allows sub 8x8 modes to use the prediction filter that was determined
|
||||
// best for 8x8 mode. If set to 0 we always re check all the filters for
|
||||
// sizes less than 8x8, 1 means we check all filter modes if no 8x8 filter
|
||||
// was selected, and 2 means we use 8 tap if no 8x8 filter mode was selected.
|
||||
int adaptive_pred_interp_filter;
|
||||
|
||||
// Adaptive prediction mode search
|
||||
int adaptive_mode_search;
|
||||
|
||||
// Chessboard pattern prediction filter type search
|
||||
int cb_pred_filter_search;
|
||||
|
||||
int cb_partition_search;
|
||||
|
||||
int motion_field_mode_search;
|
||||
|
||||
int alt_ref_search_fp;
|
||||
|
||||
// Fast quantization process path
|
||||
int use_quant_fp;
|
||||
|
||||
// Use finer quantizer in every other few frames that run variable block
|
||||
// partition type search.
|
||||
int force_frame_boost;
|
||||
|
||||
// Maximally allowed base quantization index fluctuation.
|
||||
int max_delta_qindex;
|
||||
|
||||
// Implements various heuristics to skip searching modes
|
||||
// The heuristics selected are based on flags
|
||||
// defined in the MODE_SEARCH_SKIP_HEURISTICS enum
|
||||
unsigned int mode_search_skip_flags;
|
||||
|
||||
// A source variance threshold below which filter search is disabled
|
||||
// Choose a very large value (UINT_MAX) to use 8-tap always
|
||||
unsigned int disable_filter_search_var_thresh;
|
||||
|
||||
// These bit masks allow you to enable or disable intra modes for each
|
||||
// transform size separately.
|
||||
int intra_y_mode_mask[TX_SIZES];
|
||||
int intra_uv_mode_mask[TX_SIZES];
|
||||
|
||||
// These bit masks allow you to enable or disable intra modes for each
|
||||
// prediction block size separately.
|
||||
int intra_y_mode_bsize_mask[BLOCK_SIZES];
|
||||
|
||||
// This variable enables an early break out of mode testing if the model for
|
||||
// rd built from the prediction signal indicates a value that's much
|
||||
// higher than the best rd we've seen so far.
|
||||
int use_rd_breakout;
|
||||
|
||||
// This enables us to use an estimate for intra rd based on dc mode rather
|
||||
// than choosing an actual uv mode in the stage of encoding before the actual
|
||||
// final encode.
|
||||
int use_uv_intra_rd_estimate;
|
||||
|
||||
// This feature controls how the loop filter level is determined.
|
||||
LPF_PICK_METHOD lpf_pick;
|
||||
|
||||
// This feature limits the number of coefficients updates we actually do
|
||||
// by only looking at counts from 1/2 the bands.
|
||||
FAST_COEFF_UPDATE use_fast_coef_updates;
|
||||
|
||||
// This flag controls the use of non-RD mode decision.
|
||||
int use_nonrd_pick_mode;
|
||||
|
||||
// A binary mask indicating if NEARESTMV, NEARMV, ZEROMV, NEWMV
|
||||
// modes are used in order from LSB to MSB for each BLOCK_SIZE.
|
||||
int inter_mode_mask[BLOCK_SIZES];
|
||||
|
||||
// This feature controls whether we do the expensive context update and
|
||||
// calculation in the rd coefficient costing loop.
|
||||
int use_fast_coef_costing;
|
||||
|
||||
// This feature controls the tolerence vs target used in deciding whether to
|
||||
// recode a frame. It has no meaning if recode is disabled.
|
||||
int recode_tolerance_low;
|
||||
int recode_tolerance_high;
|
||||
|
||||
// This variable controls the maximum block size where intra blocks can be
|
||||
// used in inter frames.
|
||||
// TODO(aconverse): Fold this into one of the other many mode skips
|
||||
BLOCK_SIZE max_intra_bsize;
|
||||
|
||||
// The frequency that we check if SOURCE_VAR_BASED_PARTITION or
|
||||
// FIXED_PARTITION search type should be used.
|
||||
int search_type_check_frequency;
|
||||
|
||||
// When partition is pre-set, the inter prediction result from pick_inter_mode
|
||||
// can be reused in final block encoding process. It is enabled only for real-
|
||||
// time mode speed 6.
|
||||
int reuse_inter_pred_sby;
|
||||
|
||||
// This variable sets the encode_breakout threshold. Currently, it is only
|
||||
// enabled in real time mode.
|
||||
int encode_breakout_thresh;
|
||||
|
||||
// default interp filter choice
|
||||
INTERP_FILTER default_interp_filter;
|
||||
|
||||
// Early termination in transform size search, which only applies while
|
||||
// tx_size_search_method is USE_FULL_RD.
|
||||
int tx_size_search_breakout;
|
||||
|
||||
// adaptive interp_filter search to allow skip of certain filter types.
|
||||
int adaptive_interp_filter_search;
|
||||
|
||||
// mask for skip evaluation of certain interp_filter type.
|
||||
INTERP_FILTER_MASK interp_filter_search_mask;
|
||||
|
||||
// Partition search early breakout thresholds.
|
||||
PARTITION_SEARCH_BREAKOUT_THR partition_search_breakout_thr;
|
||||
|
||||
struct {
|
||||
// Use ML-based partition search early breakout.
|
||||
int search_breakout;
|
||||
// Higher values mean more aggressiveness for partition search breakout that
|
||||
// results in better encoding speed but worse compression performance.
|
||||
float search_breakout_thresh[3];
|
||||
|
||||
// Machine-learning based partition search early termination
|
||||
int search_early_termination;
|
||||
|
||||
// Machine-learning based partition search pruning using prediction residue
|
||||
// variance.
|
||||
int var_pruning;
|
||||
|
||||
// Threshold values used for ML based rectangular partition search pruning.
|
||||
// If < 0, the feature is turned off.
|
||||
// Higher values mean more aggressiveness to skip rectangular partition
|
||||
// search that results in better encoding speed but worse coding
|
||||
// performance.
|
||||
int prune_rect_thresh[4];
|
||||
} rd_ml_partition;
|
||||
|
||||
// Allow skipping partition search for still image frame
|
||||
int allow_partition_search_skip;
|
||||
|
||||
// Fast approximation of vp9_model_rd_from_var_lapndz
|
||||
int simple_model_rd_from_var;
|
||||
|
||||
// Skip a number of expensive mode evaluations for blocks with zero source
|
||||
// variance.
|
||||
int short_circuit_flat_blocks;
|
||||
|
||||
// Skip a number of expensive mode evaluations for blocks with very low
|
||||
// temporal variance. If the low temporal variance flag is set for a block,
|
||||
// do the following:
|
||||
// 1: Skip all golden modes and ALL INTRA for bsize >= 32x32.
|
||||
// 2: Skip golden non-zeromv and newmv-last for bsize >= 16x16, skip ALL
|
||||
// INTRA for bsize >= 32x32 and vert/horz INTRA for bsize 16x16, 16x32 and
|
||||
// 32x16.
|
||||
// 3: Same as (2), but also skip golden zeromv.
|
||||
int short_circuit_low_temp_var;
|
||||
|
||||
// Limits the rd-threshold update for early exit for the newmv-last mode,
|
||||
// for non-rd mode.
|
||||
int limit_newmv_early_exit;
|
||||
|
||||
// Adds a bias against golden reference, for non-rd mode.
|
||||
int bias_golden;
|
||||
|
||||
// Bias to use base mv and skip 1/4 subpel search when use base mv in
|
||||
// enhancement layer.
|
||||
int base_mv_aggressive;
|
||||
|
||||
// Global flag to enable partition copy from the previous frame.
|
||||
int copy_partition_flag;
|
||||
|
||||
// Compute the source sad for every superblock of the frame,
|
||||
// prior to encoding the frame, to be used to bypass some encoder decisions.
|
||||
int use_source_sad;
|
||||
|
||||
int use_simple_block_yrd;
|
||||
|
||||
// If source sad of superblock is high (> adapt_partition_thresh), will switch
|
||||
// from VARIANCE_PARTITION to REFERENCE_PARTITION (which selects partition
|
||||
// based on the nonrd-pickmode).
|
||||
int adapt_partition_source_sad;
|
||||
int adapt_partition_thresh;
|
||||
|
||||
// Enable use of alt-refs in 1 pass VBR.
|
||||
int use_altref_onepass;
|
||||
|
||||
// Enable use of compound prediction, for nonrd_pickmode with nonzero lag.
|
||||
int use_compound_nonrd_pickmode;
|
||||
|
||||
// Always use nonrd_pick_intra for all block sizes on keyframes.
|
||||
int nonrd_keyframe;
|
||||
|
||||
// For SVC: enables use of partition from lower spatial resolution.
|
||||
int svc_use_lowres_part;
|
||||
|
||||
// Flag to indicate process for handling overshoot on slide/scene change,
|
||||
// for real-time CBR mode.
|
||||
OVERSHOOT_DETECTION_CBR_RT overshoot_detection_cbr_rt;
|
||||
|
||||
// Disable partitioning of 16x16 blocks.
|
||||
int disable_16x16part_nonkey;
|
||||
|
||||
// Allow for disabling golden reference.
|
||||
int disable_golden_ref;
|
||||
|
||||
// Allow sub-pixel search to use interpolation filters with different taps in
|
||||
// order to achieve accurate motion search result.
|
||||
SUBPEL_SEARCH_TYPE use_accurate_subpel_search;
|
||||
|
||||
// Search method used by temporal filtering in full_pixel_motion_search.
|
||||
SEARCH_METHODS temporal_filter_search_method;
|
||||
|
||||
// Use machine learning based partition search.
|
||||
int nonrd_use_ml_partition;
|
||||
|
||||
// Multiplier for base thresold for variance partitioning.
|
||||
int variance_part_thresh_mult;
|
||||
|
||||
// Force subpel motion filter to always use SMOOTH_FILTER.
|
||||
int force_smooth_interpol;
|
||||
|
||||
// For real-time mode: force DC only under intra search when content
|
||||
// does not have high souce SAD.
|
||||
int rt_intra_dc_only_low_content;
|
||||
} SPEED_FEATURES;
|
||||
|
||||
struct VP9_COMP;
|
||||
|
||||
void vp9_set_speed_features_framesize_independent(struct VP9_COMP *cpi,
|
||||
int speed);
|
||||
void vp9_set_speed_features_framesize_dependent(struct VP9_COMP *cpi,
|
||||
int speed);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_ENCODER_VP9_SPEED_FEATURES_H_
|
||||
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* 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/bitwriter.h"
|
||||
|
||||
#include "vp9/common/vp9_common.h"
|
||||
#include "vp9/common/vp9_entropy.h"
|
||||
#include "vp9/encoder/vp9_cost.h"
|
||||
#include "vp9/encoder/vp9_subexp.h"
|
||||
|
||||
static const uint8_t update_bits[255] = {
|
||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6,
|
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 8, 8, 8, 8, 8, 8,
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
||||
8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11,
|
||||
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
|
||||
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
|
||||
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
|
||||
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
|
||||
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
|
||||
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
|
||||
11, 11, 11, 11, 11, 11, 11, 0,
|
||||
};
|
||||
#define MIN_DELP_BITS 5
|
||||
|
||||
static int recenter_nonneg(int v, int m) {
|
||||
if (v > (m << 1))
|
||||
return v;
|
||||
else if (v >= m)
|
||||
return ((v - m) << 1);
|
||||
else
|
||||
return ((m - v) << 1) - 1;
|
||||
}
|
||||
|
||||
static int remap_prob(int v, int m) {
|
||||
int i;
|
||||
static const uint8_t map_table[MAX_PROB - 1] = {
|
||||
// generated by:
|
||||
// map_table[j] = split_index(j, MAX_PROB - 1, MODULUS_PARAM);
|
||||
20, 21, 22, 23, 24, 25, 0, 26, 27, 28, 29, 30, 31, 32, 33,
|
||||
34, 35, 36, 37, 1, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
|
||||
48, 49, 2, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
|
||||
3, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 4, 74,
|
||||
75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 5, 86, 87, 88,
|
||||
89, 90, 91, 92, 93, 94, 95, 96, 97, 6, 98, 99, 100, 101, 102,
|
||||
103, 104, 105, 106, 107, 108, 109, 7, 110, 111, 112, 113, 114, 115, 116,
|
||||
117, 118, 119, 120, 121, 8, 122, 123, 124, 125, 126, 127, 128, 129, 130,
|
||||
131, 132, 133, 9, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144,
|
||||
145, 10, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 11,
|
||||
158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 12, 170, 171,
|
||||
172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 13, 182, 183, 184, 185,
|
||||
186, 187, 188, 189, 190, 191, 192, 193, 14, 194, 195, 196, 197, 198, 199,
|
||||
200, 201, 202, 203, 204, 205, 15, 206, 207, 208, 209, 210, 211, 212, 213,
|
||||
214, 215, 216, 217, 16, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227,
|
||||
228, 229, 17, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241,
|
||||
18, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 19,
|
||||
};
|
||||
v--;
|
||||
m--;
|
||||
if ((m << 1) <= MAX_PROB)
|
||||
i = recenter_nonneg(v, m) - 1;
|
||||
else
|
||||
i = recenter_nonneg(MAX_PROB - 1 - v, MAX_PROB - 1 - m) - 1;
|
||||
|
||||
assert(i >= 0 && (size_t)i < sizeof(map_table));
|
||||
i = map_table[i];
|
||||
return i;
|
||||
}
|
||||
|
||||
static int prob_diff_update_cost(vpx_prob newp, vpx_prob oldp) {
|
||||
int delp = remap_prob(newp, oldp);
|
||||
return update_bits[delp] << VP9_PROB_COST_SHIFT;
|
||||
}
|
||||
|
||||
static void encode_uniform(vpx_writer *w, int v) {
|
||||
const int l = 8;
|
||||
const int m = (1 << l) - 191;
|
||||
if (v < m) {
|
||||
vpx_write_literal(w, v, l - 1);
|
||||
} else {
|
||||
vpx_write_literal(w, m + ((v - m) >> 1), l - 1);
|
||||
vpx_write_literal(w, (v - m) & 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static INLINE int write_bit_gte(vpx_writer *w, int word, int test) {
|
||||
vpx_write_literal(w, word >= test, 1);
|
||||
return word >= test;
|
||||
}
|
||||
|
||||
static void encode_term_subexp(vpx_writer *w, int word) {
|
||||
if (!write_bit_gte(w, word, 16)) {
|
||||
vpx_write_literal(w, word, 4);
|
||||
} else if (!write_bit_gte(w, word, 32)) {
|
||||
vpx_write_literal(w, word - 16, 4);
|
||||
} else if (!write_bit_gte(w, word, 64)) {
|
||||
vpx_write_literal(w, word - 32, 5);
|
||||
} else {
|
||||
encode_uniform(w, word - 64);
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_write_prob_diff_update(vpx_writer *w, vpx_prob newp, vpx_prob oldp) {
|
||||
const int delp = remap_prob(newp, oldp);
|
||||
encode_term_subexp(w, delp);
|
||||
}
|
||||
|
||||
int vp9_prob_diff_update_savings_search(const unsigned int *ct, vpx_prob oldp,
|
||||
vpx_prob *bestp, vpx_prob upd) {
|
||||
const int old_b = cost_branch256(ct, oldp);
|
||||
int bestsavings = 0;
|
||||
vpx_prob newp, bestnewp = oldp;
|
||||
const int step = *bestp > oldp ? -1 : 1;
|
||||
const int upd_cost = vp9_cost_one(upd) - vp9_cost_zero(upd);
|
||||
|
||||
if (old_b > upd_cost + (MIN_DELP_BITS << VP9_PROB_COST_SHIFT)) {
|
||||
for (newp = *bestp; newp != oldp; newp += step) {
|
||||
const int new_b = cost_branch256(ct, newp);
|
||||
const int update_b = prob_diff_update_cost(newp, oldp) + upd_cost;
|
||||
const int savings = old_b - new_b - update_b;
|
||||
if (savings > bestsavings) {
|
||||
bestsavings = savings;
|
||||
bestnewp = newp;
|
||||
}
|
||||
}
|
||||
}
|
||||
*bestp = bestnewp;
|
||||
return bestsavings;
|
||||
}
|
||||
|
||||
int vp9_prob_diff_update_savings_search_model(const unsigned int *ct,
|
||||
const vpx_prob oldp,
|
||||
vpx_prob *bestp, vpx_prob upd,
|
||||
int stepsize) {
|
||||
int i, old_b, new_b, update_b, savings, bestsavings;
|
||||
int newp;
|
||||
const int step_sign = *bestp > oldp ? -1 : 1;
|
||||
const int step = stepsize * step_sign;
|
||||
const int upd_cost = vp9_cost_one(upd) - vp9_cost_zero(upd);
|
||||
const vpx_prob *newplist, *oldplist;
|
||||
vpx_prob bestnewp;
|
||||
oldplist = vp9_pareto8_full[oldp - 1];
|
||||
old_b = cost_branch256(ct + 2 * PIVOT_NODE, oldp);
|
||||
for (i = UNCONSTRAINED_NODES; i < ENTROPY_NODES; ++i)
|
||||
old_b += cost_branch256(ct + 2 * i, oldplist[i - UNCONSTRAINED_NODES]);
|
||||
|
||||
bestsavings = 0;
|
||||
bestnewp = oldp;
|
||||
|
||||
assert(stepsize > 0);
|
||||
|
||||
if (old_b > upd_cost + (MIN_DELP_BITS << VP9_PROB_COST_SHIFT)) {
|
||||
for (newp = *bestp; (newp - oldp) * step_sign < 0; newp += step) {
|
||||
if (newp < 1 || newp > 255) continue;
|
||||
newplist = vp9_pareto8_full[newp - 1];
|
||||
new_b = cost_branch256(ct + 2 * PIVOT_NODE, newp);
|
||||
for (i = UNCONSTRAINED_NODES; i < ENTROPY_NODES; ++i)
|
||||
new_b += cost_branch256(ct + 2 * i, newplist[i - UNCONSTRAINED_NODES]);
|
||||
update_b = prob_diff_update_cost(newp, oldp) + upd_cost;
|
||||
savings = old_b - new_b - update_b;
|
||||
if (savings > bestsavings) {
|
||||
bestsavings = savings;
|
||||
bestnewp = newp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*bestp = bestnewp;
|
||||
return bestsavings;
|
||||
}
|
||||
|
||||
void vp9_cond_prob_diff_update(vpx_writer *w, vpx_prob *oldp,
|
||||
const unsigned int ct[2]) {
|
||||
const vpx_prob upd = DIFF_UPDATE_PROB;
|
||||
vpx_prob newp = get_binary_prob(ct[0], ct[1]);
|
||||
const int savings =
|
||||
vp9_prob_diff_update_savings_search(ct, *oldp, &newp, upd);
|
||||
assert(newp >= 1);
|
||||
if (savings > 0) {
|
||||
vpx_write(w, 1, upd);
|
||||
vp9_write_prob_diff_update(w, newp, *oldp);
|
||||
*oldp = newp;
|
||||
} else {
|
||||
vpx_write(w, 0, upd);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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_SUBEXP_H_
|
||||
#define VPX_VP9_ENCODER_VP9_SUBEXP_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "vpx_dsp/prob.h"
|
||||
|
||||
struct vpx_writer;
|
||||
|
||||
void vp9_write_prob_diff_update(struct vpx_writer *w, vpx_prob newp,
|
||||
vpx_prob oldp);
|
||||
|
||||
void vp9_cond_prob_diff_update(struct vpx_writer *w, vpx_prob *oldp,
|
||||
const unsigned int ct[2]);
|
||||
|
||||
int vp9_prob_diff_update_savings_search(const unsigned int *ct, vpx_prob oldp,
|
||||
vpx_prob *bestp, vpx_prob upd);
|
||||
|
||||
int vp9_prob_diff_update_savings_search_model(const unsigned int *ct,
|
||||
const vpx_prob oldp,
|
||||
vpx_prob *bestp, vpx_prob upd,
|
||||
int stepsize);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_ENCODER_VP9_SUBEXP_H_
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,275 @@
|
||||
/*
|
||||
* 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_SVC_LAYERCONTEXT_H_
|
||||
#define VPX_VP9_ENCODER_VP9_SVC_LAYERCONTEXT_H_
|
||||
|
||||
#include "vpx/vpx_encoder.h"
|
||||
|
||||
#include "vp9/encoder/vp9_ratectrl.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
// Inter-layer prediction is on on all frames.
|
||||
INTER_LAYER_PRED_ON,
|
||||
// Inter-layer prediction is off on all frames.
|
||||
INTER_LAYER_PRED_OFF,
|
||||
// Inter-layer prediction is off on non-key frames and non-sync frames.
|
||||
INTER_LAYER_PRED_OFF_NONKEY,
|
||||
// Inter-layer prediction is on on all frames, but constrained such
|
||||
// that any layer S (> 0) can only predict from previous spatial
|
||||
// layer S-1, from the same superframe.
|
||||
INTER_LAYER_PRED_ON_CONSTRAINED
|
||||
} INTER_LAYER_PRED;
|
||||
|
||||
typedef struct BUFFER_LONGTERM_REF {
|
||||
int idx;
|
||||
int is_used;
|
||||
} BUFFER_LONGTERM_REF;
|
||||
|
||||
typedef struct {
|
||||
RATE_CONTROL rc;
|
||||
int target_bandwidth;
|
||||
int spatial_layer_target_bandwidth; // Target for the spatial layer.
|
||||
double framerate;
|
||||
int avg_frame_size;
|
||||
int max_q;
|
||||
int min_q;
|
||||
int scaling_factor_num;
|
||||
int scaling_factor_den;
|
||||
TWO_PASS twopass;
|
||||
vpx_fixed_buf_t rc_twopass_stats_in;
|
||||
unsigned int current_video_frame_in_layer;
|
||||
int is_key_frame;
|
||||
int frames_from_key_frame;
|
||||
FRAME_TYPE last_frame_type;
|
||||
struct lookahead_entry *alt_ref_source;
|
||||
int alt_ref_idx;
|
||||
int gold_ref_idx;
|
||||
int has_alt_frame;
|
||||
size_t layer_size;
|
||||
// Cyclic refresh parameters (aq-mode=3), that need to be updated per-frame.
|
||||
// TODO(jianj/marpan): Is it better to use the full cyclic refresh struct.
|
||||
int sb_index;
|
||||
signed char *map;
|
||||
uint8_t *last_coded_q_map;
|
||||
uint8_t *consec_zero_mv;
|
||||
int actual_num_seg1_blocks;
|
||||
int actual_num_seg2_blocks;
|
||||
int counter_encode_maxq_scene_change;
|
||||
uint8_t speed;
|
||||
} LAYER_CONTEXT;
|
||||
|
||||
typedef struct SVC {
|
||||
int spatial_layer_id;
|
||||
int temporal_layer_id;
|
||||
int number_spatial_layers;
|
||||
int number_temporal_layers;
|
||||
|
||||
int spatial_layer_to_encode;
|
||||
|
||||
// Workaround for multiple frame contexts
|
||||
enum { ENCODED = 0, ENCODING, NEED_TO_ENCODE } encode_empty_frame_state;
|
||||
struct lookahead_entry empty_frame;
|
||||
int encode_intra_empty_frame;
|
||||
|
||||
// Store scaled source frames to be used for temporal filter to generate
|
||||
// a alt ref frame.
|
||||
YV12_BUFFER_CONFIG scaled_frames[MAX_LAG_BUFFERS];
|
||||
// Temp buffer used for 2-stage down-sampling, for real-time mode.
|
||||
YV12_BUFFER_CONFIG scaled_temp;
|
||||
int scaled_one_half;
|
||||
int scaled_temp_is_alloc;
|
||||
|
||||
// Layer context used for rate control in one pass temporal CBR mode or
|
||||
// two pass spatial mode.
|
||||
LAYER_CONTEXT layer_context[VPX_MAX_LAYERS];
|
||||
// Indicates what sort of temporal layering is used.
|
||||
// Currently, this only works for CBR mode.
|
||||
VP9E_TEMPORAL_LAYERING_MODE temporal_layering_mode;
|
||||
// Frame flags and buffer indexes for each spatial layer, set by the
|
||||
// application (external settings).
|
||||
int ext_frame_flags[VPX_MAX_LAYERS];
|
||||
int lst_fb_idx[VPX_MAX_LAYERS];
|
||||
int gld_fb_idx[VPX_MAX_LAYERS];
|
||||
int alt_fb_idx[VPX_MAX_LAYERS];
|
||||
int force_zero_mode_spatial_ref;
|
||||
// Sequence level flag to enable second (long term) temporal reference.
|
||||
int use_gf_temporal_ref;
|
||||
// Frame level flag to enable second (long term) temporal reference.
|
||||
int use_gf_temporal_ref_current_layer;
|
||||
// Allow second reference for at most 2 top highest resolution layers.
|
||||
BUFFER_LONGTERM_REF buffer_gf_temporal_ref[2];
|
||||
int current_superframe;
|
||||
int non_reference_frame;
|
||||
int use_base_mv;
|
||||
int use_partition_reuse;
|
||||
// Used to control the downscaling filter for source scaling, for 1 pass CBR.
|
||||
// downsample_filter_phase: = 0 will do sub-sampling (no weighted average),
|
||||
// = 8 will center the target pixel and get a symmetric averaging filter.
|
||||
// downsample_filter_type: 4 filters may be used: eighttap_regular,
|
||||
// eighttap_smooth, eighttap_sharp, and bilinear.
|
||||
INTERP_FILTER downsample_filter_type[VPX_SS_MAX_LAYERS];
|
||||
int downsample_filter_phase[VPX_SS_MAX_LAYERS];
|
||||
|
||||
BLOCK_SIZE *prev_partition_svc;
|
||||
int mi_stride[VPX_MAX_LAYERS];
|
||||
int mi_rows[VPX_MAX_LAYERS];
|
||||
int mi_cols[VPX_MAX_LAYERS];
|
||||
|
||||
int first_layer_denoise;
|
||||
|
||||
int skip_enhancement_layer;
|
||||
|
||||
int lower_layer_qindex;
|
||||
|
||||
int last_layer_dropped[VPX_MAX_LAYERS];
|
||||
int drop_spatial_layer[VPX_MAX_LAYERS];
|
||||
int framedrop_thresh[VPX_MAX_LAYERS];
|
||||
int drop_count[VPX_MAX_LAYERS];
|
||||
int force_drop_constrained_from_above[VPX_MAX_LAYERS];
|
||||
int max_consec_drop;
|
||||
SVC_LAYER_DROP_MODE framedrop_mode;
|
||||
|
||||
INTER_LAYER_PRED disable_inter_layer_pred;
|
||||
|
||||
// Flag to indicate scene change and high num of motion blocks at current
|
||||
// superframe, scene detection is currently checked for each superframe prior
|
||||
// to encoding, on the full resolution source.
|
||||
int high_source_sad_superframe;
|
||||
int high_num_blocks_with_motion;
|
||||
|
||||
// Flags used to get SVC pattern info.
|
||||
int update_buffer_slot[VPX_SS_MAX_LAYERS];
|
||||
uint8_t reference_last[VPX_SS_MAX_LAYERS];
|
||||
uint8_t reference_golden[VPX_SS_MAX_LAYERS];
|
||||
uint8_t reference_altref[VPX_SS_MAX_LAYERS];
|
||||
// TODO(jianj): Remove these last 3, deprecated.
|
||||
uint8_t update_last[VPX_SS_MAX_LAYERS];
|
||||
uint8_t update_golden[VPX_SS_MAX_LAYERS];
|
||||
uint8_t update_altref[VPX_SS_MAX_LAYERS];
|
||||
|
||||
// Keep track of the frame buffer index updated/refreshed on the base
|
||||
// temporal superframe.
|
||||
int fb_idx_upd_tl0[VPX_SS_MAX_LAYERS];
|
||||
|
||||
// Keep track of the spatial and temporal layer id of the frame that last
|
||||
// updated the frame buffer index.
|
||||
uint8_t fb_idx_spatial_layer_id[REF_FRAMES];
|
||||
uint8_t fb_idx_temporal_layer_id[REF_FRAMES];
|
||||
|
||||
int spatial_layer_sync[VPX_SS_MAX_LAYERS];
|
||||
uint8_t set_intra_only_frame;
|
||||
uint8_t previous_frame_is_intra_only;
|
||||
uint8_t superframe_has_layer_sync;
|
||||
|
||||
uint8_t fb_idx_base[REF_FRAMES];
|
||||
|
||||
int use_set_ref_frame_config;
|
||||
|
||||
int temporal_layer_id_per_spatial[VPX_SS_MAX_LAYERS];
|
||||
|
||||
int first_spatial_layer_to_encode;
|
||||
|
||||
// Parameters for allowing framerate per spatial layer, and buffer
|
||||
// update based on timestamps.
|
||||
int64_t duration[VPX_SS_MAX_LAYERS];
|
||||
int64_t timebase_fac;
|
||||
int64_t time_stamp_superframe;
|
||||
int64_t time_stamp_prev[VPX_SS_MAX_LAYERS];
|
||||
|
||||
int num_encoded_top_layer;
|
||||
|
||||
// Every spatial layer on a superframe whose base is key is key too.
|
||||
int simulcast_mode;
|
||||
} SVC;
|
||||
|
||||
struct VP9_COMP;
|
||||
|
||||
// Initialize layer context data from init_config().
|
||||
void vp9_init_layer_context(struct VP9_COMP *const cpi);
|
||||
|
||||
// Update the layer context from a change_config() call.
|
||||
void vp9_update_layer_context_change_config(struct VP9_COMP *const cpi,
|
||||
const int target_bandwidth);
|
||||
|
||||
// Prior to encoding the frame, update framerate-related quantities
|
||||
// for the current temporal layer.
|
||||
void vp9_update_temporal_layer_framerate(struct VP9_COMP *const cpi);
|
||||
|
||||
// Update framerate-related quantities for the current spatial layer.
|
||||
void vp9_update_spatial_layer_framerate(struct VP9_COMP *const cpi,
|
||||
double framerate);
|
||||
|
||||
// Prior to encoding the frame, set the layer context, for the current layer
|
||||
// to be encoded, to the cpi struct.
|
||||
void vp9_restore_layer_context(struct VP9_COMP *const cpi);
|
||||
|
||||
// Save the layer context after encoding the frame.
|
||||
void vp9_save_layer_context(struct VP9_COMP *const cpi);
|
||||
|
||||
// Initialize second pass rc for spatial svc.
|
||||
void vp9_init_second_pass_spatial_svc(struct VP9_COMP *cpi);
|
||||
|
||||
void get_layer_resolution(const int width_org, const int height_org,
|
||||
const int num, const int den, int *width_out,
|
||||
int *height_out);
|
||||
|
||||
// Increment number of video frames in layer
|
||||
void vp9_inc_frame_in_layer(struct VP9_COMP *const cpi);
|
||||
|
||||
// Check if current layer is key frame in spatial upper layer
|
||||
int vp9_is_upper_layer_key_frame(const struct VP9_COMP *const cpi);
|
||||
|
||||
// Get the next source buffer to encode
|
||||
struct lookahead_entry *vp9_svc_lookahead_pop(struct VP9_COMP *const cpi,
|
||||
struct lookahead_ctx *ctx,
|
||||
int drain);
|
||||
|
||||
// Start a frame and initialize svc parameters
|
||||
int vp9_svc_start_frame(struct VP9_COMP *const cpi);
|
||||
|
||||
#if CONFIG_VP9_TEMPORAL_DENOISING
|
||||
int vp9_denoise_svc_non_key(struct VP9_COMP *const cpi);
|
||||
#endif
|
||||
|
||||
void vp9_copy_flags_ref_update_idx(struct VP9_COMP *const cpi);
|
||||
|
||||
int vp9_one_pass_cbr_svc_start_layer(struct VP9_COMP *const cpi);
|
||||
|
||||
void vp9_free_svc_cyclic_refresh(struct VP9_COMP *const cpi);
|
||||
|
||||
void vp9_svc_reset_temporal_layers(struct VP9_COMP *const cpi, int is_key);
|
||||
|
||||
void vp9_svc_check_reset_layer_rc_flag(struct VP9_COMP *const cpi);
|
||||
|
||||
void vp9_svc_constrain_inter_layer_pred(struct VP9_COMP *const cpi);
|
||||
|
||||
void vp9_svc_assert_constraints_pattern(struct VP9_COMP *const cpi);
|
||||
|
||||
void vp9_svc_check_spatial_layer_sync(struct VP9_COMP *const cpi);
|
||||
|
||||
void vp9_svc_update_ref_frame_buffer_idx(struct VP9_COMP *const cpi);
|
||||
|
||||
void vp9_svc_update_ref_frame_key_simulcast(struct VP9_COMP *const cpi);
|
||||
|
||||
void vp9_svc_update_ref_frame(struct VP9_COMP *const cpi);
|
||||
|
||||
void vp9_svc_adjust_frame_rate(struct VP9_COMP *const cpi);
|
||||
|
||||
void vp9_svc_adjust_avg_frame_qindex(struct VP9_COMP *const cpi);
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_ENCODER_VP9_SVC_LAYERCONTEXT_H_
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2010 The WebM project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef VPX_VP9_ENCODER_VP9_TEMPORAL_FILTER_H_
|
||||
#define VPX_VP9_ENCODER_VP9_TEMPORAL_FILTER_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ARNR_FILT_QINDEX 128
|
||||
static const MV kZeroMv = { 0, 0 };
|
||||
|
||||
// Block size used in temporal filtering
|
||||
#define TF_BLOCK BLOCK_32X32
|
||||
#define BH 32
|
||||
#define BH_LOG2 5
|
||||
#define BW 32
|
||||
#define BW_LOG2 5
|
||||
#define BLK_PELS ((BH) * (BW)) // Pixels in the block
|
||||
#define TF_SHIFT 2
|
||||
#define TF_ROUND 3
|
||||
#define THR_SHIFT 2
|
||||
#define TF_SUB_BLOCK BLOCK_16X16
|
||||
#define SUB_BH 16
|
||||
#define SUB_BW 16
|
||||
|
||||
void vp9_temporal_filter_init(void);
|
||||
void vp9_temporal_filter(VP9_COMP *cpi, int distance);
|
||||
|
||||
void vp9_temporal_filter_iterate_row_c(VP9_COMP *cpi, ThreadData *td,
|
||||
int mb_row, int mb_col_start,
|
||||
int mb_col_end);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_ENCODER_VP9_TEMPORAL_FILTER_H_
|
||||
@@ -0,0 +1,490 @@
|
||||
/*
|
||||
* Copyright (c) 2010 The WebM project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "vpx_mem/vpx_mem.h"
|
||||
|
||||
#include "vp9/common/vp9_entropy.h"
|
||||
#include "vp9/common/vp9_pred_common.h"
|
||||
#include "vp9/common/vp9_scan.h"
|
||||
|
||||
#include "vp9/encoder/vp9_cost.h"
|
||||
#include "vp9/encoder/vp9_encoder.h"
|
||||
#include "vp9/encoder/vp9_tokenize.h"
|
||||
|
||||
static const TOKENVALUE dct_cat_lt_10_value_tokens[] = {
|
||||
{ 9, 63 }, { 9, 61 }, { 9, 59 }, { 9, 57 }, { 9, 55 }, { 9, 53 }, { 9, 51 },
|
||||
{ 9, 49 }, { 9, 47 }, { 9, 45 }, { 9, 43 }, { 9, 41 }, { 9, 39 }, { 9, 37 },
|
||||
{ 9, 35 }, { 9, 33 }, { 9, 31 }, { 9, 29 }, { 9, 27 }, { 9, 25 }, { 9, 23 },
|
||||
{ 9, 21 }, { 9, 19 }, { 9, 17 }, { 9, 15 }, { 9, 13 }, { 9, 11 }, { 9, 9 },
|
||||
{ 9, 7 }, { 9, 5 }, { 9, 3 }, { 9, 1 }, { 8, 31 }, { 8, 29 }, { 8, 27 },
|
||||
{ 8, 25 }, { 8, 23 }, { 8, 21 }, { 8, 19 }, { 8, 17 }, { 8, 15 }, { 8, 13 },
|
||||
{ 8, 11 }, { 8, 9 }, { 8, 7 }, { 8, 5 }, { 8, 3 }, { 8, 1 }, { 7, 15 },
|
||||
{ 7, 13 }, { 7, 11 }, { 7, 9 }, { 7, 7 }, { 7, 5 }, { 7, 3 }, { 7, 1 },
|
||||
{ 6, 7 }, { 6, 5 }, { 6, 3 }, { 6, 1 }, { 5, 3 }, { 5, 1 }, { 4, 1 },
|
||||
{ 3, 1 }, { 2, 1 }, { 1, 1 }, { 0, 0 }, { 1, 0 }, { 2, 0 }, { 3, 0 },
|
||||
{ 4, 0 }, { 5, 0 }, { 5, 2 }, { 6, 0 }, { 6, 2 }, { 6, 4 }, { 6, 6 },
|
||||
{ 7, 0 }, { 7, 2 }, { 7, 4 }, { 7, 6 }, { 7, 8 }, { 7, 10 }, { 7, 12 },
|
||||
{ 7, 14 }, { 8, 0 }, { 8, 2 }, { 8, 4 }, { 8, 6 }, { 8, 8 }, { 8, 10 },
|
||||
{ 8, 12 }, { 8, 14 }, { 8, 16 }, { 8, 18 }, { 8, 20 }, { 8, 22 }, { 8, 24 },
|
||||
{ 8, 26 }, { 8, 28 }, { 8, 30 }, { 9, 0 }, { 9, 2 }, { 9, 4 }, { 9, 6 },
|
||||
{ 9, 8 }, { 9, 10 }, { 9, 12 }, { 9, 14 }, { 9, 16 }, { 9, 18 }, { 9, 20 },
|
||||
{ 9, 22 }, { 9, 24 }, { 9, 26 }, { 9, 28 }, { 9, 30 }, { 9, 32 }, { 9, 34 },
|
||||
{ 9, 36 }, { 9, 38 }, { 9, 40 }, { 9, 42 }, { 9, 44 }, { 9, 46 }, { 9, 48 },
|
||||
{ 9, 50 }, { 9, 52 }, { 9, 54 }, { 9, 56 }, { 9, 58 }, { 9, 60 }, { 9, 62 }
|
||||
};
|
||||
const TOKENVALUE *vp9_dct_cat_lt_10_value_tokens =
|
||||
dct_cat_lt_10_value_tokens +
|
||||
(sizeof(dct_cat_lt_10_value_tokens) / sizeof(*dct_cat_lt_10_value_tokens)) /
|
||||
2;
|
||||
// The corresponding costs of the extrabits for the tokens in the above table
|
||||
// are stored in the table below. The values are obtained from looking up the
|
||||
// entry for the specified extrabits in the table corresponding to the token
|
||||
// (as defined in cost element vp9_extra_bits)
|
||||
// e.g. {9, 63} maps to cat5_cost[63 >> 1], {1, 1} maps to sign_cost[1 >> 1]
|
||||
static const int dct_cat_lt_10_value_cost[] = {
|
||||
3773, 3750, 3704, 3681, 3623, 3600, 3554, 3531, 3432, 3409, 3363, 3340, 3282,
|
||||
3259, 3213, 3190, 3136, 3113, 3067, 3044, 2986, 2963, 2917, 2894, 2795, 2772,
|
||||
2726, 2703, 2645, 2622, 2576, 2553, 3197, 3116, 3058, 2977, 2881, 2800, 2742,
|
||||
2661, 2615, 2534, 2476, 2395, 2299, 2218, 2160, 2079, 2566, 2427, 2334, 2195,
|
||||
2023, 1884, 1791, 1652, 1893, 1696, 1453, 1256, 1229, 864, 512, 512, 512,
|
||||
512, 0, 512, 512, 512, 512, 864, 1229, 1256, 1453, 1696, 1893, 1652,
|
||||
1791, 1884, 2023, 2195, 2334, 2427, 2566, 2079, 2160, 2218, 2299, 2395, 2476,
|
||||
2534, 2615, 2661, 2742, 2800, 2881, 2977, 3058, 3116, 3197, 2553, 2576, 2622,
|
||||
2645, 2703, 2726, 2772, 2795, 2894, 2917, 2963, 2986, 3044, 3067, 3113, 3136,
|
||||
3190, 3213, 3259, 3282, 3340, 3363, 3409, 3432, 3531, 3554, 3600, 3623, 3681,
|
||||
3704, 3750, 3773,
|
||||
};
|
||||
const int *vp9_dct_cat_lt_10_value_cost =
|
||||
dct_cat_lt_10_value_cost +
|
||||
(sizeof(dct_cat_lt_10_value_cost) / sizeof(*dct_cat_lt_10_value_cost)) / 2;
|
||||
|
||||
// Array indices are identical to previously-existing CONTEXT_NODE indices
|
||||
/* clang-format off */
|
||||
const vpx_tree_index vp9_coef_tree[TREE_SIZE(ENTROPY_TOKENS)] = {
|
||||
-EOB_TOKEN, 2, // 0 = EOB
|
||||
-ZERO_TOKEN, 4, // 1 = ZERO
|
||||
-ONE_TOKEN, 6, // 2 = ONE
|
||||
8, 12, // 3 = LOW_VAL
|
||||
-TWO_TOKEN, 10, // 4 = TWO
|
||||
-THREE_TOKEN, -FOUR_TOKEN, // 5 = THREE
|
||||
14, 16, // 6 = HIGH_LOW
|
||||
-CATEGORY1_TOKEN, -CATEGORY2_TOKEN, // 7 = CAT_ONE
|
||||
18, 20, // 8 = CAT_THREEFOUR
|
||||
-CATEGORY3_TOKEN, -CATEGORY4_TOKEN, // 9 = CAT_THREE
|
||||
-CATEGORY5_TOKEN, -CATEGORY6_TOKEN // 10 = CAT_FIVE
|
||||
};
|
||||
/* clang-format on */
|
||||
|
||||
static const int16_t zero_cost[] = { 0 };
|
||||
static const int16_t sign_cost[1] = { 512 };
|
||||
static const int16_t cat1_cost[1 << 1] = { 864, 1229 };
|
||||
static const int16_t cat2_cost[1 << 2] = { 1256, 1453, 1696, 1893 };
|
||||
static const int16_t cat3_cost[1 << 3] = { 1652, 1791, 1884, 2023,
|
||||
2195, 2334, 2427, 2566 };
|
||||
static const int16_t cat4_cost[1 << 4] = { 2079, 2160, 2218, 2299, 2395, 2476,
|
||||
2534, 2615, 2661, 2742, 2800, 2881,
|
||||
2977, 3058, 3116, 3197 };
|
||||
static const int16_t cat5_cost[1 << 5] = {
|
||||
2553, 2576, 2622, 2645, 2703, 2726, 2772, 2795, 2894, 2917, 2963,
|
||||
2986, 3044, 3067, 3113, 3136, 3190, 3213, 3259, 3282, 3340, 3363,
|
||||
3409, 3432, 3531, 3554, 3600, 3623, 3681, 3704, 3750, 3773
|
||||
};
|
||||
const int16_t vp9_cat6_low_cost[256] = {
|
||||
3378, 3390, 3401, 3413, 3435, 3447, 3458, 3470, 3517, 3529, 3540, 3552, 3574,
|
||||
3586, 3597, 3609, 3671, 3683, 3694, 3706, 3728, 3740, 3751, 3763, 3810, 3822,
|
||||
3833, 3845, 3867, 3879, 3890, 3902, 3973, 3985, 3996, 4008, 4030, 4042, 4053,
|
||||
4065, 4112, 4124, 4135, 4147, 4169, 4181, 4192, 4204, 4266, 4278, 4289, 4301,
|
||||
4323, 4335, 4346, 4358, 4405, 4417, 4428, 4440, 4462, 4474, 4485, 4497, 4253,
|
||||
4265, 4276, 4288, 4310, 4322, 4333, 4345, 4392, 4404, 4415, 4427, 4449, 4461,
|
||||
4472, 4484, 4546, 4558, 4569, 4581, 4603, 4615, 4626, 4638, 4685, 4697, 4708,
|
||||
4720, 4742, 4754, 4765, 4777, 4848, 4860, 4871, 4883, 4905, 4917, 4928, 4940,
|
||||
4987, 4999, 5010, 5022, 5044, 5056, 5067, 5079, 5141, 5153, 5164, 5176, 5198,
|
||||
5210, 5221, 5233, 5280, 5292, 5303, 5315, 5337, 5349, 5360, 5372, 4988, 5000,
|
||||
5011, 5023, 5045, 5057, 5068, 5080, 5127, 5139, 5150, 5162, 5184, 5196, 5207,
|
||||
5219, 5281, 5293, 5304, 5316, 5338, 5350, 5361, 5373, 5420, 5432, 5443, 5455,
|
||||
5477, 5489, 5500, 5512, 5583, 5595, 5606, 5618, 5640, 5652, 5663, 5675, 5722,
|
||||
5734, 5745, 5757, 5779, 5791, 5802, 5814, 5876, 5888, 5899, 5911, 5933, 5945,
|
||||
5956, 5968, 6015, 6027, 6038, 6050, 6072, 6084, 6095, 6107, 5863, 5875, 5886,
|
||||
5898, 5920, 5932, 5943, 5955, 6002, 6014, 6025, 6037, 6059, 6071, 6082, 6094,
|
||||
6156, 6168, 6179, 6191, 6213, 6225, 6236, 6248, 6295, 6307, 6318, 6330, 6352,
|
||||
6364, 6375, 6387, 6458, 6470, 6481, 6493, 6515, 6527, 6538, 6550, 6597, 6609,
|
||||
6620, 6632, 6654, 6666, 6677, 6689, 6751, 6763, 6774, 6786, 6808, 6820, 6831,
|
||||
6843, 6890, 6902, 6913, 6925, 6947, 6959, 6970, 6982
|
||||
};
|
||||
const uint16_t vp9_cat6_high_cost[64] = {
|
||||
88, 2251, 2727, 4890, 3148, 5311, 5787, 7950, 3666, 5829, 6305,
|
||||
8468, 6726, 8889, 9365, 11528, 3666, 5829, 6305, 8468, 6726, 8889,
|
||||
9365, 11528, 7244, 9407, 9883, 12046, 10304, 12467, 12943, 15106, 3666,
|
||||
5829, 6305, 8468, 6726, 8889, 9365, 11528, 7244, 9407, 9883, 12046,
|
||||
10304, 12467, 12943, 15106, 7244, 9407, 9883, 12046, 10304, 12467, 12943,
|
||||
15106, 10822, 12985, 13461, 15624, 13882, 16045, 16521, 18684
|
||||
};
|
||||
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
const uint16_t vp9_cat6_high10_high_cost[256] = {
|
||||
94, 2257, 2733, 4896, 3154, 5317, 5793, 7956, 3672, 5835, 6311,
|
||||
8474, 6732, 8895, 9371, 11534, 3672, 5835, 6311, 8474, 6732, 8895,
|
||||
9371, 11534, 7250, 9413, 9889, 12052, 10310, 12473, 12949, 15112, 3672,
|
||||
5835, 6311, 8474, 6732, 8895, 9371, 11534, 7250, 9413, 9889, 12052,
|
||||
10310, 12473, 12949, 15112, 7250, 9413, 9889, 12052, 10310, 12473, 12949,
|
||||
15112, 10828, 12991, 13467, 15630, 13888, 16051, 16527, 18690, 4187, 6350,
|
||||
6826, 8989, 7247, 9410, 9886, 12049, 7765, 9928, 10404, 12567, 10825,
|
||||
12988, 13464, 15627, 7765, 9928, 10404, 12567, 10825, 12988, 13464, 15627,
|
||||
11343, 13506, 13982, 16145, 14403, 16566, 17042, 19205, 7765, 9928, 10404,
|
||||
12567, 10825, 12988, 13464, 15627, 11343, 13506, 13982, 16145, 14403, 16566,
|
||||
17042, 19205, 11343, 13506, 13982, 16145, 14403, 16566, 17042, 19205, 14921,
|
||||
17084, 17560, 19723, 17981, 20144, 20620, 22783, 4187, 6350, 6826, 8989,
|
||||
7247, 9410, 9886, 12049, 7765, 9928, 10404, 12567, 10825, 12988, 13464,
|
||||
15627, 7765, 9928, 10404, 12567, 10825, 12988, 13464, 15627, 11343, 13506,
|
||||
13982, 16145, 14403, 16566, 17042, 19205, 7765, 9928, 10404, 12567, 10825,
|
||||
12988, 13464, 15627, 11343, 13506, 13982, 16145, 14403, 16566, 17042, 19205,
|
||||
11343, 13506, 13982, 16145, 14403, 16566, 17042, 19205, 14921, 17084, 17560,
|
||||
19723, 17981, 20144, 20620, 22783, 8280, 10443, 10919, 13082, 11340, 13503,
|
||||
13979, 16142, 11858, 14021, 14497, 16660, 14918, 17081, 17557, 19720, 11858,
|
||||
14021, 14497, 16660, 14918, 17081, 17557, 19720, 15436, 17599, 18075, 20238,
|
||||
18496, 20659, 21135, 23298, 11858, 14021, 14497, 16660, 14918, 17081, 17557,
|
||||
19720, 15436, 17599, 18075, 20238, 18496, 20659, 21135, 23298, 15436, 17599,
|
||||
18075, 20238, 18496, 20659, 21135, 23298, 19014, 21177, 21653, 23816, 22074,
|
||||
24237, 24713, 26876
|
||||
};
|
||||
const uint16_t vp9_cat6_high12_high_cost[1024] = {
|
||||
100, 2263, 2739, 4902, 3160, 5323, 5799, 7962, 3678, 5841, 6317,
|
||||
8480, 6738, 8901, 9377, 11540, 3678, 5841, 6317, 8480, 6738, 8901,
|
||||
9377, 11540, 7256, 9419, 9895, 12058, 10316, 12479, 12955, 15118, 3678,
|
||||
5841, 6317, 8480, 6738, 8901, 9377, 11540, 7256, 9419, 9895, 12058,
|
||||
10316, 12479, 12955, 15118, 7256, 9419, 9895, 12058, 10316, 12479, 12955,
|
||||
15118, 10834, 12997, 13473, 15636, 13894, 16057, 16533, 18696, 4193, 6356,
|
||||
6832, 8995, 7253, 9416, 9892, 12055, 7771, 9934, 10410, 12573, 10831,
|
||||
12994, 13470, 15633, 7771, 9934, 10410, 12573, 10831, 12994, 13470, 15633,
|
||||
11349, 13512, 13988, 16151, 14409, 16572, 17048, 19211, 7771, 9934, 10410,
|
||||
12573, 10831, 12994, 13470, 15633, 11349, 13512, 13988, 16151, 14409, 16572,
|
||||
17048, 19211, 11349, 13512, 13988, 16151, 14409, 16572, 17048, 19211, 14927,
|
||||
17090, 17566, 19729, 17987, 20150, 20626, 22789, 4193, 6356, 6832, 8995,
|
||||
7253, 9416, 9892, 12055, 7771, 9934, 10410, 12573, 10831, 12994, 13470,
|
||||
15633, 7771, 9934, 10410, 12573, 10831, 12994, 13470, 15633, 11349, 13512,
|
||||
13988, 16151, 14409, 16572, 17048, 19211, 7771, 9934, 10410, 12573, 10831,
|
||||
12994, 13470, 15633, 11349, 13512, 13988, 16151, 14409, 16572, 17048, 19211,
|
||||
11349, 13512, 13988, 16151, 14409, 16572, 17048, 19211, 14927, 17090, 17566,
|
||||
19729, 17987, 20150, 20626, 22789, 8286, 10449, 10925, 13088, 11346, 13509,
|
||||
13985, 16148, 11864, 14027, 14503, 16666, 14924, 17087, 17563, 19726, 11864,
|
||||
14027, 14503, 16666, 14924, 17087, 17563, 19726, 15442, 17605, 18081, 20244,
|
||||
18502, 20665, 21141, 23304, 11864, 14027, 14503, 16666, 14924, 17087, 17563,
|
||||
19726, 15442, 17605, 18081, 20244, 18502, 20665, 21141, 23304, 15442, 17605,
|
||||
18081, 20244, 18502, 20665, 21141, 23304, 19020, 21183, 21659, 23822, 22080,
|
||||
24243, 24719, 26882, 4193, 6356, 6832, 8995, 7253, 9416, 9892, 12055,
|
||||
7771, 9934, 10410, 12573, 10831, 12994, 13470, 15633, 7771, 9934, 10410,
|
||||
12573, 10831, 12994, 13470, 15633, 11349, 13512, 13988, 16151, 14409, 16572,
|
||||
17048, 19211, 7771, 9934, 10410, 12573, 10831, 12994, 13470, 15633, 11349,
|
||||
13512, 13988, 16151, 14409, 16572, 17048, 19211, 11349, 13512, 13988, 16151,
|
||||
14409, 16572, 17048, 19211, 14927, 17090, 17566, 19729, 17987, 20150, 20626,
|
||||
22789, 8286, 10449, 10925, 13088, 11346, 13509, 13985, 16148, 11864, 14027,
|
||||
14503, 16666, 14924, 17087, 17563, 19726, 11864, 14027, 14503, 16666, 14924,
|
||||
17087, 17563, 19726, 15442, 17605, 18081, 20244, 18502, 20665, 21141, 23304,
|
||||
11864, 14027, 14503, 16666, 14924, 17087, 17563, 19726, 15442, 17605, 18081,
|
||||
20244, 18502, 20665, 21141, 23304, 15442, 17605, 18081, 20244, 18502, 20665,
|
||||
21141, 23304, 19020, 21183, 21659, 23822, 22080, 24243, 24719, 26882, 8286,
|
||||
10449, 10925, 13088, 11346, 13509, 13985, 16148, 11864, 14027, 14503, 16666,
|
||||
14924, 17087, 17563, 19726, 11864, 14027, 14503, 16666, 14924, 17087, 17563,
|
||||
19726, 15442, 17605, 18081, 20244, 18502, 20665, 21141, 23304, 11864, 14027,
|
||||
14503, 16666, 14924, 17087, 17563, 19726, 15442, 17605, 18081, 20244, 18502,
|
||||
20665, 21141, 23304, 15442, 17605, 18081, 20244, 18502, 20665, 21141, 23304,
|
||||
19020, 21183, 21659, 23822, 22080, 24243, 24719, 26882, 12379, 14542, 15018,
|
||||
17181, 15439, 17602, 18078, 20241, 15957, 18120, 18596, 20759, 19017, 21180,
|
||||
21656, 23819, 15957, 18120, 18596, 20759, 19017, 21180, 21656, 23819, 19535,
|
||||
21698, 22174, 24337, 22595, 24758, 25234, 27397, 15957, 18120, 18596, 20759,
|
||||
19017, 21180, 21656, 23819, 19535, 21698, 22174, 24337, 22595, 24758, 25234,
|
||||
27397, 19535, 21698, 22174, 24337, 22595, 24758, 25234, 27397, 23113, 25276,
|
||||
25752, 27915, 26173, 28336, 28812, 30975, 4193, 6356, 6832, 8995, 7253,
|
||||
9416, 9892, 12055, 7771, 9934, 10410, 12573, 10831, 12994, 13470, 15633,
|
||||
7771, 9934, 10410, 12573, 10831, 12994, 13470, 15633, 11349, 13512, 13988,
|
||||
16151, 14409, 16572, 17048, 19211, 7771, 9934, 10410, 12573, 10831, 12994,
|
||||
13470, 15633, 11349, 13512, 13988, 16151, 14409, 16572, 17048, 19211, 11349,
|
||||
13512, 13988, 16151, 14409, 16572, 17048, 19211, 14927, 17090, 17566, 19729,
|
||||
17987, 20150, 20626, 22789, 8286, 10449, 10925, 13088, 11346, 13509, 13985,
|
||||
16148, 11864, 14027, 14503, 16666, 14924, 17087, 17563, 19726, 11864, 14027,
|
||||
14503, 16666, 14924, 17087, 17563, 19726, 15442, 17605, 18081, 20244, 18502,
|
||||
20665, 21141, 23304, 11864, 14027, 14503, 16666, 14924, 17087, 17563, 19726,
|
||||
15442, 17605, 18081, 20244, 18502, 20665, 21141, 23304, 15442, 17605, 18081,
|
||||
20244, 18502, 20665, 21141, 23304, 19020, 21183, 21659, 23822, 22080, 24243,
|
||||
24719, 26882, 8286, 10449, 10925, 13088, 11346, 13509, 13985, 16148, 11864,
|
||||
14027, 14503, 16666, 14924, 17087, 17563, 19726, 11864, 14027, 14503, 16666,
|
||||
14924, 17087, 17563, 19726, 15442, 17605, 18081, 20244, 18502, 20665, 21141,
|
||||
23304, 11864, 14027, 14503, 16666, 14924, 17087, 17563, 19726, 15442, 17605,
|
||||
18081, 20244, 18502, 20665, 21141, 23304, 15442, 17605, 18081, 20244, 18502,
|
||||
20665, 21141, 23304, 19020, 21183, 21659, 23822, 22080, 24243, 24719, 26882,
|
||||
12379, 14542, 15018, 17181, 15439, 17602, 18078, 20241, 15957, 18120, 18596,
|
||||
20759, 19017, 21180, 21656, 23819, 15957, 18120, 18596, 20759, 19017, 21180,
|
||||
21656, 23819, 19535, 21698, 22174, 24337, 22595, 24758, 25234, 27397, 15957,
|
||||
18120, 18596, 20759, 19017, 21180, 21656, 23819, 19535, 21698, 22174, 24337,
|
||||
22595, 24758, 25234, 27397, 19535, 21698, 22174, 24337, 22595, 24758, 25234,
|
||||
27397, 23113, 25276, 25752, 27915, 26173, 28336, 28812, 30975, 8286, 10449,
|
||||
10925, 13088, 11346, 13509, 13985, 16148, 11864, 14027, 14503, 16666, 14924,
|
||||
17087, 17563, 19726, 11864, 14027, 14503, 16666, 14924, 17087, 17563, 19726,
|
||||
15442, 17605, 18081, 20244, 18502, 20665, 21141, 23304, 11864, 14027, 14503,
|
||||
16666, 14924, 17087, 17563, 19726, 15442, 17605, 18081, 20244, 18502, 20665,
|
||||
21141, 23304, 15442, 17605, 18081, 20244, 18502, 20665, 21141, 23304, 19020,
|
||||
21183, 21659, 23822, 22080, 24243, 24719, 26882, 12379, 14542, 15018, 17181,
|
||||
15439, 17602, 18078, 20241, 15957, 18120, 18596, 20759, 19017, 21180, 21656,
|
||||
23819, 15957, 18120, 18596, 20759, 19017, 21180, 21656, 23819, 19535, 21698,
|
||||
22174, 24337, 22595, 24758, 25234, 27397, 15957, 18120, 18596, 20759, 19017,
|
||||
21180, 21656, 23819, 19535, 21698, 22174, 24337, 22595, 24758, 25234, 27397,
|
||||
19535, 21698, 22174, 24337, 22595, 24758, 25234, 27397, 23113, 25276, 25752,
|
||||
27915, 26173, 28336, 28812, 30975, 12379, 14542, 15018, 17181, 15439, 17602,
|
||||
18078, 20241, 15957, 18120, 18596, 20759, 19017, 21180, 21656, 23819, 15957,
|
||||
18120, 18596, 20759, 19017, 21180, 21656, 23819, 19535, 21698, 22174, 24337,
|
||||
22595, 24758, 25234, 27397, 15957, 18120, 18596, 20759, 19017, 21180, 21656,
|
||||
23819, 19535, 21698, 22174, 24337, 22595, 24758, 25234, 27397, 19535, 21698,
|
||||
22174, 24337, 22595, 24758, 25234, 27397, 23113, 25276, 25752, 27915, 26173,
|
||||
28336, 28812, 30975, 16472, 18635, 19111, 21274, 19532, 21695, 22171, 24334,
|
||||
20050, 22213, 22689, 24852, 23110, 25273, 25749, 27912, 20050, 22213, 22689,
|
||||
24852, 23110, 25273, 25749, 27912, 23628, 25791, 26267, 28430, 26688, 28851,
|
||||
29327, 31490, 20050, 22213, 22689, 24852, 23110, 25273, 25749, 27912, 23628,
|
||||
25791, 26267, 28430, 26688, 28851, 29327, 31490, 23628, 25791, 26267, 28430,
|
||||
26688, 28851, 29327, 31490, 27206, 29369, 29845, 32008, 30266, 32429, 32905,
|
||||
35068
|
||||
};
|
||||
#endif
|
||||
|
||||
const vp9_extra_bit vp9_extra_bits[ENTROPY_TOKENS] = {
|
||||
{ 0, 0, 0, zero_cost }, // ZERO_TOKEN
|
||||
{ 0, 0, 1, sign_cost }, // ONE_TOKEN
|
||||
{ 0, 0, 2, sign_cost }, // TWO_TOKEN
|
||||
{ 0, 0, 3, sign_cost }, // THREE_TOKEN
|
||||
{ 0, 0, 4, sign_cost }, // FOUR_TOKEN
|
||||
{ vp9_cat1_prob, 1, CAT1_MIN_VAL, cat1_cost }, // CATEGORY1_TOKEN
|
||||
{ vp9_cat2_prob, 2, CAT2_MIN_VAL, cat2_cost }, // CATEGORY2_TOKEN
|
||||
{ vp9_cat3_prob, 3, CAT3_MIN_VAL, cat3_cost }, // CATEGORY3_TOKEN
|
||||
{ vp9_cat4_prob, 4, CAT4_MIN_VAL, cat4_cost }, // CATEGORY4_TOKEN
|
||||
{ vp9_cat5_prob, 5, CAT5_MIN_VAL, cat5_cost }, // CATEGORY5_TOKEN
|
||||
{ vp9_cat6_prob, 14, CAT6_MIN_VAL, 0 }, // CATEGORY6_TOKEN
|
||||
{ 0, 0, 0, zero_cost } // EOB_TOKEN
|
||||
};
|
||||
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
const vp9_extra_bit vp9_extra_bits_high10[ENTROPY_TOKENS] = {
|
||||
{ 0, 0, 0, zero_cost }, // ZERO
|
||||
{ 0, 0, 1, sign_cost }, // ONE
|
||||
{ 0, 0, 2, sign_cost }, // TWO
|
||||
{ 0, 0, 3, sign_cost }, // THREE
|
||||
{ 0, 0, 4, sign_cost }, // FOUR
|
||||
{ vp9_cat1_prob, 1, CAT1_MIN_VAL, cat1_cost }, // CAT1
|
||||
{ vp9_cat2_prob, 2, CAT2_MIN_VAL, cat2_cost }, // CAT2
|
||||
{ vp9_cat3_prob, 3, CAT3_MIN_VAL, cat3_cost }, // CAT3
|
||||
{ vp9_cat4_prob, 4, CAT4_MIN_VAL, cat4_cost }, // CAT4
|
||||
{ vp9_cat5_prob, 5, CAT5_MIN_VAL, cat5_cost }, // CAT5
|
||||
{ vp9_cat6_prob_high12 + 2, 16, CAT6_MIN_VAL, 0 }, // CAT6
|
||||
{ 0, 0, 0, zero_cost } // EOB
|
||||
};
|
||||
const vp9_extra_bit vp9_extra_bits_high12[ENTROPY_TOKENS] = {
|
||||
{ 0, 0, 0, zero_cost }, // ZERO
|
||||
{ 0, 0, 1, sign_cost }, // ONE
|
||||
{ 0, 0, 2, sign_cost }, // TWO
|
||||
{ 0, 0, 3, sign_cost }, // THREE
|
||||
{ 0, 0, 4, sign_cost }, // FOUR
|
||||
{ vp9_cat1_prob, 1, CAT1_MIN_VAL, cat1_cost }, // CAT1
|
||||
{ vp9_cat2_prob, 2, CAT2_MIN_VAL, cat2_cost }, // CAT2
|
||||
{ vp9_cat3_prob, 3, CAT3_MIN_VAL, cat3_cost }, // CAT3
|
||||
{ vp9_cat4_prob, 4, CAT4_MIN_VAL, cat4_cost }, // CAT4
|
||||
{ vp9_cat5_prob, 5, CAT5_MIN_VAL, cat5_cost }, // CAT5
|
||||
{ vp9_cat6_prob_high12, 18, CAT6_MIN_VAL, 0 }, // CAT6
|
||||
{ 0, 0, 0, zero_cost } // EOB
|
||||
};
|
||||
#endif
|
||||
|
||||
const struct vp9_token vp9_coef_encodings[ENTROPY_TOKENS] = {
|
||||
{ 2, 2 }, { 6, 3 }, { 28, 5 }, { 58, 6 }, { 59, 6 }, { 60, 6 },
|
||||
{ 61, 6 }, { 124, 7 }, { 125, 7 }, { 126, 7 }, { 127, 7 }, { 0, 1 }
|
||||
};
|
||||
|
||||
struct tokenize_b_args {
|
||||
VP9_COMP *cpi;
|
||||
ThreadData *td;
|
||||
TOKENEXTRA **tp;
|
||||
};
|
||||
|
||||
static void set_entropy_context_b(int plane, int block, int row, int col,
|
||||
BLOCK_SIZE plane_bsize, TX_SIZE tx_size,
|
||||
void *arg) {
|
||||
struct tokenize_b_args *const args = arg;
|
||||
ThreadData *const td = args->td;
|
||||
MACROBLOCK *const x = &td->mb;
|
||||
MACROBLOCKD *const xd = &x->e_mbd;
|
||||
struct macroblock_plane *p = &x->plane[plane];
|
||||
struct macroblockd_plane *pd = &xd->plane[plane];
|
||||
vp9_set_contexts(xd, pd, plane_bsize, tx_size, p->eobs[block] > 0, col, row);
|
||||
}
|
||||
|
||||
static INLINE void add_token(TOKENEXTRA **t, const vpx_prob *context_tree,
|
||||
int16_t token, EXTRABIT extra,
|
||||
unsigned int *counts) {
|
||||
(*t)->context_tree = context_tree;
|
||||
(*t)->token = token;
|
||||
(*t)->extra = extra;
|
||||
(*t)++;
|
||||
++counts[token];
|
||||
}
|
||||
|
||||
static INLINE void add_token_no_extra(TOKENEXTRA **t,
|
||||
const vpx_prob *context_tree,
|
||||
int16_t token, unsigned int *counts) {
|
||||
(*t)->context_tree = context_tree;
|
||||
(*t)->token = token;
|
||||
(*t)++;
|
||||
++counts[token];
|
||||
}
|
||||
|
||||
static void tokenize_b(int plane, int block, int row, int col,
|
||||
BLOCK_SIZE plane_bsize, TX_SIZE tx_size, void *arg) {
|
||||
struct tokenize_b_args *const args = arg;
|
||||
VP9_COMP *cpi = args->cpi;
|
||||
ThreadData *const td = args->td;
|
||||
MACROBLOCK *const x = &td->mb;
|
||||
MACROBLOCKD *const xd = &x->e_mbd;
|
||||
TOKENEXTRA **tp = args->tp;
|
||||
uint8_t token_cache[32 * 32];
|
||||
struct macroblock_plane *p = &x->plane[plane];
|
||||
struct macroblockd_plane *pd = &xd->plane[plane];
|
||||
MODE_INFO *mi = xd->mi[0];
|
||||
int pt; /* near block/prev token context index */
|
||||
int c;
|
||||
TOKENEXTRA *t = *tp; /* store tokens starting here */
|
||||
int eob = p->eobs[block];
|
||||
const PLANE_TYPE type = get_plane_type(plane);
|
||||
const tran_low_t *qcoeff = BLOCK_OFFSET(p->qcoeff, block);
|
||||
const int16_t *scan, *nb;
|
||||
const scan_order *so;
|
||||
const int ref = is_inter_block(mi);
|
||||
unsigned int(*const counts)[COEFF_CONTEXTS][ENTROPY_TOKENS] =
|
||||
td->rd_counts.coef_counts[tx_size][type][ref];
|
||||
vpx_prob(*const coef_probs)[COEFF_CONTEXTS][UNCONSTRAINED_NODES] =
|
||||
cpi->common.fc->coef_probs[tx_size][type][ref];
|
||||
unsigned int(*const eob_branch)[COEFF_CONTEXTS] =
|
||||
td->counts->eob_branch[tx_size][type][ref];
|
||||
const uint8_t *const band = get_band_translate(tx_size);
|
||||
const int tx_eob = 16 << (tx_size << 1);
|
||||
int16_t token;
|
||||
EXTRABIT extra;
|
||||
pt = get_entropy_context(tx_size, pd->above_context + col,
|
||||
pd->left_context + row);
|
||||
so = get_scan(xd, tx_size, type, block);
|
||||
scan = so->scan;
|
||||
nb = so->neighbors;
|
||||
c = 0;
|
||||
|
||||
while (c < eob) {
|
||||
int v = 0;
|
||||
v = qcoeff[scan[c]];
|
||||
++eob_branch[band[c]][pt];
|
||||
|
||||
while (!v) {
|
||||
add_token_no_extra(&t, coef_probs[band[c]][pt], ZERO_TOKEN,
|
||||
counts[band[c]][pt]);
|
||||
|
||||
token_cache[scan[c]] = 0;
|
||||
++c;
|
||||
pt = get_coef_context(nb, token_cache, c);
|
||||
v = qcoeff[scan[c]];
|
||||
}
|
||||
|
||||
vp9_get_token_extra(v, &token, &extra);
|
||||
|
||||
add_token(&t, coef_probs[band[c]][pt], token, extra, counts[band[c]][pt]);
|
||||
|
||||
token_cache[scan[c]] = vp9_pt_energy_class[token];
|
||||
++c;
|
||||
pt = get_coef_context(nb, token_cache, c);
|
||||
}
|
||||
if (c < tx_eob) {
|
||||
++eob_branch[band[c]][pt];
|
||||
add_token_no_extra(&t, coef_probs[band[c]][pt], EOB_TOKEN,
|
||||
counts[band[c]][pt]);
|
||||
}
|
||||
|
||||
*tp = t;
|
||||
|
||||
vp9_set_contexts(xd, pd, plane_bsize, tx_size, c > 0, col, row);
|
||||
}
|
||||
|
||||
struct is_skippable_args {
|
||||
uint16_t *eobs;
|
||||
int *skippable;
|
||||
};
|
||||
|
||||
static void is_skippable(int plane, int block, int row, int col,
|
||||
BLOCK_SIZE plane_bsize, TX_SIZE tx_size, void *argv) {
|
||||
struct is_skippable_args *args = argv;
|
||||
(void)plane;
|
||||
(void)plane_bsize;
|
||||
(void)tx_size;
|
||||
(void)row;
|
||||
(void)col;
|
||||
args->skippable[0] &= (!args->eobs[block]);
|
||||
}
|
||||
|
||||
// TODO(yaowu): rewrite and optimize this function to remove the usage of
|
||||
// vp9_foreach_transform_block() and simplify is_skippable().
|
||||
int vp9_is_skippable_in_plane(MACROBLOCK *x, BLOCK_SIZE bsize, int plane) {
|
||||
int result = 1;
|
||||
struct is_skippable_args args = { x->plane[plane].eobs, &result };
|
||||
vp9_foreach_transformed_block_in_plane(&x->e_mbd, bsize, plane, is_skippable,
|
||||
&args);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void has_high_freq_coeff(int plane, int block, int row, int col,
|
||||
BLOCK_SIZE plane_bsize, TX_SIZE tx_size,
|
||||
void *argv) {
|
||||
struct is_skippable_args *args = argv;
|
||||
int eobs = (tx_size == TX_4X4) ? 3 : 10;
|
||||
(void)plane;
|
||||
(void)plane_bsize;
|
||||
(void)row;
|
||||
(void)col;
|
||||
*(args->skippable) |= (args->eobs[block] > eobs);
|
||||
}
|
||||
|
||||
int vp9_has_high_freq_in_plane(MACROBLOCK *x, BLOCK_SIZE bsize, int plane) {
|
||||
int result = 0;
|
||||
struct is_skippable_args args = { x->plane[plane].eobs, &result };
|
||||
vp9_foreach_transformed_block_in_plane(&x->e_mbd, bsize, plane,
|
||||
has_high_freq_coeff, &args);
|
||||
return result;
|
||||
}
|
||||
|
||||
void vp9_tokenize_sb(VP9_COMP *cpi, ThreadData *td, TOKENEXTRA **t, int dry_run,
|
||||
int seg_skip, BLOCK_SIZE bsize) {
|
||||
MACROBLOCK *const x = &td->mb;
|
||||
MACROBLOCKD *const xd = &x->e_mbd;
|
||||
MODE_INFO *const mi = xd->mi[0];
|
||||
const int ctx = vp9_get_skip_context(xd);
|
||||
struct tokenize_b_args arg = { cpi, td, t };
|
||||
|
||||
if (seg_skip) {
|
||||
assert(mi->skip);
|
||||
}
|
||||
|
||||
if (mi->skip) {
|
||||
if (!dry_run && !seg_skip) ++td->counts->skip[ctx][1];
|
||||
reset_skip_context(xd, bsize);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dry_run) {
|
||||
++td->counts->skip[ctx][0];
|
||||
vp9_foreach_transformed_block(xd, bsize, tokenize_b, &arg);
|
||||
} else {
|
||||
vp9_foreach_transformed_block(xd, bsize, set_entropy_context_b, &arg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* 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_ENCODER_VP9_TOKENIZE_H_
|
||||
#define VPX_VP9_ENCODER_VP9_TOKENIZE_H_
|
||||
|
||||
#include "vp9/common/vp9_entropy.h"
|
||||
|
||||
#include "vp9/encoder/vp9_block.h"
|
||||
#include "vp9/encoder/vp9_treewriter.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define EOSB_TOKEN 127 // Not signalled, encoder only
|
||||
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
typedef int32_t EXTRABIT;
|
||||
#else
|
||||
typedef int16_t EXTRABIT;
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
int16_t token;
|
||||
EXTRABIT extra;
|
||||
} TOKENVALUE;
|
||||
|
||||
typedef struct {
|
||||
const vpx_prob *context_tree;
|
||||
int16_t token;
|
||||
EXTRABIT extra;
|
||||
} TOKENEXTRA;
|
||||
|
||||
extern const vpx_tree_index vp9_coef_tree[];
|
||||
extern const vpx_tree_index vp9_coef_con_tree[];
|
||||
extern const struct vp9_token vp9_coef_encodings[];
|
||||
|
||||
int vp9_is_skippable_in_plane(MACROBLOCK *x, BLOCK_SIZE bsize, int plane);
|
||||
int vp9_has_high_freq_in_plane(MACROBLOCK *x, BLOCK_SIZE bsize, int plane);
|
||||
|
||||
struct VP9_COMP;
|
||||
struct ThreadData;
|
||||
|
||||
void vp9_tokenize_sb(struct VP9_COMP *cpi, struct ThreadData *td,
|
||||
TOKENEXTRA **t, int dry_run, int seg_skip,
|
||||
BLOCK_SIZE bsize);
|
||||
|
||||
typedef struct {
|
||||
const vpx_prob *prob;
|
||||
int len;
|
||||
int base_val;
|
||||
const int16_t *cost;
|
||||
} vp9_extra_bit;
|
||||
|
||||
// indexed by token value
|
||||
extern const vp9_extra_bit vp9_extra_bits[ENTROPY_TOKENS];
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
extern const vp9_extra_bit vp9_extra_bits_high10[ENTROPY_TOKENS];
|
||||
extern const vp9_extra_bit vp9_extra_bits_high12[ENTROPY_TOKENS];
|
||||
#endif // CONFIG_VP9_HIGHBITDEPTH
|
||||
|
||||
extern const int16_t *vp9_dct_value_cost_ptr;
|
||||
/* TODO: The Token field should be broken out into a separate char array to
|
||||
* improve cache locality, since it's needed for costing when the rest of the
|
||||
* fields are not.
|
||||
*/
|
||||
extern const TOKENVALUE *vp9_dct_value_tokens_ptr;
|
||||
extern const TOKENVALUE *vp9_dct_cat_lt_10_value_tokens;
|
||||
extern const int *vp9_dct_cat_lt_10_value_cost;
|
||||
extern const int16_t vp9_cat6_low_cost[256];
|
||||
extern const uint16_t vp9_cat6_high_cost[64];
|
||||
extern const uint16_t vp9_cat6_high10_high_cost[256];
|
||||
extern const uint16_t vp9_cat6_high12_high_cost[1024];
|
||||
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
static INLINE const uint16_t *vp9_get_high_cost_table(int bit_depth) {
|
||||
return bit_depth == 8 ? vp9_cat6_high_cost
|
||||
: (bit_depth == 10 ? vp9_cat6_high10_high_cost
|
||||
: vp9_cat6_high12_high_cost);
|
||||
}
|
||||
#else
|
||||
static INLINE const uint16_t *vp9_get_high_cost_table(int bit_depth) {
|
||||
(void)bit_depth;
|
||||
return vp9_cat6_high_cost;
|
||||
}
|
||||
#endif // CONFIG_VP9_HIGHBITDEPTH
|
||||
|
||||
static INLINE void vp9_get_token_extra(int v, int16_t *token, EXTRABIT *extra) {
|
||||
if (v >= CAT6_MIN_VAL || v <= -CAT6_MIN_VAL) {
|
||||
*token = CATEGORY6_TOKEN;
|
||||
if (v >= CAT6_MIN_VAL)
|
||||
*extra = 2 * v - 2 * CAT6_MIN_VAL;
|
||||
else
|
||||
*extra = -2 * v - 2 * CAT6_MIN_VAL + 1;
|
||||
return;
|
||||
}
|
||||
*token = vp9_dct_cat_lt_10_value_tokens[v].token;
|
||||
*extra = vp9_dct_cat_lt_10_value_tokens[v].extra;
|
||||
}
|
||||
static INLINE int16_t vp9_get_token(int v) {
|
||||
if (v >= CAT6_MIN_VAL || v <= -CAT6_MIN_VAL) return 10;
|
||||
return vp9_dct_cat_lt_10_value_tokens[v].token;
|
||||
}
|
||||
|
||||
static INLINE int vp9_get_token_cost(int v, int16_t *token,
|
||||
const uint16_t *cat6_high_table) {
|
||||
if (v >= CAT6_MIN_VAL || v <= -CAT6_MIN_VAL) {
|
||||
EXTRABIT extrabits;
|
||||
*token = CATEGORY6_TOKEN;
|
||||
extrabits = abs(v) - CAT6_MIN_VAL;
|
||||
return vp9_cat6_low_cost[extrabits & 0xff] +
|
||||
cat6_high_table[extrabits >> 8];
|
||||
}
|
||||
*token = vp9_dct_cat_lt_10_value_tokens[v].token;
|
||||
return vp9_dct_cat_lt_10_value_cost[v];
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_ENCODER_VP9_TOKENIZE_H_
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2010 The WebM project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "vp9/encoder/vp9_treewriter.h"
|
||||
|
||||
static void tree2tok(struct vp9_token *tokens, const vpx_tree_index *tree,
|
||||
int i, int v, int l) {
|
||||
v += v;
|
||||
++l;
|
||||
|
||||
do {
|
||||
const vpx_tree_index j = tree[i++];
|
||||
if (j <= 0) {
|
||||
tokens[-j].value = v;
|
||||
tokens[-j].len = l;
|
||||
} else {
|
||||
tree2tok(tokens, tree, j, v, l);
|
||||
}
|
||||
} while (++v & 1);
|
||||
}
|
||||
|
||||
void vp9_tokens_from_tree(struct vp9_token *tokens,
|
||||
const vpx_tree_index *tree) {
|
||||
tree2tok(tokens, tree, 0, 0, 0);
|
||||
}
|
||||
|
||||
static unsigned int convert_distribution(unsigned int i, vpx_tree tree,
|
||||
unsigned int branch_ct[][2],
|
||||
const unsigned int num_events[]) {
|
||||
unsigned int left, right;
|
||||
|
||||
if (tree[i] <= 0)
|
||||
left = num_events[-tree[i]];
|
||||
else
|
||||
left = convert_distribution(tree[i], tree, branch_ct, num_events);
|
||||
|
||||
if (tree[i + 1] <= 0)
|
||||
right = num_events[-tree[i + 1]];
|
||||
else
|
||||
right = convert_distribution(tree[i + 1], tree, branch_ct, num_events);
|
||||
|
||||
branch_ct[i >> 1][0] = left;
|
||||
branch_ct[i >> 1][1] = right;
|
||||
return left + right;
|
||||
}
|
||||
|
||||
void vp9_tree_probs_from_distribution(vpx_tree tree,
|
||||
unsigned int branch_ct[/* n-1 */][2],
|
||||
const unsigned int num_events[/* n */]) {
|
||||
convert_distribution(0, tree, branch_ct, num_events);
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2010 The WebM project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef VPX_VP9_ENCODER_VP9_TREEWRITER_H_
|
||||
#define VPX_VP9_ENCODER_VP9_TREEWRITER_H_
|
||||
|
||||
#include "vpx_dsp/bitwriter.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void vp9_tree_probs_from_distribution(vpx_tree tree,
|
||||
unsigned int branch_ct[/* n - 1 */][2],
|
||||
const unsigned int num_events[/* n */]);
|
||||
|
||||
struct vp9_token {
|
||||
int value;
|
||||
int len;
|
||||
};
|
||||
|
||||
void vp9_tokens_from_tree(struct vp9_token *, const vpx_tree_index *);
|
||||
|
||||
static INLINE void vp9_write_tree(vpx_writer *w, const vpx_tree_index *tree,
|
||||
const vpx_prob *probs, int bits, int len,
|
||||
vpx_tree_index i) {
|
||||
do {
|
||||
const int bit = (bits >> --len) & 1;
|
||||
vpx_write(w, bit, probs[i >> 1]);
|
||||
i = tree[i + bit];
|
||||
} while (len);
|
||||
}
|
||||
|
||||
static INLINE void vp9_write_token(vpx_writer *w, const vpx_tree_index *tree,
|
||||
const vpx_prob *probs,
|
||||
const struct vp9_token *token) {
|
||||
vp9_write_tree(w, tree, probs, token->value, token->len, 0);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP9_ENCODER_VP9_TREEWRITER_H_
|
||||
Reference in New Issue
Block a user